Skip to content

Estimators

eigenkit includes quantum estimators that are compatible with sklearn and built on PyTorch. They are hybrid classifiers and regressors, their recurrent versions, wrappers around your own networks, and adapters for time series. Every estimator follows the standard sklearn interface, fit(X, y), predict(X) and score(X, y), and works with GridSearchCV, Pipeline, clone and the rest of sklearn. Import them from the top level: from eigenkit import HQNC.

Install: these estimators need the torch extra (pip install eigenkit[torch]). They run on the built-in NumPy simulator. Another backend needs its own extra, for example eigenkit[pennylane] for provider="pennylane".

You can save a fitted model to a .eigenkit bundle, which is a zip file, and load it again with save() and load(), or with load_model(). See Model persistence for the format of the bundle, the supported classes, and how the benchmark uses save_dir.

How to get the trained network: model_

fit() trains a deep copy of the network, so it never changes the module that you gave to the estimator. After training, the object that you passed to GenericClassifier(model=...) therefore still has its initial weights, whatever the network did. This comes from the copy, and says nothing about the model. model_ returns the network that was actually trained. It exists on every estimator that trains a PyTorch network (all the estimators of this page except the time-series wrappers), and it raises NotFittedError before fit().

from torch import nn
from eigenkit import Basic, GenericClassifier
from eigenkit.datasets import load_dataset

data = load_dataset("iris")
X_train, y_train = data["X_train"], data["y_train"]

layer = Basic(n_qubits=4, depth=2)
clf = GenericClassifier(model=nn.Sequential(layer, nn.Linear(4, 3)), in_features=4)
clf.fit(X_train, y_train)

layer.state_dict()  # unchanged, this object never trained
clf.model_[0].state_dict()  # the trained weights

Classifiers

HQNC uses the PyTorch loss CrossEntropyLoss, and train_losses_ stores the cross-entropy of each epoch. When you pass validation data with fit(..., X_val=..., y_val=...), validation_losses_ stores the matching validation curve. n_classes is optional on every classifier of this section. If you leave it out, the set of labels is inferred from y when you call fit().

The examples of this section use the built-in iris dataset. It has 4 features and 3 classes, which is what the constructors below are sized for:

from eigenkit.datasets import load_dataset

data = load_dataset("iris")
X_train, y_train = data["X_train"], data["y_train"]
X_test, y_test = data["X_test"], data["y_test"]

HQNC

HQNC is the hybrid quantum neural network classifier. It places a quantum layer in a small nn.Sequential pipeline, and trains the whole pipeline together with the cross-entropy loss.

from eigenkit import HQNC

model = HQNC(
    in_features=4,
    depth=2,
    n_classes=3,
    epochs=30,
)
model.fit(X_train, y_train)
predictions = model.predict(X_test)
print(model.score(X_test, y_test))  # accuracy
print(model.train_losses_)  # per-epoch loss

You choose the quantum layer with layer_type:

layer_type Quantum layer Notes
"Basic" (default) One encoding block and one variational block. It needs n_qubits == in_quantum.
"Reupload" Standard data reuploading. It needs n_qubits == in_quantum.
"Ensemble" N independent circuits. It needs n_qubits to divide in_quantum.

Note: if n_qubits and in_quantum differ for Basic or Reupload, a linear adapter Linear(in_features, n_qubits) is added in front automatically, and a UserWarning is raised.

enc_rotation, var_rotation, variational_type and basis are passed to that layer unchanged. Their default is None, which means "the value that the layer you named uses". So the architecture that an estimator builds is the one that the layer page describes, and if you build it yourself from that page, you get the same model. Pass any of these four arguments to replace the default of the layer.

# Ensemble of 4-qubit circuits over 16 features.
model = HQNC(in_features=16, n_qubits=4, layer_type="Ensemble", depth=2)

RecurrentHQNC

RecurrentHQNC is a hybrid classifier for sequences. An encoder that is a recurrent neural network (RNN), of type "rnn", "gru" or "lstm", reads the sequence and passes the encoded vector to a quantum layer like the one of HQNC. The whole model is trained together, with one optimiser and one loss, so the RNN and the quantum block are updated at the same time.

X must be 3-D, with shape (n_samples, seq_len, seq_feature_dim). By default, only the last time step of the RNN goes to the quantum block. To flatten the whole sequence instead, set rnn_return_last_timestep=False and also give sequence_length.

import numpy as np
from eigenkit import RecurrentHQNC

X = np.random.randn(32, 10, 4).astype(np.float32)
y = np.where(X[:, -1, 0] > 0, "up", "down")

model = RecurrentHQNC(
    seq_feature_dim=4,
    rnn_type="gru",
    rnn_hidden_dim=16,
    depth=2,
    epochs=30,
)
model.fit(X, y)
predictions = model.predict(X)
probabilities = model.predict_proba(X)

The quantum layer takes the same arguments as in HQNC: layer_type, n_qubits, enc_rotation, var_rotation, variational_type and basis. See the table of layer_type values of HQNC above. The other options of the RNN are rnn_num_layers, rnn_dropout and rnn_bidirectional.

CustomQuantumClassifier

CustomQuantumClassifier builds its architecture from any list of blocks. Use it when none of the layer_type presets fits:

from eigenkit import (
    Encoding,
    Variational,
    StrongVariational,
    all_z,
)
from eigenkit import CustomQuantumClassifier

blocks = [
    Encoding(in_features=4, rotation="RY"),
    StrongVariational(depth=2),
    Variational(depth=1, rotation="RX"),
]
model = CustomQuantumClassifier(
    blocks=blocks,
    observables=all_z(4),
    n_classes=2,
    epochs=30,
)

# This estimator is configured for two classes, so keep iris labels 0 and 1.
binary = y_train < 2
model.fit(X_train[binary], y_train[binary])
predictions = model.predict(X_test)

observables= accepts the same forms as Circuit(observables=...) (see Observables). When the number of features of the data differs from the input size of the circuit, an nn.Linear adapter is added in front automatically. The input size of the circuit is inferred from the first Encoding or Reuploading block.

Regressors

The examples of this section use the built-in concrete dataset. It has 8 features and a continuous target. The examples use only part of the data, so that they run quickly:

from eigenkit.datasets import load_dataset

data = load_dataset("concrete")
X_train, y_train = data["X_train"][:200], data["y_train"][:200]
X_test, y_test = data["X_test"][:50], data["y_test"][:50]

HQNR

HQNR is the regression version of HQNC. Its output is a single neuron, trained with the regression loss that you choose.

from eigenkit import HQNR

model = HQNR(in_features=8, depth=2, epochs=50)
model.fit(X_train, y_train)
predictions = model.predict(X_test)
print(model.score(X_test, y_test))  # R^2

It takes the same layer_type and n_qubits arguments as HQNC. You choose the loss with loss_func: "mse", "mae" or "huber".

RecurrentHQNR

RecurrentHQNR is a hybrid regressor for sequences. An RNN encoder, of type "rnn", "gru" or "lstm", reads the sequence and passes the encoded vector to a quantum layer like the one of HQNR. The whole model is trained together, with one optimiser and one loss, so the RNN and the quantum block are updated at the same time.

X must be 3-D, with shape (n_samples, seq_len, seq_feature_dim). By default, only the last time step of the RNN goes to the quantum block. To flatten the whole sequence instead, set rnn_return_last_timestep=False and also give sequence_length.

import numpy as np
from eigenkit import RecurrentHQNR

X = np.random.randn(32, 10, 4).astype(np.float32)
last = X[:, -1, :]
y = (
    0.5 * last[:, 0]
    + 0.3 * np.sin(last[:, 1])
    + 0.2 * np.cos(2 * np.pi * last[:, 2])
    + 0.1 * last[:, 3] * last[:, 0]
).astype(np.float32)

model = RecurrentHQNR(
    seq_feature_dim=4,
    rnn_type="gru",
    rnn_hidden_dim=16,
    depth=2,
    epochs=30,
)
model.fit(X, y)
predictions = model.predict(X)

CustomQuantumRegressor

CustomQuantumRegressor is the regression version of CustomQuantumClassifier. It builds the circuit from a list of blocks, and adds a Linear head with a single neuron, trained with the regression loss that you choose.

Generic estimators

GenericClassifier and GenericRegressor are wrappers, compatible with sklearn, that train any torch.nn.Module through the standard fit and predict interface. HQNC and HQNR build the architecture of the model for you. The generic estimators instead expect a complete network, output head included, so you have full control over the architecture.

Pre-trained weights and the behaviour of fit()

fit() does not start from pre-trained weights. It copies the nn.Module, and then calls reset_parameters() on every submodule that has this method (such as nn.Linear and the quantum layers of eigenkit), seeded with random_state. So the weights of these layers are drawn again before training, even if the module that you pass already holds trained weights. Each later call to fit() (for example inside cross-validation, or after clone()) also starts again from new weights, not from the weights of the previous fit(). To keep the trained weights, use the fitted estimator, or save it with save() and load it again with load(), and do not call fit() on it again.

random_state does not reseed your process

Every estimator applies random_state inside fit() and load() on a private copy of the state of the PyTorch random number generators, that is the generator of the central processing unit (CPU) and the generator of every CUDA device. Two runs with the same random_state give the same model, on the CPU and on the graphics processing unit (GPU), and neither run changes a seed that you set yourself.

Only model is required. If you leave out in_features (default None), the number of features is taken from the data. sequence_input (default False) tells the estimator that X has shape (batch, timesteps, features) instead of (batch, features). The training arguments are lr (0.01), optimizer ("adam"), optimizer_kwargs (None), epochs (50), batch_size (32), show_progress (True) and random_state (42). GenericClassifier adds n_classes, and GenericRegressor adds loss_func, huber_delta and huber_reduction. None of these arguments is about the circuit, because the network is yours.

The examples below use moons for the classifier and diabetes for the regressor, which match the input sizes of their networks:

from eigenkit.datasets import load_dataset

moons = load_dataset("moons")
X_train, y_train = moons["X_train"], moons["y_train"]
X_test, y_test = moons["X_test"], moons["y_test"]

diabetes = load_dataset("diabetes")
X_reg, y_reg = diabetes["X_train"][:200], diabetes["y_train"][:200]
X_reg_test, y_reg_test = diabetes["X_test"][:50], diabetes["y_test"][:50]

GenericClassifier

from torch import nn
from eigenkit import GenericClassifier
from eigenkit import Basic

N_QUBITS, N_CLASSES = 4, 2

clf_net = nn.Sequential(
    nn.Linear(2, N_QUBITS),
    nn.Tanh(),
    Basic(n_qubits=N_QUBITS, depth=2),
    nn.Linear(N_QUBITS, N_CLASSES),
)

clf = GenericClassifier(
    model=clf_net,
    in_features=2,
    epochs=30,
    lr=0.01,
    batch_size=16,
    random_state=42,
)
clf.fit(X_train, y_train)
print(clf.score(X_test, y_test))  # accuracy
labels = clf.predict(X_test)
probs = clf.predict_proba(X_test)  # shape (n_samples, n_classes)

The forward() method of the network must return logits of shape (batch, n_classes). The wrapper encodes the labels automatically, so y can hold integers, strings or any other hashable labels.

in_features is optional but recommended. When it is set, fit raises an error at once if the shape of the data does not match.

GenericRegressor

from torch import nn
from eigenkit import GenericRegressor
from eigenkit import Basic

N_QUBITS_REG, IN_FEATURES = 6, 10

reg_net = nn.Sequential(
    nn.Linear(IN_FEATURES, N_QUBITS_REG),
    nn.Tanh(),
    Basic(n_qubits=N_QUBITS_REG, depth=2),
    nn.Linear(N_QUBITS_REG, 1),
)

reg = GenericRegressor(
    model=reg_net,
    in_features=IN_FEATURES,
    loss_func="mse",
    epochs=50,
    lr=0.01,
    batch_size=32,
    random_state=42,
)
reg.fit(X_reg, y_reg)
print(reg.score(X_reg_test, y_reg_test))  # R²
preds = reg.predict(X_reg_test)  # float32 array, shape (n_samples,)

The forward() method of the network must return shape (batch,) or (batch, 1). The losses available by name are "mse", "mae" and "huber". Any callable (output, target) -> scalar_tensor is also accepted, but a model trained with a callable loss cannot be saved.

Save and load

Generic estimators use the same .eigenkit bundle format as the other estimators, with one difference: the bundle does not store the architecture. You must pass a module with the same nn.Module structure to .load():

clf.save("clf_hybrid.eigenkit")

clf_net_fresh = nn.Sequential(
    nn.Linear(2, N_QUBITS),
    nn.Tanh(),
    Basic(n_qubits=N_QUBITS, depth=2),
    nn.Linear(N_QUBITS, N_CLASSES),
)

clf_loaded = GenericClassifier.load("clf_hybrid.eigenkit", model=clf_net_fresh)

load_model() also works for generic estimators, but the model= argument is required, because the bundle does not store the architecture and it cannot be inferred. If you call either method without model=, it raises SerializationError.

sklearn compatibility

GenericClassifier inherits from ClassifierMixin and GenericRegressor from RegressorMixin, so both work with Pipeline, cross_val_score, GridSearchCV and clone:

from sklearn.base import clone
from sklearn.model_selection import cross_val_score

scores = cross_val_score(clf, X_train, y_train, cv=3, scoring="accuracy")
cloned = clone(clf)  # unfitted copy with the same hyperparameters

See the Generic Estimators example for a complete example.

Time series

QuantumTimeSeriesRegressor and QuantumTimeSeriesClassifier wrap an inner estimator and apply a sliding window to data in time order. Each row of X is one time step. With a window of length in_size, the inner model receives a 3-D batch of shape (n_windows, in_size, n_features), and the window that starts at row i predicts y[i + in_size - 1 + shift]. With autoregressive=True, an extra channel is added to each time step, and it holds the target value at that step.

For tabular estimators (HQNR, CustomQuantumRegressor, and so on), the wrapper flattens each window before it calls fit or predict. For RecurrentHQNR and RecurrentHQNC, and for the generic estimators with sequence_input=True, the windows stay 3-D, so that the RNN sees the time axis.

import numpy as np
from eigenkit import (
    QuantumTimeSeriesRegressor,
    RecurrentHQNR,
)

n_feat = 5
window = 10
X = np.random.randn(200, n_feat).astype(np.float32)
y = X[:, 0] + 0.1 * np.random.randn(200).astype(np.float32)

inner = RecurrentHQNR(
    seq_feature_dim=n_feat,
    rnn_type="gru",
    rnn_hidden_dim=16,
    depth=2,
)
model = QuantumTimeSeriesRegressor(estimator=inner, in_size=window, shift=1)
model.fit(X, y)
predictions = model.predict(X)  # length n_timesteps - in_size - shift + 1

Classification uses the same alignment of the windows:

import numpy as np
from eigenkit import (
    QuantumTimeSeriesClassifier,
    RecurrentHQNC,
)

n_feat = 5
window = 10
X = np.random.randn(200, n_feat).astype(np.float32)
y = np.where(X[:, 0] > 0, "up", "down")

inner = RecurrentHQNC(
    seq_feature_dim=n_feat,
    rnn_type="gru",
    rnn_hidden_dim=16,
    depth=2,
)
model = QuantumTimeSeriesClassifier(estimator=inner, in_size=window, shift=1)
model.fit(X, y)
predictions = model.predict(X)  # length n_timesteps - in_size - shift + 1
probabilities = model.predict_proba(X)

Autoregressive mode. Set autoregressive=True to add the past values of the target to each window, as an extra channel of features. This extra channel counts as a feature: the inner estimator must be built with seq_feature_dim = n_feat + 1, and if you reuse the one above, you get ValueError: Last dimension of X must equal seq_feature_dim=5, got 6. When you predict, you must pass the known history as y_history:

# The appended target channel makes it n_feat + 1 inputs, so this needs its
# own inner estimator.
inner_ar = RecurrentHQNC(
    seq_feature_dim=n_feat + 1,
    rnn_type="gru",
    rnn_hidden_dim=16,
    depth=2,
)

# Fit on the head of the series, predict on the tail.
X_hist, y_hist = X[:150], y[:150]
X_future, y_future = X[150:], y[150:]

model_ar = QuantumTimeSeriesClassifier(
    estimator=inner_ar,
    in_size=window,
    shift=1,
    autoregressive=True,
)
model_ar.fit(X_hist, y_hist)
predictions = model_ar.predict(X_future, y_history=y_future)
probabilities = model_ar.predict_proba(X_future, y_history=y_future)

sklearn compatibility

Every algorithm class is a subclass of sklearn.base.BaseEstimator, and stores each argument of its constructor as an attribute of the same name on self, as sklearn expects. This is what makes clone, Pipeline, cross_val_score and GridSearchCV work without extra code.

from sklearn.base import clone
from sklearn.model_selection import cross_val_score

cloned = clone(model)
scores = cross_val_score(model, X, y, cv=5)
from sklearn.model_selection import GridSearchCV
from eigenkit import HQNC
from eigenkit.datasets import load_dataset

iris = load_dataset("iris")
binary = iris["y_train"] < 2  # the estimator below declares two classes
X_iris, y_iris = iris["X_train"][binary], iris["y_train"][binary]

grid = GridSearchCV(
    HQNC(in_features=4, n_classes=2),
    param_grid={"depth": [1, 2], "epochs": [20, 40]},
    cv=3,
)
grid.fit(X_iris, y_iris)
best = grid.best_estimator_

BaseQuantumClassifier inherits from ClassifierMixin, so its score() returns the accuracy. BaseQuantumRegressor inherits from RegressorMixin, so its score() returns R².

Import the base classes when you build your own estimators:

from eigenkit import (
    BaseQuantumClassifier,
    BaseQuantumEstimator,
    BaseQuantumRegressor,
)

Choosing a backend

Every estimator accepts the same provider= argument as Circuit: the name of a registered backend as a string, a configuration dataclass, or a Backend instance.

from eigenkit import PennyLaneConfig

# String. Requires the matching extra, here `qiskit`.
HQNC(in_features=4, depth=2, provider="qiskit")

# Config: forwards device-level options. Requires the `pennylane` extra.
HQNC(
    in_features=4,
    depth=2,
    provider=PennyLaneConfig(device_name="lightning.qubit", shots=None),
)

API reference

eigenkit.qml.BaseQuantumEstimator

Bases: BaseEstimator, ABC

Base class, compatible with scikit-learn, for all quantum algorithms.

Parameters:

Name Type Description Default
provider ProviderSpec

The backend. It can be a registered name ("pennylane", "qiskit", "braket", or any name passed to register()), a configuration instance (for example PennyLaneConfig(device_name=...)), or a backend instance.

'numpy'
random_state int | None

The seed for reproducibility, applied inside fit() and load(). What it seeds depends on the estimator. The PyTorch estimators isolate the random number generator of PyTorch, so seeding one of them does not reseed the random stream of the caller. The kernel estimators are deterministic, and they take it only so that all the estimators have the same interface.

42

fit(X, y) abstractmethod

Fit the estimator on X and y.

Parameters:

Name Type Description Default
X ndarray

The samples, of shape (n_samples, n_features).

required
y ndarray

One target for each sample, of shape (n_samples,).

required

Returns:

Type Description
'BaseQuantumEstimator'

This estimator, so that calls can be chained.

load(path, *, provider=None) classmethod

Load a fitted model from a .eigenkit bundle.

Load only bundles that you trust. A bundle can contain joblib pickles, and unpickling runs code, as with torch.load or joblib.load.

Parameters:

Name Type Description Default
path str | Path

The path of the bundle.

required
provider ProviderSpec | None

A provider that replaces the saved one.

None

Returns:

Type Description
'BaseQuantumEstimator'

The loaded estimator.

Raises:

Type Description
TypeError

If the method is called on a subclass and the bundle holds a different class. BaseQuantumEstimator.load() accepts any class.

predict(X) abstractmethod

Predict a value for every sample in X.

Parameters:

Name Type Description Default
X ndarray

The samples, of shape (n_samples, n_features).

required

Returns:

Type Description
ndarray

One prediction for each sample.

save(path)

Save a fitted model to a .eigenkit bundle.

The bundles of models that hold scikit-learn objects (QSVC, QSVR, the reservoir estimators and the time-series estimators) contain joblib pickles, so loading one can run code. Share them only with people who trust you.

Parameters:

Name Type Description Default
path str | Path

The path of the bundle. The suffix .eigenkit is added when it is missing.

required

eigenkit.qml.BaseQuantumClassifier

Bases: ClassifierMixin, BaseQuantumEstimator

Base class for quantum classifiers. Its score() returns the accuracy.

predict_proba(X)

Predict the class probabilities.

Subclasses should return the probabilities in the order of classes_, with shape (n_samples, n_classes). The default implementation raises a NotImplementedError.

Parameters:

Name Type Description Default
X ndarray

The samples, of shape (n_samples, n_features).

required

Returns:

Type Description
ndarray

The probabilities, of shape (n_samples, n_classes), with the columns in the order of classes_.

eigenkit.qml.BaseQuantumRegressor

Bases: RegressorMixin, BaseQuantumEstimator

Base class for quantum regressors. Its score() returns R².

eigenkit.torch.estimators

The PyTorch estimators: differentiable hybrid quantum-classical models.

The estimator base classes compatible with scikit-learn, the quantum kernels, the support vector machines and the saving and loading of models are in a separate package, eigenkit.qml, which does not need PyTorch. The base classes and load_model are also exported here for convenience, because the hybrid estimators build on them.

BaseQuantumClassifier

Bases: ClassifierMixin, BaseQuantumEstimator

Base class for quantum classifiers. Its score() returns the accuracy.

predict_proba(X)

Predict the class probabilities.

Subclasses should return the probabilities in the order of classes_, with shape (n_samples, n_classes). The default implementation raises a NotImplementedError.

Parameters:

Name Type Description Default
X ndarray

The samples, of shape (n_samples, n_features).

required

Returns:

Type Description
ndarray

The probabilities, of shape (n_samples, n_classes), with the columns in the order of classes_.

BaseQuantumEstimator

Bases: BaseEstimator, ABC

Base class, compatible with scikit-learn, for all quantum algorithms.

Parameters:

Name Type Description Default
provider ProviderSpec

The backend. It can be a registered name ("pennylane", "qiskit", "braket", or any name passed to register()), a configuration instance (for example PennyLaneConfig(device_name=...)), or a backend instance.

'numpy'
random_state int | None

The seed for reproducibility, applied inside fit() and load(). What it seeds depends on the estimator. The PyTorch estimators isolate the random number generator of PyTorch, so seeding one of them does not reseed the random stream of the caller. The kernel estimators are deterministic, and they take it only so that all the estimators have the same interface.

42
fit(X, y) abstractmethod

Fit the estimator on X and y.

Parameters:

Name Type Description Default
X ndarray

The samples, of shape (n_samples, n_features).

required
y ndarray

One target for each sample, of shape (n_samples,).

required

Returns:

Type Description
'BaseQuantumEstimator'

This estimator, so that calls can be chained.

load(path, *, provider=None) classmethod

Load a fitted model from a .eigenkit bundle.

Load only bundles that you trust. A bundle can contain joblib pickles, and unpickling runs code, as with torch.load or joblib.load.

Parameters:

Name Type Description Default
path str | Path

The path of the bundle.

required
provider ProviderSpec | None

A provider that replaces the saved one.

None

Returns:

Type Description
'BaseQuantumEstimator'

The loaded estimator.

Raises:

Type Description
TypeError

If the method is called on a subclass and the bundle holds a different class. BaseQuantumEstimator.load() accepts any class.

predict(X) abstractmethod

Predict a value for every sample in X.

Parameters:

Name Type Description Default
X ndarray

The samples, of shape (n_samples, n_features).

required

Returns:

Type Description
ndarray

One prediction for each sample.

save(path)

Save a fitted model to a .eigenkit bundle.

The bundles of models that hold scikit-learn objects (QSVC, QSVR, the reservoir estimators and the time-series estimators) contain joblib pickles, so loading one can run code. Share them only with people who trust you.

Parameters:

Name Type Description Default
path str | Path

The path of the bundle. The suffix .eigenkit is added when it is missing.

required

BaseQuantumRegressor

Bases: RegressorMixin, BaseQuantumEstimator

Base class for quantum regressors. Its score() returns R².

CustomQuantumClassifier

Bases: ModelAccessMixin, BaseQuantumClassifier

Classifier compatible with scikit-learn, built from your own list of blocks.

Give any sequence of blocks (Encoding, Variational, StrongVariational, Reuploading, or a custom block from CircuitBuilder.to_block()) and an observables specification, as for Circuit. The estimator connects them into a quantum layer followed by a classical nn.Linear head, and trains the whole model with the cross-entropy loss. When the number of features of the data differs from the number of inputs that the circuit expects, an nn.Linear adapter is added in front automatically.

Parameters:

Name Type Description Default
blocks list[Block]

The list of blocks, in order.

required
observables ObservableLike

The observables. It takes the same options as Circuit(observables=...). Default: None (Z on every qubit).

None
provider ProviderSpec

The backend. Default: "numpy".

'numpy'
in_features int | None

The number of features of the data. If None, it is inferred from the first Encoding or Reuploading block.

None
n_classes int | None

The number of output classes. If None, it is inferred from the training labels.

None
lr float

The learning rate of the optimiser.

0.01
optimizer str

The name of the optimiser. The supported names are "adam", "adamw", "rmsprop" and "sgd".

'adam'
optimizer_kwargs dict | None

Extra keyword arguments passed to the optimiser.

None
epochs int

The number of training epochs.

50
batch_size int

The size of each mini-batch.

32
show_progress bool

If True, a tqdm progress bar is shown.

True
random_state int | None

The seed.

42

Attributes:

Name Type Description
train_losses_

The cross-entropy loss of each epoch, set by fit().

validation_losses_

The validation cross-entropy loss of each epoch, set by fit() when validation data is given.

Example
import numpy as np
from eigenkit import (
    CustomQuantumClassifier, Encoding, Variational, all_z,
)

rng = np.random.default_rng(0)
X_train, X_test = rng.uniform(0, np.pi, (20, 4)), rng.uniform(0, np.pi, (5, 4))
y_train = np.array([0, 1] * 10)

blocks = [
    Encoding(in_features=4, rotation="RY"),
    Variational(depth=2, rotation="RY"),
]
model = CustomQuantumClassifier(
    blocks=blocks, observables=all_z(4), epochs=10,
)
model.fit(X_train, y_train)
predictions = model.predict(X_test)
fit(X, y, X_val=None, y_val=None)

Fit the classifier on training data.

Parameters:

Name Type Description Default
X ndarray

The samples, of shape (n_samples, in_features).

required
y ndarray

The class labels, of shape (n_samples,). They can be of any type that scikit-learn's LabelEncoder accepts.

required
X_val ndarray | None

Optional validation samples, used to compute the validation loss of each epoch.

None
y_val ndarray | None

Optional validation labels, used to compute the validation loss of each epoch.

None

Returns:

Type Description
'CustomQuantumClassifier'

This estimator, so that calls can be chained.

Raises:

Type Description
ValueError

If in_features is set and X does not have in_features columns.

predict(X)

Predict the class labels of X.

Parameters:

Name Type Description Default
X ndarray

The samples, of shape (n_samples, n_features).

required

Returns:

Type Description
ndarray

One prediction for each sample.

predict_proba(X)

Predict the probability of each class, with a softmax over the logits.

It returns a float32 array of shape (n_samples, n_classes).

Parameters:

Name Type Description Default
X ndarray

The samples, of shape (n_samples, n_features).

required

Returns:

Type Description
ndarray

The probabilities, of shape (n_samples, n_classes), with the columns in the order of classes_.

CustomQuantumRegressor

Bases: ModelAccessMixin, BaseQuantumRegressor

Regressor compatible with scikit-learn, built from your own list of blocks.

It is the regression counterpart of CustomQuantumClassifier. It wraps your quantum Circuit with an nn.Linear head of one neuron, trained with the chosen regression loss. An nn.Linear input adapter is added when the number of features of the data differs from the number of inputs of the circuit.

Parameters:

Name Type Description Default
blocks list[Block]

The list of blocks, in order.

required
observables ObservableLike

The observables. It takes the same options as Circuit(observables=...).

None
provider ProviderSpec

The backend. Default: "numpy".

'numpy'
in_features int | None

The number of features of the data. If None, it is inferred from the first Encoding or Reuploading block.

None
lr float

The learning rate of the optimiser.

0.01
optimizer str

The name of the optimiser: "adam", "adamw", "rmsprop" or "sgd".

'adam'
optimizer_kwargs dict | None

Extra keyword arguments passed to the optimiser.

None
epochs int

The number of training epochs.

50
batch_size int

The size of each mini-batch.

32
loss_func str

The regression loss: "mse", "mae" or "huber".

'mse'
huber_delta float

The threshold of the Huber loss.

1.0
huber_reduction str

The reduction of the Huber loss: "mean" or "sum".

'mean'
show_progress bool

If True, a tqdm progress bar is shown.

True
random_state int | None

The seed.

42

Attributes:

Name Type Description
train_losses_

The training loss of each epoch, set by fit().

validation_losses_

The validation loss of each epoch, set by fit() when validation data is given.

fit(X, y, X_val=None, y_val=None)

Fit the regressor on training data.

Parameters:

Name Type Description Default
X ndarray

The samples, of shape (n_samples, in_features).

required
y ndarray

The real-valued targets, of shape (n_samples,).

required
X_val ndarray | None

Optional validation samples, used to compute the validation loss of each epoch.

None
y_val ndarray | None

Optional validation targets, used to compute the validation loss of each epoch.

None

Returns:

Type Description
'CustomQuantumRegressor'

This estimator, so that calls can be chained.

predict(X)

Predict the continuous targets of X. It returns a float32 array.

Parameters:

Name Type Description Default
X ndarray

The samples, of shape (n_samples, n_features).

required

Returns:

Type Description
ndarray

One prediction for each sample.

GenericClassifier

Bases: ModelAccessMixin, BaseQuantumClassifier

Classifier compatible with scikit-learn that wraps any torch.nn.Module.

You supply a complete model whose forward(X) accepts a float32 tensor of shape (batch, in_features) and returns logits of shape (batch, n_classes). For sequence models (for example a long short-term memory network), set sequence_input=True. The wrapper then passes a 3-D tensor of shape (batch, seq_len, in_features) as it is, instead of flattening it.

The wrapper trains with CrossEntropyLoss and encodes the labels automatically.

Parameters:

Name Type Description Default
model Module

Any nn.Module. It must include its own classification head, which gives n_classes logits.

required
in_features int | None

The expected number of features at each time step (the last dimension of the input). When it is given, fit raises an error if X.shape[-1] does not match. Pass None to skip the check.

None
sequence_input bool

If True, the estimator tells QuantumTimeSeriesClassifier that it expects a 3-D tensor of shape (batch, seq_len, in_features), so the windowed data must not be flattened. Default: False.

False
n_classes int | None

The number of output classes. If None, it is inferred from the training labels. If it is given, it must equal the number of distinct labels in y.

None
lr float

The learning rate of the optimiser.

0.01
optimizer str

The name of the optimiser: "adam", "adamw", "rmsprop" or "sgd".

'adam'
optimizer_kwargs dict | None

Extra keyword arguments passed to the constructor of the optimiser.

None
epochs int

The number of full passes over the training data.

50
batch_size int

The size of each mini-batch.

32
show_progress bool

If True, a tqdm progress bar is shown during training.

True
random_state int | None

The seed, applied before the first training step.

42

Attributes:

Name Type Description
train_losses_

The average cross-entropy loss of each epoch, set by fit().

validation_losses_

The validation cross-entropy loss of each epoch, set by fit() when validation data is given.

Example
import numpy as np
from torch import nn
from eigenkit.torch.estimators import GenericClassifier
from eigenkit.torch.layers import Basic

rng = np.random.default_rng(0)
X_train, X_test = rng.normal(size=(30, 4)), rng.normal(size=(5, 4))
y_train = np.arange(30) % 3

# A plain PyTorch network, with a head for 3 classes.
net = nn.Sequential(nn.Linear(4, 8), nn.ReLU(), nn.Linear(8, 3))
clf = GenericClassifier(model=net, in_features=4, epochs=20)
clf.fit(X_train, y_train)
labels = clf.predict(X_test)
probs  = clf.predict_proba(X_test)

# A quantum layer with a classification head.
q = Basic(n_qubits=4, depth=2)
hybrid = nn.Sequential(q, nn.Linear(4, 3))
clf2 = GenericClassifier(model=hybrid, in_features=4)
accepts_sequence_input property

Whether the model expects a 3-D input (batch, seq_len, features).

fit(X, y, X_val=None, y_val=None)

Fit the model on training data.

Parameters:

Name Type Description Default
X ndarray

The samples, of shape (n_samples, in_features) for flat models, or (n_samples, seq_len, in_features) when sequence_input=True.

required
y ndarray

The class labels, of shape (n_samples,).

required
X_val ndarray | None

Optional validation samples, used to compute the validation loss of each epoch.

None
y_val ndarray | None

Optional validation labels, used to compute the validation loss of each epoch.

None

Returns:

Type Description
'GenericClassifier'

This estimator, so that calls can be chained.

Raises:

Type Description
ValueError

If X.shape[-1] or X_val.shape[-1] differs from in_features, if n_classes differs from the number of distinct labels, or if the model does not give one logit for each class.

load(path, *, model=None, provider=None) classmethod

Load a fitted GenericClassifier from a .eigenkit bundle.

The architecture of the model cannot be rebuilt automatically, so you must give it. The saved weights and the label encoder are restored automatically.

Parameters:

Name Type Description Default
path str | Path

The path of the .eigenkit bundle.

required
model Module | None

An nn.Module with the same architecture as the one used in training. Its weights are not changed: the saved weights go into a deep copy, which is model_ of the loaded estimator.

None
provider ProviderSpec | None

It is ignored. It is kept so that the signature matches the other estimators.

None

Returns:

Type Description
'GenericClassifier'

The loaded estimator.

Raises:

Type Description
SerializationError

If model is not given.

TypeError

If the bundle holds a different class.

Example
from torch import nn
from eigenkit.torch.estimators import GenericClassifier

net = nn.Sequential(nn.Linear(4, 8), nn.ReLU(), nn.Linear(8, 3))
clf = GenericClassifier.load("checkpoint.eigenkit", model=net)
predict(X)

Predict the class labels of X.

Parameters:

Name Type Description Default
X ndarray

The samples, of shape (n_samples, n_features).

required

Returns:

Type Description
ndarray

One prediction for each sample.

predict_proba(X)

Predict the probability of each class, with a softmax over the logits.

It returns a float32 array of shape (n_samples, n_classes).

Parameters:

Name Type Description Default
X ndarray

The samples, of shape (n_samples, n_features).

required

Returns:

Type Description
ndarray

The probabilities, of shape (n_samples, n_classes), with the columns in the order of classes_.

GenericRegressor

Bases: ModelAccessMixin, BaseQuantumRegressor

Regressor compatible with scikit-learn that wraps any torch.nn.Module.

You supply a complete model whose forward(X) accepts a float32 tensor of shape (batch, in_features) and returns a tensor of shape (batch, 1) or (batch,). For sequence models (for example a long short-term memory network), set sequence_input=True. The wrapper then passes a 3-D tensor of shape (batch, seq_len, in_features) as it is, instead of flattening it.

The wrapper trains the model with the standard train_loop() of the library, and returns the predictions as a float32 NumPy array.

Parameters:

Name Type Description Default
model Module

Any nn.Module. It must include its own output head.

required
in_features int | None

The expected number of features at each time step (the last dimension of the input). When it is given, fit raises an error if X.shape[-1] does not match. Pass None to skip the check.

None
sequence_input bool

If True, the estimator tells QuantumTimeSeriesRegressor that it expects a 3-D tensor of shape (batch, seq_len, in_features), so the windowed data must not be flattened. Default: False.

False
loss_func str | Callable

The loss: "mse", "mae", "huber", or any callable (output, target) -> scalar_tensor.

'mse'
huber_delta float

The threshold of the Huber loss. It is ignored for the other losses.

1.0
huber_reduction str

The reduction of the Huber loss: "mean" or "sum".

'mean'
lr float

The learning rate of the optimiser.

0.01
optimizer str

The name of the optimiser: "adam", "adamw", "rmsprop" or "sgd".

'adam'
optimizer_kwargs dict | None

Extra keyword arguments passed to the constructor of the optimiser.

None
epochs int

The number of full passes over the training data.

50
batch_size int

The size of each mini-batch.

32
show_progress bool

If True, a tqdm progress bar is shown during training.

True
random_state int | None

The seed, applied before the first training step.

42

Attributes:

Name Type Description
train_losses_

The list of the average loss of each epoch, set by fit().

validation_losses_

The list of the validation loss of each epoch, set by fit() when validation data is given.

Example
import numpy as np
from torch import nn
from eigenkit.torch.estimators import GenericRegressor
from eigenkit.torch.layers import Basic

rng = np.random.default_rng(0)
X_train, X_test = rng.normal(size=(30, 8)), rng.normal(size=(5, 8))
y_train = X_train.sum(axis=1)

# A plain PyTorch network.
net = nn.Sequential(nn.Linear(8, 16), nn.ReLU(), nn.Linear(16, 1))
reg = GenericRegressor(model=net, in_features=8, epochs=30)
reg.fit(X_train, y_train)
preds = reg.predict(X_test)

# A quantum layer with a classical head.
q = Basic(n_qubits=4, depth=2)
hybrid = nn.Sequential(q, nn.Linear(4, 1))
reg2 = GenericRegressor(model=hybrid, in_features=4)
accepts_sequence_input property

Whether the model expects a 3-D input (batch, seq_len, features).

fit(X, y, X_val=None, y_val=None)

Fit the model on training data.

Parameters:

Name Type Description Default
X ndarray

The samples, of shape (n_samples, in_features) for flat models, or (n_samples, seq_len, in_features) when sequence_input=True.

required
y ndarray

The real-valued targets, of shape (n_samples,).

required
X_val ndarray | None

Optional validation samples, used to compute the validation loss of each epoch.

None
y_val ndarray | None

Optional validation targets, used to compute the validation loss of each epoch.

None

Returns:

Type Description
'GenericRegressor'

This estimator, so that calls can be chained.

Raises:

Type Description
ValueError

If X.shape[-1] or X_val.shape[-1] differs from in_features, or if the output of the model does not have shape (batch,) or (batch, 1).

load(path, *, model=None, provider=None) classmethod

Load a fitted GenericRegressor from a .eigenkit bundle.

The architecture of the model cannot be rebuilt automatically, so you must give it. The saved weights are loaded into a copy of it.

Parameters:

Name Type Description Default
path str | Path

The path of the .eigenkit bundle.

required
model Module | None

An nn.Module with the same architecture as the one used in training. Its weights are not changed: the saved weights go into a deep copy, which is model_ of the loaded estimator.

None
provider ProviderSpec | None

It is ignored. It is kept so that the signature matches the other estimators.

None

Returns:

Type Description
'GenericRegressor'

The loaded estimator.

Raises:

Type Description
SerializationError

If model is not given.

TypeError

If the bundle holds a different class.

Example
from torch import nn
from eigenkit.torch.estimators import GenericRegressor

net = nn.Sequential(nn.Linear(8, 16), nn.ReLU(), nn.Linear(16, 1))
reg = GenericRegressor.load("checkpoint.eigenkit", model=net)
predict(X)

Predict the continuous targets of X. It returns a float32 array.

Parameters:

Name Type Description Default
X ndarray

The samples, of shape (n_samples, n_features).

required

Returns:

Type Description
ndarray

One prediction for each sample.

HQNC

Bases: ModelAccessMixin, BaseQuantumClassifier

Hybrid quantum neural network classifier (HQNC).

The model is MinMaxNorm -> quantum_layer -> nn.Linear(q_out, n_classes). If the number of features of the data differs from the resolved input size of the quantum layer (derived from in_quantum, n_qubits and layer_type), an nn.Linear adapter is added in front automatically.

Parameters:

Name Type Description Default
in_features int

The number of input features.

required
in_quantum int | None

The number of inputs that the quantum layer expects. It defaults to in_features.

None
n_qubits int | None

The number of qubits in each circuit. It defaults to in_quantum.

None
depth int

The number of repetitions of the variational layer.

2
n_classes int | None

The number of output classes. If None, it is inferred from the training labels.

None
layer_type str

The quantum layer. It is one of "Basic", "Reupload" and "Ensemble".

'Basic'
enc_rotation Literal['RX', 'RY', 'RZ'] | None

The encoding rotation: "RX", "RY", "RZ" or None.

None
var_rotation Literal['RX', 'RY', 'RZ'] | None

The variational rotation of the "basic" ansatz: "RX", "RY", "RZ" or None.

None
variational_type Literal['basic', 'strong'] | None

The type of variational block: "basic", "strong" or None.

None
basis Literal['X', 'Y', 'Z'] | None

The measurement basis: "X", "Y", "Z" or None. For these four arguments, None means "use the default of the layer named by layer_type", which is where each of these values is decided.

None
provider ProviderSpec

The backend. It takes the same options as Circuit(provider=...).

'numpy'
lr float

The learning rate of the optimiser.

0.01
optimizer str

The name of the optimiser. The supported names are "adam", "adamw", "rmsprop" and "sgd".

'adam'
optimizer_kwargs dict | None

Extra keyword arguments passed to the optimiser.

None
epochs int

The number of training epochs.

50
batch_size int

The size of each mini-batch.

32
show_progress bool

If True, a tqdm progress bar is shown.

True
random_state int | None

The seed for the initialisation of the weights.

42

Attributes:

Name Type Description
train_losses_

The average cross-entropy loss of each epoch, set by fit().

validation_losses_

The validation cross-entropy loss of each epoch, set by fit() when validation data is given.

Example
import numpy as np
from eigenkit.torch.estimators import HQNC

rng = np.random.default_rng(0)
X_train, X_test = rng.normal(size=(30, 4)), rng.normal(size=(5, 4))
y_train = np.arange(30) % 3

model = HQNC(in_features=4, depth=2, n_classes=3)
model.fit(X_train, y_train)
predictions = model.predict(X_test)
__init__(in_features, in_quantum=None, n_qubits=None, depth=2, n_classes=None, layer_type='Basic', enc_rotation=None, var_rotation=None, variational_type=None, basis=None, provider='numpy', lr=0.01, optimizer='adam', optimizer_kwargs=None, epochs=50, batch_size=32, show_progress=True, random_state=42)

Initialise a hybrid quantum neural network classifier (HQNC).

Parameters:

Name Type Description Default
in_features int

The number of input features that fit() expects.

required
in_quantum int | None

The number of inputs that the quantum layer expects. It defaults to in_features.

None
n_qubits int | None

The number of qubits in each circuit. It defaults to in_quantum.

None
depth int

The number of repetitions of the variational layer.

2
n_classes int | None

The number of output classes. If None, it is inferred from the labels passed to fit().

None
layer_type str

The family of the quantum layer. It is one of "Basic", "Reupload" and "Ensemble".

'Basic'
enc_rotation Literal['RX', 'RY', 'RZ'] | None

The encoding rotation: "RX", "RY", "RZ" or None.

None
var_rotation Literal['RX', 'RY', 'RZ'] | None

The variational rotation of the basic ansatz: "RX", "RY", "RZ" or None.

None
variational_type Literal['basic', 'strong'] | None

The type of variational block: "basic", "strong" or None.

None
basis Literal['X', 'Y', 'Z'] | None

The measurement basis: "X", "Y", "Z" or None. For these four arguments, None means "use the default of the layer named by layer_type", which is where each of these values is decided.

None
provider ProviderSpec

The backend. It takes the same options as Circuit(provider=...).

'numpy'
lr float

The learning rate of the optimiser.

0.01
optimizer str

The name of the optimiser. The supported names are "adam", "adamw", "rmsprop" and "sgd".

'adam'
optimizer_kwargs dict | None

Extra keyword arguments passed to the optimiser.

None
epochs int

The number of training epochs.

50
batch_size int

The size of each mini-batch.

32
show_progress bool

If True, a tqdm progress bar is shown during training.

True
random_state int | None

The seed for the initialisation of the weights.

42
fit(X, y, X_val=None, y_val=None)

Fit the classifier on training data.

Parameters:

Name Type Description Default
X ndarray

The samples, of shape (n_samples, in_features).

required
y ndarray

The class labels, of shape (n_samples,). They can be of any type that scikit-learn's LabelEncoder accepts.

required
X_val ndarray | None

Optional validation samples, used to compute the validation loss of each epoch.

None
y_val ndarray | None

Optional validation labels, used to compute the validation loss of each epoch.

None

Returns:

Type Description
HQNC

This estimator, so that calls can be chained.

Raises:

Type Description
ValueError

If X does not have in_features columns.

predict(X)

Predict the class labels of X.

Parameters:

Name Type Description Default
X ndarray

The samples, of shape (n_samples, n_features).

required

Returns:

Type Description
ndarray

One prediction for each sample.

predict_proba(X)

Predict the probability of each class, with a softmax over the logits.

It returns a float32 array of shape (n_samples, n_classes). Each row sums to 1.

Parameters:

Name Type Description Default
X ndarray

The samples, of shape (n_samples, n_features).

required

Returns:

Type Description
ndarray

The probabilities, of shape (n_samples, n_classes), with the columns in the order of classes_.

HQNR

Bases: ModelAccessMixin, BaseQuantumRegressor

Hybrid quantum neural network regressor (HQNR).

It is the regression counterpart of HQNC. The model is MinMaxNorm -> quantum_layer -> nn.Linear(q_out, 1). If the number of features of the data differs from the resolved input size of the quantum layer, an nn.Linear adapter is added in front automatically.

Parameters:

Name Type Description Default
in_features int

The number of input features.

required
in_quantum int | None

The number of inputs that the quantum layer expects. It defaults to in_features.

None
n_qubits int | None

The number of qubits in each circuit. It defaults to in_quantum.

None
depth int

The number of repetitions of the variational layer.

2
layer_type str

The quantum layer. It is one of "Basic", "Reupload" and "Ensemble".

'Basic'
enc_rotation Literal['RX', 'RY', 'RZ'] | None

The encoding rotation: "RX", "RY", "RZ" or None.

None
var_rotation Literal['RX', 'RY', 'RZ'] | None

The variational rotation of the "basic" ansatz: "RX", "RY", "RZ" or None.

None
variational_type Literal['basic', 'strong'] | None

The type of variational block: "basic", "strong" or None.

None
basis Literal['X', 'Y', 'Z'] | None

The measurement basis: "X", "Y", "Z" or None. For these four arguments, None means "use the default of the layer named by layer_type", which is where each of these values is decided.

None
provider ProviderSpec

The backend. It takes the same options as Circuit(provider=...).

'numpy'
lr float

The learning rate of the optimiser.

0.01
optimizer str

The name of the optimiser. The supported names are "adam", "adamw", "rmsprop" and "sgd".

'adam'
optimizer_kwargs dict | None

Extra keyword arguments passed to the optimiser.

None
epochs int

The number of training epochs.

50
batch_size int

The size of each mini-batch.

32
show_progress bool

If True, a tqdm progress bar is shown.

True
loss_func str

The regression loss: "mse", "mae" or "huber".

'mse'
huber_delta float

The threshold of the Huber loss.

1.0
huber_reduction str

The reduction of the Huber loss: "mean" or "sum".

'mean'
random_state int | None

The seed.

42

Attributes:

Name Type Description
train_losses_

The training loss of each epoch, set by fit().

validation_losses_

The validation loss of each epoch, set by fit() when validation data is given.

Example
import numpy as np
from eigenkit.torch.estimators import HQNR

rng = np.random.default_rng(0)
X_train, X_test = rng.normal(size=(30, 8)), rng.normal(size=(5, 8))
y_train = X_train.sum(axis=1)

model = HQNR(in_features=8, depth=2)
model.fit(X_train, y_train)
predictions = model.predict(X_test)
fit(X, y, X_val=None, y_val=None)

Fit the regressor on training data.

Parameters:

Name Type Description Default
X ndarray

The samples, of shape (n_samples, in_features).

required
y ndarray

The real-valued targets, of shape (n_samples,).

required
X_val ndarray | None

Optional validation samples, used to compute the validation loss of each epoch.

None
y_val ndarray | None

Optional validation targets, used to compute the validation loss of each epoch.

None

Returns:

Type Description
HQNR

This estimator, so that calls can be chained.

Raises:

Type Description
ValueError

If X does not have in_features columns.

predict(X)

Predict the continuous targets of X. It returns a float32 array.

Parameters:

Name Type Description Default
X ndarray

The samples, of shape (n_samples, n_features).

required

Returns:

Type Description
ndarray

One prediction for each sample.

QuantumTimeSeriesClassifier

Bases: BaseQuantumClassifier

Supervised wrapper for time-series classification.

It builds sliding windows over the rows of X (one row for each time step). Each window has shape (in_size, n_features). Stacked along the batch axis, they form an array of shape (n_windows, in_size, n_features), ready for sequence models such as RecurrentHQNC. When autoregressive=True, an extra last channel holds the target value of each timestep, so each step has n_features + 1 values. For a window that starts at row i, the classification target is y[i + in_size - 1 + shift].

Parameters:

Name Type Description Default
estimator Any

The inner estimator. It must have fit(X, y) and predict(X).

required
in_size int | None

The length of the window, in time steps. If None, it is treated as 1.

None
shift int

How many steps after the last timestep of the window the target is. It must be zero or more. shift=0 predicts the target at the last timestep.

1
autoregressive bool

If True, a channel with y[i + k] for k = 0, ..., in_size - 1 is added to each window. With shift=0, this leaks the target into the inputs, and a UserWarning is raised. When autoregressive=True, predict() and predict_proba() require a y_history argument.

False

Attributes:

Name Type Description
classes_

The distinct class labels seen by fit().

train_losses_

The training loss of each epoch, copied from the inner estimator if it has train_losses_ (HQNC, RecurrentHQNC), and an empty list otherwise. It is set by fit().

Example
import numpy as np
from eigenkit.torch.estimators import (
    QuantumTimeSeriesClassifier, RecurrentHQNC,
)

rng = np.random.default_rng(0)
X_train, X_test = rng.normal(size=(40, 4)), rng.normal(size=(15, 4))
y_train = np.arange(40) % 2

inner = RecurrentHQNC(seq_feature_dim=4, rnn_hidden_dim=4, depth=2)
model = QuantumTimeSeriesClassifier(estimator=inner, in_size=10, shift=1)
model.fit(X_train, y_train)
predictions = model.predict(X_test)
output property

The number of classes.

After fit(), it is the number of classes seen. Before, it is the n_classes of the inner estimator, or None if it has none.

fit(X, y)

Fit the inner classifier on the windows and their labels.

Parameters:

Name Type Description Default
X ndarray

The features in time order, of shape (n_timesteps, n_features).

required
y ndarray

The class labels, of shape (n_timesteps,) or (n_timesteps, 1).

required

Returns:

Type Description
'QuantumTimeSeriesClassifier'

This estimator, so that calls can be chained.

load(path, *, provider=None, model=None) classmethod

Load a fitted time-series classifier wrapper from a .eigenkit bundle.

Parameters:

Name Type Description Default
path str | Path

The path of the .eigenkit bundle.

required
provider ProviderSpec | None

An optional provider that replaces the saved one. It is passed to the inner estimator.

None
model Any

The nn.Module architecture, required when the inner estimator is GenericClassifier. Pass the same architecture as the one used in training.

None

Returns:

Type Description
'QuantumTimeSeriesClassifier'

The loaded wrapper.

Raises:

Type Description
TypeError

If the bundle holds a different class.

SerializationError

If the inner estimator needs model and it is not given.

predict(X, y_history=None)

Predict the class labels of the windows of X.

Parameters:

Name Type Description Default
X ndarray

The features in time order, of shape (n_timesteps, n_features).

required
y_history ndarray | None

The past class labels, aligned with the rows of X. They fill the autoregressive channel of each window. It is required when autoregressive=True, and it must have at least n_timesteps - shift elements (that is, n_timesteps - in_size - shift + 1 + in_size - 1).

None

Returns:

Type Description
ndarray

The predicted labels, of shape (n_timesteps - in_size - shift + 1,).

predict_proba(X, y_history=None)

Return the estimated class probabilities of the windows of X.

Parameters:

Name Type Description Default
X ndarray

The features in time order, of shape (n_timesteps, n_features).

required
y_history ndarray | None

The past class labels. It is required when autoregressive=True. See predict().

None

Returns:

Type Description
ndarray

A float32 array of shape (n_windows, n_classes).

Raises:

Type Description
NotImplementedError

If the inner estimator has no predict_proba.

score(X, y, *, return_dict=False)
score(
    X: np.ndarray,
    y: np.ndarray,
    *,
    return_dict: Literal[False] = False,
) -> float
score(
    X: np.ndarray,
    y: np.ndarray,
    *,
    return_dict: Literal[True],
) -> dict[str, float]

Score the estimator on the window targets, aligned as in predict.

By default, it returns the accuracy, for compatibility with scikit-learn (cross_val_score, GridSearchCV). Pass return_dict=True to get a dict with accuracy, f1 (weighted), precision (weighted) and recall (weighted).

Note

When autoregressive=True, the true labels y are used as the autoregressive history channel (teacher forcing). This is the correct behaviour for held-out evaluation, but it means that score cannot be called without the true labels of all the timesteps in X.

Parameters:

Name Type Description Default
X ndarray

The samples, of shape (n_samples, n_features). The windows are built inside.

required
y ndarray

One target for each sample, of shape (n_samples,).

required
return_dict bool

If True, every metric is returned in a dict, instead of the single main score. Default: False.

False

Returns:

Type Description
float | dict[str, float]

The accuracy, or a dict of metrics when return_dict is set.

QuantumTimeSeriesRegressor

Bases: BaseQuantumRegressor

Supervised wrapper with a single output, for time-series regression.

It builds sliding windows over the rows of X (one row for each time step). Each window has shape (in_size, n_features). Stacked along the batch axis, they form an array of shape (n_windows, in_size, n_features), ready for sequence models such as torch.nn.LSTM. When autoregressive=True, an extra last channel holds the target value of each timestep, so each step has n_features + 1 values. For a window that starts at row i, the regression target is y[i + in_size - 1 + shift].

Parameters:

Name Type Description Default
estimator Any

The inner estimator. It must have fit(X, y) and predict(X).

required
in_size int | None

The length of the window, in time steps. If None, it is treated as 1.

None
shift int

How many steps after the last timestep of the window the target is. It must be zero or more. shift=0 predicts the target at the last timestep.

1
autoregressive bool

If True, a channel with y[i + k] for k = 0, ..., in_size - 1 is added to each window. With shift=0, this leaks the target into the inputs, and a UserWarning is raised.

False

Attributes:

Name Type Description
train_losses_

The training loss of each epoch, copied from the inner estimator if it has train_losses_ (HQNR, RecurrentHQNR), and an empty list otherwise. It is set by fit().

Example
import numpy as np
from eigenkit.torch.estimators import QuantumTimeSeriesRegressor, RecurrentHQNR

rng = np.random.default_rng(0)
X_train, X_test = rng.normal(size=(40, 3)), rng.normal(size=(15, 3))
y_train = np.sin(np.arange(40) / 4)

# The inner estimator should accept X of shape (batch, in_size, n_features).
inner = RecurrentHQNR(seq_feature_dim=3, rnn_hidden_dim=4, epochs=5)
model = QuantumTimeSeriesRegressor(estimator=inner, in_size=10, shift=1)
model.fit(X_train, y_train)
predictions = model.predict(X_test)
output property

The number of outputs, which is always 1.

fit(X, y)

Fit the inner estimator on the windows and their targets.

Parameters:

Name Type Description Default
X ndarray

The features in time order, of shape (n_timesteps, n_features).

required
y ndarray

The targets, of shape (n_timesteps,) or (n_timesteps, 1).

required

Returns:

Type Description
'QuantumTimeSeriesRegressor'

This estimator, so that calls can be chained.

load(path, *, provider=None, model=None) classmethod

Load a fitted time-series wrapper from a .eigenkit bundle.

Parameters:

Name Type Description Default
path str | Path

The path of the .eigenkit bundle.

required
provider ProviderSpec | None

An optional provider that replaces the saved one. It is passed to the inner estimator.

None
model Any

The nn.Module architecture, required when the inner estimator is GenericRegressor. Pass the same architecture as the one used in training.

None

Returns:

Type Description
'QuantumTimeSeriesRegressor'

The loaded wrapper.

Raises:

Type Description
TypeError

If the bundle holds a different class.

SerializationError

If the inner estimator needs model and it is not given.

predict(X, y_history=None)

Predict the regression targets of the windows of X.

Parameters:

Name Type Description Default
X ndarray

The features in time order, of shape (n_timesteps, n_features).

required
y_history ndarray | None

The past targets, aligned with the rows of X. They fill the autoregressive channel of each window. It is required when autoregressive=True.

None

Returns:

Type Description
ndarray

The predictions, of shape (n_timesteps - in_size - shift + 1,).

score(X, y, *, return_dict=False)
score(
    X: np.ndarray,
    y: np.ndarray,
    *,
    return_dict: Literal[False] = False,
) -> float
score(
    X: np.ndarray,
    y: np.ndarray,
    *,
    return_dict: Literal[True],
) -> dict[str, float]

Score the estimator on the window targets, aligned as in predict.

By default, it returns R², for compatibility with scikit-learn (cross_val_score, GridSearchCV). Pass return_dict=True to get a dict with r2, mse, mae, rmse and mape.

Parameters:

Name Type Description Default
X ndarray

The samples, of shape (n_samples, n_features). The windows are built inside.

required
y ndarray

One target for each sample, of shape (n_samples,).

required
return_dict bool

If True, every metric is returned in a dict, instead of the single main score. Default: False.

False

Returns:

Type Description
float | dict[str, float]

The R² score, or a dict of metrics when return_dict is set.

RecurrentHQNC

Bases: ModelAccessMixin, BaseQuantumClassifier

Hybrid classifier: a recurrent encoder, a quantum layer and a linear class head.

The recurrent encoder is a recurrent neural network (RNN). The estimator expects 3-D inputs of shape (n_samples, seq_len, seq_feature_dim). By default, only the last timestep of the RNN output goes to the quantum layer. Set rnn_return_last_timestep=False, together with sequence_length, to use the full RNN output (flattened) instead. The quantum part is the same as in HQNC: MinMaxNorm, the quantum layer and an nn.Linear head.

Parameters:

Name Type Description Default
seq_feature_dim int

The number of features at each time step (the last axis of X).

required
rnn_type Literal['rnn', 'gru', 'lstm']

The type of recurrent layer: "rnn", "gru" (gated recurrent unit) or "lstm" (long short-term memory).

'gru'
rnn_hidden_dim int

The hidden size in each direction.

32
rnn_num_layers int

The number of stacked RNN layers.

1
rnn_dropout float

The dropout between the RNN layers. It applies only if rnn_num_layers > 1.

0.0
rnn_bidirectional bool

If True, the RNN is bidirectional, and its output size doubles.

False
rnn_return_last_timestep bool

If True, only the last output step is kept. Otherwise, the full sequence is flattened, which requires sequence_length.

True
sequence_length int | None

The number of time steps in each sample. It is required when rnn_return_last_timestep=False, and it must equal X.shape[1] in fit.

None
in_quantum int | None

The number of inputs of the quantum layer. It defaults to the size of the RNN output that reaches the quantum layer: rnn_hidden_dim, doubled when the RNN is bidirectional, and multiplied by sequence_length when rnn_return_last_timestep=False.

None
n_qubits int | None

The number of qubits in each circuit. It defaults to in_quantum.

None
depth int

The number of repetitions of the variational layer.

2
n_classes int | None

The number of output classes. If None, it is inferred from the labels passed to fit(). If it is given, it must equal the number of distinct labels in y.

None
layer_type str

The quantum layer. It is one of "Basic", "Reupload" and "Ensemble".

'Basic'
enc_rotation Literal['RX', 'RY', 'RZ'] | None

The encoding rotation: "RX", "RY", "RZ" or None.

None
var_rotation Literal['RX', 'RY', 'RZ'] | None

The variational rotation of the basic ansatz: "RX", "RY", "RZ" or None.

None
variational_type Literal['basic', 'strong'] | None

The type of variational block: "basic", "strong" or None.

None
basis Literal['X', 'Y', 'Z'] | None

The measurement basis: "X", "Y", "Z" or None. For these four arguments, None means "use the default of the layer named by layer_type", which is where each of these values is decided.

None
provider ProviderSpec

The backend. It takes the same options as Circuit(provider=...).

'numpy'
lr float

The learning rate of the optimiser.

0.01
optimizer str

The name of the optimiser. The supported names are "adam", "adamw", "rmsprop" and "sgd".

'adam'
optimizer_kwargs dict | None

Extra keyword arguments passed to the optimiser.

None
epochs int

The number of training epochs.

50
batch_size int

The size of each mini-batch.

32
show_progress bool

If True, a tqdm progress bar is shown during training.

True
random_state int | None

The seed for the initialisation of the weights.

42

Attributes:

Name Type Description
train_losses_

The cross-entropy loss of each epoch, set by fit().

validation_losses_

The validation cross-entropy loss of each epoch, set by fit() when validation data is given.

fit(X, y, X_val=None, y_val=None)

Fit the estimator on X and y.

Parameters:

Name Type Description Default
X ndarray

The sequences, of shape (n_samples, seq_len, seq_feature_dim).

required
y ndarray

One label for each sequence, of shape (n_samples,).

required
X_val ndarray | None

Optional validation sequences, of the same shape as X. Default: None.

None
y_val ndarray | None

The labels of X_val. Default: None.

None

Returns:

Type Description
RecurrentHQNC

This estimator, so that calls can be chained.

predict(X)

Predict a label for every sample in X.

Parameters:

Name Type Description Default
X ndarray

The sequences, of shape (n_samples, seq_len, seq_feature_dim).

required

Returns:

Type Description
ndarray

One prediction for each sequence, of shape (n_samples,).

predict_proba(X)

Predict the class probabilities of every sample in X.

Parameters:

Name Type Description Default
X ndarray

The sequences, of shape (n_samples, seq_len, seq_feature_dim).

required

Returns:

Type Description
ndarray

The probabilities, of shape (n_samples, n_classes), with the columns in the order of classes_.

RecurrentHQNR

Bases: ModelAccessMixin, BaseQuantumRegressor

Hybrid regressor: a recurrent encoder, a quantum layer and a linear head.

The recurrent encoder is a recurrent neural network (RNN). The estimator expects 3-D inputs of shape (n_samples, seq_len, seq_feature_dim). By default, only the last timestep of the RNN output goes to the quantum layer. Set rnn_return_last_timestep=False, together with sequence_length, to use the full RNN output (flattened) instead. The quantum part is the same as in HQNR: MinMaxNorm, the quantum layer and an nn.Linear head.

Parameters:

Name Type Description Default
seq_feature_dim int

The number of features at each time step (the last axis of X).

required
rnn_type Literal['rnn', 'gru', 'lstm']

The type of recurrent layer: "rnn", "gru" (gated recurrent unit) or "lstm" (long short-term memory).

'gru'
rnn_hidden_dim int

The hidden size in each direction.

32
rnn_num_layers int

The number of stacked RNN layers.

1
rnn_dropout float

The dropout between the RNN layers. It applies only if rnn_num_layers > 1.

0.0
rnn_bidirectional bool

If True, the RNN is bidirectional, and its output size doubles.

False
rnn_return_last_timestep bool

If True, only the last output step is kept. Otherwise, the full sequence is flattened, which requires sequence_length.

True
sequence_length int | None

The number of time steps in each sample. It is required when rnn_return_last_timestep=False, and it must equal X.shape[1] in fit.

None
in_quantum int | None

The number of inputs of the quantum layer. It defaults to the size of the RNN output that reaches the quantum layer: rnn_hidden_dim, doubled when the RNN is bidirectional, and multiplied by sequence_length when rnn_return_last_timestep=False.

None
n_qubits int | None

The number of qubits in each circuit. It defaults to in_quantum.

None
depth int

The number of repetitions of the variational layer.

2
layer_type str

The quantum layer. It is one of "Basic", "Reupload" and "Ensemble".

'Basic'
enc_rotation Literal['RX', 'RY', 'RZ'] | None

The encoding rotation: "RX", "RY", "RZ" or None.

None
var_rotation Literal['RX', 'RY', 'RZ'] | None

The variational rotation of the "basic" ansatz: "RX", "RY", "RZ" or None.

None
variational_type Literal['basic', 'strong'] | None

The type of variational block: "basic", "strong" or None.

None
basis Literal['X', 'Y', 'Z'] | None

The measurement basis: "X", "Y", "Z" or None. For these four arguments, None means "use the default of the layer named by layer_type", which is where each of these values is decided.

None
provider ProviderSpec

The backend. It takes the same options as Circuit(provider=...).

'numpy'
lr float

The learning rate of the optimiser.

0.01
optimizer str

The name of the optimiser.

'adam'
optimizer_kwargs dict | None

Extra keyword arguments passed to the optimiser.

None
epochs int

The number of training epochs.

50
batch_size int

The size of each mini-batch.

32
show_progress bool

If True, a tqdm progress bar is shown.

True
loss_func str

The regression loss: "mse", "mae" or "huber".

'mse'
huber_delta float

The threshold of the Huber loss.

1.0
huber_reduction str

The reduction of the Huber loss: "mean" or "sum".

'mean'
random_state int | None

The seed.

42

Attributes:

Name Type Description
train_losses_

The training loss of each epoch, set by fit().

validation_losses_

The validation loss of each epoch, set by fit() when validation data is given.

fit(X, y, X_val=None, y_val=None)

Fit the estimator on X and y.

Parameters:

Name Type Description Default
X ndarray

The sequences, of shape (n_samples, seq_len, seq_feature_dim).

required
y ndarray

One target for each sequence, of shape (n_samples,) or (n_samples, 1).

required
X_val ndarray | None

Optional validation sequences, of the same shape as X. Default: None.

None
y_val ndarray | None

The targets of X_val. Default: None.

None

Returns:

Type Description
RecurrentHQNR

This estimator, so that calls can be chained.

predict(X)

Predict a value for every sample in X.

Parameters:

Name Type Description Default
X ndarray

The sequences, of shape (n_samples, seq_len, seq_feature_dim).

required

Returns:

Type Description
ndarray

One prediction for each sequence, as a float32 array of shape (n_samples,).

load_model(path, *, provider=None, model=None)

Load any saved model. The class of the model is read from metadata.json.

Load only bundles that you trust. A bundle can contain joblib pickles, and unpickling runs code, as with torch.load or joblib.load.

Parameters:

Name Type Description Default
path str | Path

The path to the .eigenkit bundle.

required
provider ProviderSpec | None

A provider that replaces the saved one. It is passed to the load() method of the estimator.

None
model Any

The nn.Module architecture, for checkpoints of GenericRegressor and GenericClassifier. It is ignored for the other estimators.

None

Returns:

Type Description
BaseQuantumEstimator

The loaded estimator, an instance of the class named in the bundle.