Custom quantum models
In qadence
, the QuantumModel
is the central class point for executing
QuantumCircuit
s. The idea of a QuantumModel
is to decouple the backend
execution from the management of circuit parameters and desired quantum
computation output.
In the following, we create a custom QuantumModel
instance which introduces
some additional optimizable parameters:
* an adjustable scaling factor in front of the observable to measured
* adjustable scale and shift factors to be applied to the model output before returning the result
This can be easily done using PyTorch flexible model definition, and it will
automatically work with the rest of qadence
infrastructure.
The custom model can be used like any other QuantumModel
:
from qadence import Parameter, RX, CNOT, QuantumCircuit
from qadence import chain, kron, hamiltonian_factory, Z
from sympy import acos
def quantum_circuit(n_qubits):
x = Parameter("x", trainable=False)
fm = kron(RX(i, acos(x) * (i+1)) for i in range(n_qubits))
ansatz = kron(RX(i, f"theta{i}") for i in range(n_qubits))
ansatz = chain(ansatz, CNOT(0, n_qubits-1))
block = chain(fm, ansatz)
block.tag = "circuit"
return QuantumCircuit(n_qubits, block)
n_qubits = 4
batch_size = 10
circuit = quantum_circuit(n_qubits)
observable = hamiltonian_factory(n_qubits, detuning=Z) # Total magnetization
model = CustomQuantumModel(circuit, observable, backend="pyqtorch")
values = {"x": torch.rand(batch_size)}
res = model(values)
print("Model output: ", res)
assert len(res) == batch_size
Quantum model with wavefunction overlaps
QuantumModel
's can also use different quantum operations in their forward
pass, such as wavefunction overlaps described here. Beware that the resulting overlap tensor
has to be differentiable to apply gradient-based optimization. This is only applicable to the "EXACT"
overlap method.
Here we show how to use overlap calculation when fitting a parameterized quantum circuit to act as a standard Hadamard gate.
from qadence import RY, RX, H, Overlap
# create a quantum model which acts as an Hadamard gate after training
class LearnHadamard(QuantumModel):
def __init__(
self,
train_circuit: QuantumCircuit,
target_circuit: QuantumCircuit,
backend="pyqtorch",
):
super().__init__(circuit=train_circuit, backend=backend)
self.overlap_fn = Overlap(train_circuit, target_circuit, backend=backend, method="exact", diff_mode='ad')
def forward(self):
return self.overlap_fn()
# compute the wavefunction of the associated train circuit
def wavefunction(self):
return model.overlap_fn.run({})
train_circuit = QuantumCircuit(1, chain(RX(0, "phi"), RY(0, "theta")))
target_circuit = QuantumCircuit(1, H(0))
model = LearnHadamard(train_circuit, target_circuit)
# get the overlap between model and target circuit wavefunctions
print(model())
This model can then be trained with the standard Qadence helper functions.