Reservoris Quàntics
El funcional QuantumReservoir executa un pipeline de reservoir sobre una seqüència d’entrades. Cada capa aplica un circuit opcional de preprocessament, un bloc de dinàmica de reservoir analog (Schedule) i un circuit opcional de postprocessament, seguit de mesures d’un o més observables. La llista opcional qubits_to_reset es pot fer servir per restablir qubits seleccionats entre capes.
Les entrades del reservoir es representen fent servir paràmetres ReservoirInput. Aquests es comporten com els objectes estàndard Parameter però estan marcats com a no entrenables, de manera que poden ser dirigits per seqüències de dades d’entrada en lloc de bucles d’optimització.
Paràmetres
initial_state (
QTensor): Estat inicial del reservoir.reservoir_layer (
ReservoirLayer): Defineix el pre/postprocessament, la dinàmica del reservoir, els observables i la política de restabliment.input_per_layer (List[Dict[str, float]]): Valors d’entrada a aplicar a cada capa, indexats pels noms dels paràmetres d’entrada (normalment les etiquetes de
ReservoirInput).
Retorna
FunctionalResult: Accediu als valors d’expectació per capa mitjançantget_expectation_values(), més estats opcionals mitjançantget_intermediate_states()si es va sol·licitar tomografia d’estat a l’especificació de lectura.
Exemple d’ús
import numpy as np
from qilisdk.backends import CudaBackend
from qilisdk.core import ket
from qilisdk.digital import Circuit, U2
from qilisdk.functionals.quantum_reservoirs import QuantumReservoir, ReservoirInput, ReservoirLayer
from qilisdk.analog import Schedule, X, Z
from qilisdk.readout import Readout
pre_processing = Circuit(2)
pre_processing.add(U2(1, phi=ReservoirInput("phi_1", 0.1), gamma=ReservoirInput("gamma_1", 0.1)))
res_layer = ReservoirLayer(
evolution_dynamics=Schedule(
hamiltonians={"h": Z(0) + Z(1) + Z(0) * Z(1) + 0.5 * (X(0) + X(1))},
total_time=1.0,
dt=0.1,
),
input_encoding=pre_processing,
qubits_to_reset=[1],
)
reservoir = QuantumReservoir(
initial_state=(np.random.rand() * ket(0, 0) + np.random.rand() * ket(1, 1)).unit(),
reservoir_layer=res_layer,
input_per_layer=[
{"phi_1": 0.2, "gamma_1": 0.1},
{"phi_1": 0.3, "gamma_1": 0.2},
{"phi_1": 0.4, "gamma_1": 0.3},
],
)
results = CudaBackend().execute(
reservoir,
Readout().with_expectation(observables=[Z(0), Z(1), Z(0) * Z(1)]),
)
print(results.get_expectation_values())
Codificació de dades d’entrada
Podeu injectar dades clàssiques en una capa de reservoir en múltiples llocs. L’únic requisit és que les claus de input_per_layer coincideixin amb les etiquetes dels objectes ReservoirInput que col·loqueu a la capa.
1. Codificar amb circuits d’entrada i sortida
from qilisdk.analog import Schedule, X, Z
from qilisdk.core import ket
from qilisdk.digital import Circuit, RX, RY
from qilisdk.functionals.quantum_reservoirs import QuantumReservoir, ReservoirInput, ReservoirLayer
theta_in = ReservoirInput("theta_in", 0.0)
phi_out = ReservoirInput("phi_out", 0.0)
input_circuit = Circuit(2)
input_circuit.add(RX(0, theta=theta_in))
output_circuit = Circuit(2)
output_circuit.add(RY(1, theta=phi_out))
layer = ReservoirLayer(
evolution_dynamics=Schedule(
hamiltonians={"h": Z(0) * Z(1) + 0.3 * (X(0) + X(1))},
total_time=1.0,
dt=0.1,
),
input_encoding=input_circuit,
output_encoding=output_circuit,
)
reservoir = QuantumReservoir(
initial_state=ket(0, 0),
reservoir_layer=layer,
input_per_layer=[
{"theta_in": 0.1, "phi_out": 0.0},
{"theta_in": 0.5, "phi_out": 0.4},
],
)
2. Codificar directament en paràmetres del Hamiltonià
from qilisdk.analog import Schedule, X, Z
from qilisdk.core import ket
from qilisdk.functionals.quantum_reservoirs import QuantumReservoir, ReservoirInput, ReservoirLayer
gain = ReservoirInput("gain", 0.2)
detuning = ReservoirInput("detuning", -0.1)
hamiltonian = gain * (X(0) + X(1)) + detuning * (Z(0) + Z(1)) + Z(0) * Z(1)
layer = ReservoirLayer(
evolution_dynamics=Schedule(
hamiltonians={"h": hamiltonian},
coefficients={"h": {(0.0, 1.0): 1.0}},
dt=0.05,
),
)
reservoir = QuantumReservoir(
initial_state=ket(0, 0),
reservoir_layer=layer,
input_per_layer=[
{"gain": 0.1, "detuning": -0.2},
{"gain": 0.7, "detuning": 0.0},
{"gain": 0.3, "detuning": 0.2},
],
)
3. Codificar en el perfil i la durada de l’esquema
from qilisdk.analog import Schedule, X, Z
from qilisdk.core import ket
from qilisdk.functionals.quantum_reservoirs import QuantumReservoir, ReservoirInput, ReservoirLayer
drive_amp = ReservoirInput("drive_amp", 1.0)
duration = ReservoirInput("duration", 1.0)
layer = ReservoirLayer(
evolution_dynamics=Schedule(
hamiltonians={
"drive": X(0) + X(1),
"problem": Z(0) * Z(1),
},
coefficients={
"drive": {(0.0, 1.0): drive_amp},
"problem": {(0.0, 1.0): lambda t: t},
},
total_time=duration,
dt=0.05,
),
)
reservoir = QuantumReservoir(
initial_state=ket(0, 0),
reservoir_layer=layer,
input_per_layer=[
{"drive_amp": 1.0, "duration": 0.6},
{"drive_amp": 0.3, "duration": 1.4},
],
)