Noiseless simulations

Let us take a look at how to encode a noiseless, yet time-dependent Hamiltonian of the following form:

\[H(t) = \alpha \sigma^y_0 + \beta(t) * \sigma^x_1 \sigma^x_2\]

where \(\alpha = \pi/2\) to represent a rotation of the \(\left|0\right>\) state of qubit \(0\) around the \(Y\) axis by \(\pi\) and \(\beta(t) = 1.27 * \sin(t)\) is some time-dependent function for \(\sigma^x_1 \sigma^x_2\) acting on qubit \(1\) and \(2\).

The code snippet below performs a simulation of the evolution of this \(H(t)\) for time tmax = 1 both in SAMPLE and OBS mode:

import numpy as np
from qat.qpus import AnalogQPU
from qat.core import Observable, Term, Schedule
from qat.core.variables import Variable, sin

# Define a time Variable
t = Variable("t", float)

# Define the Hamiltonian in a drive to enter the Schedule
alpha =  np.pi / 2
beta_t  = 1.27 * sin(t)
drive = [(alpha, Observable(3, pauli_terms=[Term(1, "Y", [0])])),
         (beta_t, Observable(3, pauli_terms=[Term(1, "XX", [1, 2])]))]
schedule = Schedule(drive=drive, tmax=1.0) # tmax as the evolution duration from t=0

# Specify Observables to measure at the end
H_target_0 = Observable(3, pauli_terms=[Term(1, "Z", [0])])
H_target_12 = Observable(3, pauli_terms=[Term(1, "YX", [1, 2]),
                                         Term(1.34, "ZZ", [1, 2])])
job_obs = schedule.to_job(job_type="OBS",
                          observable=H_target_0,
                          observables=[H_target_12])

# Jobs are in SAMPLE mode by default
job_sample = schedule.to_job()

# Create a QPU and send the jobs for simulation
qpu = AnalogQPU()
res_obs = qpu.submit(job_obs)
res_sample = qpu.submit(job_sample)

# Output the results
print("<H_target_0> =", res_obs.value)
print("<H_target_12> =", res_obs.values[0])
for sample in res_sample:
    if sample.probability > 1e-5:
        print(sample.state, sample.amplitude)
<H_target_0> = -0.999991678115056
<H_target_12> = 0.4201682609634986
|100> (0.8343589502672528+0j)
|111> -0.5512139514464107j
If one measures the observable \(\sigma_z\) on qubit \(0\), via H_target_0, one should get \(-1\). At the same time, more involved observables can also be measured, e.g. H_target_12 on qubit \(1\) and \(2\), and furthermore, during the same simulation - via the observables field of to_job().
When choosing SAMPLE mode the final state of the system will be shown. In this case the first qubit will have changed to state \(\left|1\right>\), while the second and the third will be in some superposition of the states \(\left|00\right>\) and \(\left|11\right>\).

A more involved example with an imperfect QPU (for which we specify a hardware model) can be found in the following Getting started notebook. The section on analog computation gives a simple introduction to the class Schedule along with examples on how to perform arithmetic and other operations with one or more instances of it.