Quantum Reservoir Computing: Logistic map#

1. Setup#

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 documented in this preprint.

Install the dependencies first with pip install -r requirements.txt.

2. Import the 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