Quantum Reservoir Computing: Logistic map#

1. Install and import (quantum)reservoirpy if needed#

This notebook shows how to use a quantum reservoir for time series prediction. It uses quantumreservoirpy which follows the standard API from reservoirpy. The underlying procedures are documentet in this preprint.

import subprocess
import sys

try:
    import quantumreservoirpy  # noqa

    print("quantumreservoirpy is already installed.")
except ImportError:
    print("quantumreservoirpy is not installed. Installing now...")
    subprocess.check_call([sys.executable, "-m", "pip", "install", "quantumreservoirpy"])

try:
    import reservoirpy  # noqa

    print("reservoirpy is already installed.")
except ImportError:
    print("reservoirpy is not installed. Installing now...")
    subprocess.check_call([sys.executable, "-m", "pip", "install", "reservoirpy"])
quantumreservoirpy is already installed.
reservoirpy is already installed.

2. Import other necessary modules#

import matplotlib.pyplot as plt
import numpy as np
from qiskit_aer import AerSimulator
from quantumreservoirpy.partialmeasurement import PartialMeasurement
from quantumreservoirpy.stabilizer import Stabilizer
from quantumreservoirpy.util import create_shifted_array
from reservoirpy.datasets import logistic_map
from reservoirpy.nodes import Reservoir
from sklearn.linear_model import Ridge
from sklearn.model_selection import TimeSeriesSplit

3. We want to “learn” the logistic map from observations.#

ts = logistic_map(200, r=3.9, x0=0.5).flatten()
plt.figure(figsize=(20, 4))
_ = plt.plot(ts)
../../_images/42bcd6f9ff894acc33d622169cce4d7ca5b890a91efb7f192834c04a72f2e26e.png

4. The setup#

We use spatial multiplexing by using 10 reservoirs. In addition we use temporal multiplexing, i.e., we train/predict using the last 10 observations. Each reservoir has 3 qubits, where 2 are measured at each time step. We also use higher order observables set by the degree.

num_reservoirs = 10
num_qubits = 3
num_meas = 2
degree = num_meas
timeplex = 10

The classical reservoir should have the same number of neurons as the number of observables the quantum reservoirs use. We use the en/decoding of classical data using cosets of a given stabilizer.

res = {}
num_neurons = num_reservoirs * (2**num_meas - 1)
res["classical"] = Reservoir(num_neurons, lr=0.5, sr=0.9)

res["quantum_part"] = PartialMeasurement(
    num_qubits,
    num_meas,
    backend=AerSimulator(),
    degree=degree,
    num_reservoirs=num_reservoirs,
)

res["quantum_stab"] = Stabilizer(
    num_qubits,
    num_meas,
    backend=AerSimulator(),
    degree=degree,
    num_reservoirs=num_reservoirs,
)

5. Helper functions to fit the model and run predictions#

def fit_model(model, res_states, series, WARMUP=0.3, timeplex=1):
    warmup = int(len(series) * WARMUP)

    X = res_states[warmup:-1]
    y = series[warmup + 1 :]

    if timeplex > 1:
        X = create_shifted_array(X, timeplex)
    model.fit(X, y)

    return model, X, y


def run_prediction(model, res_states, timeplex=1):
    X = np.copy(res_states)

    if timeplex > 1:
        X = create_shifted_array(X, timeplex)
    X = X[-1, :]
    X = X.reshape((1, -1))
    return model.predict(X)

6. Fit the model with linear regression and run the predictions#

This will take some time!

prediction = {}
tscv = TimeSeriesSplit()
for method in ["classical", "quantum_part", "quantum_stab"]:
    for i, (train_index, test_index) in enumerate(tscv.split(ts)):
        if not i == 2:
            continue

        X_train = ts[train_index]
        X_test = ts[test_index]
        num_pred = len(test_index)
        linreg = Ridge(alpha=1e-7)
        if method == "classical":
            states = res[method].run(X_train.reshape(-1, 1), reset=True)
            linreg, X, y = fit_model(linreg, states, X_train)
        else:
            states = res[method].run(timeseries=X_train, shots=1e3, precision=1e-2)
            linreg, X, y = fit_model(linreg, states, X_train, timeplex=timeplex)

        score = linreg.score(X, y)
        print("score[", method, "]=", score)

        firsttime = True
        prediction[method] = X_train

        for j in range(num_pred):
            print(j, "/", num_pred)
            if method == "classical":
                if firsttime:
                    states = res[method].state()
                else:
                    states = res[method].run(prediction[method][-1])
                tmp = run_prediction(linreg, states, 1)
            else:
                states = res[method].run(
                    prediction[method][-2 * int(timeplex) :], shots=1e3, precision=1e-2
                )
                tmp = run_prediction(linreg, states, timeplex)

            prediction[method] = np.append(prediction[method], tmp)

            firsttime = False
Running Reservoir-0: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 101/101 [00:00<00:00, 7702.83it/s]
score[ classical ]= 0.9971940011772895
0 / 33
1 / 33
Running Reservoir-0: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 3300.00it/s]
2 / 33
Running Reservoir-0: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 2721.81it/s]
3 / 33
Running Reservoir-0: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 2613.27it/s]
4 / 33
Running Reservoir-0: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 2534.32it/s]
5 / 33
Running Reservoir-0: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 1689.21it/s]
6 / 33
Running Reservoir-0: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 2657.99it/s]
7 / 33
Running Reservoir-0: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 2737.80it/s]
8 / 33
Running Reservoir-0: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 2685.21it/s]
9 / 33
Running Reservoir-0: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 2304.56it/s]
10 / 33
Running Reservoir-0: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 2704.26it/s]
11 / 33
Running Reservoir-0: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 3398.95it/s]
12 / 33
Running Reservoir-0: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 3310.42it/s]
13 / 33
Running Reservoir-0: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 325.77it/s]
14 / 33
Running Reservoir-0: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 2725.34it/s]
15 / 33
Running Reservoir-0: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 2490.68it/s]
16 / 33
Running Reservoir-0: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 2711.25it/s]
17 / 33
Running Reservoir-0: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 2273.34it/s]
18 / 33
Running Reservoir-0: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 2520.62it/s]
19 / 33
Running Reservoir-0: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 1968.23it/s]
20 / 33
Running Reservoir-0: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 2317.30it/s]
21 / 33
Running Reservoir-0: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 2505.56it/s]
22 / 33
Running Reservoir-0: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 2377.72it/s]
23 / 33
Running Reservoir-0: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 2369.66it/s]
24 / 33
Running Reservoir-0: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 1763.79it/s]
25 / 33
Running Reservoir-0: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 2880.70it/s]
26 / 33
Running Reservoir-0: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 3524.63it/s]
27 / 33
Running Reservoir-0: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 2421.65it/s]
28 / 33
Running Reservoir-0: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 3440.77it/s]
29 / 33
Running Reservoir-0: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 3477.86it/s]
30 / 33
Running Reservoir-0: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 3070.50it/s]
31 / 33
Running Reservoir-0: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 2023.30it/s]
32 / 33
Running Reservoir-0: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 2549.73it/s]
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [02:17<00:00, 13.78s/it]
score[ quantum_part ]= 0.9999999999999559
0 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:21<00:00,  2.10s/it]
1 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:21<00:00,  2.11s/it]
2 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:21<00:00,  2.13s/it]
3 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:21<00:00,  2.12s/it]
4 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:20<00:00,  2.10s/it]
5 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:20<00:00,  2.10s/it]
6 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:21<00:00,  2.15s/it]
7 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:21<00:00,  2.12s/it]
8 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:21<00:00,  2.18s/it]
9 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:20<00:00,  2.05s/it]
10 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:20<00:00,  2.08s/it]
11 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:20<00:00,  2.06s/it]
12 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:20<00:00,  2.04s/it]
13 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:20<00:00,  2.08s/it]
14 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:20<00:00,  2.07s/it]
15 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:21<00:00,  2.11s/it]
16 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:21<00:00,  2.13s/it]
17 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:20<00:00,  2.06s/it]
18 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:20<00:00,  2.09s/it]
19 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:20<00:00,  2.09s/it]
20 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:21<00:00,  2.11s/it]
21 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:21<00:00,  2.11s/it]
22 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:20<00:00,  2.10s/it]
23 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:20<00:00,  2.09s/it]
24 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:21<00:00,  2.13s/it]
25 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:21<00:00,  2.12s/it]
26 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:21<00:00,  2.11s/it]
27 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:21<00:00,  2.11s/it]
28 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:21<00:00,  2.11s/it]
29 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:21<00:00,  2.10s/it]
30 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:20<00:00,  2.10s/it]
31 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:22<00:00,  2.20s/it]
32 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:21<00:00,  2.17s/it]
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [02:43<00:00, 16.38s/it]
score[ quantum_stab ]= 0.99999999999995
0 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:25<00:00,  2.52s/it]
1 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:25<00:00,  2.52s/it]
2 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:26<00:00,  2.68s/it]
3 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:25<00:00,  2.53s/it]
4 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:26<00:00,  2.64s/it]
5 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:24<00:00,  2.50s/it]
6 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:25<00:00,  2.55s/it]
7 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:25<00:00,  2.56s/it]
8 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:24<00:00,  2.48s/it]
9 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:25<00:00,  2.53s/it]
10 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:25<00:00,  2.55s/it]
11 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:25<00:00,  2.50s/it]
12 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:25<00:00,  2.52s/it]
13 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:25<00:00,  2.52s/it]
14 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:25<00:00,  2.57s/it]
15 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:25<00:00,  2.51s/it]
16 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:24<00:00,  2.48s/it]
17 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:24<00:00,  2.49s/it]
18 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:24<00:00,  2.50s/it]
19 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:25<00:00,  2.53s/it]
20 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:24<00:00,  2.49s/it]
21 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:25<00:00,  2.53s/it]
22 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:25<00:00,  2.55s/it]
23 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:25<00:00,  2.52s/it]
24 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:24<00:00,  2.49s/it]
25 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:24<00:00,  2.47s/it]
26 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:25<00:00,  2.51s/it]
27 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:24<00:00,  2.48s/it]
28 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:25<00:00,  2.53s/it]
29 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:25<00:00,  2.52s/it]
30 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:25<00:00,  2.51s/it]
31 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:25<00:00,  2.51s/it]
32 / 33
Running reservoirs: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:25<00:00,  2.50s/it]

7. Plot the predictions#

plt.figure(figsize=(20, 4))
for method in ["classical", "quantum_part", "quantum_stab"]:
    plt.plot(prediction[method], label=method)
plt.plot(X_train, "k", label="training")
plt.legend(loc="upper left")
<matplotlib.legend.Legend at 0x745752f8dc40>
../../_images/5e55cc0454cf3363d699ea9e6719f131f1f23d38cb01634852b61280df7729af.png

8. Poincaré plot to see how well the logistic map was learned.#

fig = plt.figure()
k = 1
plt.plot(ts[k:], ts[:-k], lw=0, color="gray", marker="o", alpha=0.5)

for method in ["classical", "quantum_part", "quantum_stab"]:
    tmp = prediction[method][len(X_train) :]
    plt.plot(tmp[k:], tmp[:-k], "o", label=method)

plt.legend(loc="center left")
<matplotlib.legend.Legend at 0x745753016f30>
../../_images/b577cc737e445b74a6d8d52f490eb5f1ddcc6af3dc0103030a4afe92912ad00f.png