## `eigenkit.torch.estimators.custom`

Estimators built from blocks and observables that you supply.

They wrap a list of `Block` objects and an `observables` specification into a `Circuit`, and then add a small classical head (an `nn.Linear` layer that gives the classification logits or a single regression output). 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.

## `eigenkit.torch.estimators.custom.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. |
| `n_classes`        | \`int            | None\`                                                                                                    | The number of output classes. If None, it is inferred from the training labels.                           |
| `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.                                                          |
| `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.                                                                                                 |

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

```python
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. |
| `y_val` | \`ndarray | None\`                                                                                                     | Optional validation labels, used to compute the validation loss of each epoch.  |

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. |

### `load(path, *, provider=None)`

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.                 |
| `provider` | \`ProviderSpec | None\`      | A provider that replaces the saved one. |

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)`

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\_. |

### `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. |

## `eigenkit.torch.estimators.custom.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. |
| `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.                                                          |
| `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.                                                                                                 |

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. |
| `y_val` | \`ndarray | None\`                                          | Optional validation targets, used to compute the validation loss of each epoch. |

Returns:

| Type                       | Description                                   |
| -------------------------- | --------------------------------------------- |
| `'CustomQuantumRegressor'` | This estimator, so that calls can be chained. |

### `load(path, *, provider=None)`

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.                 |
| `provider` | \`ProviderSpec | None\`      | A provider that replaces the saved one. |

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)`

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. |

### `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. |
