openqasm/examples/vqe.qasm

89 lines
2.6 KiB
Plaintext

/*
* Variational eigensolver example
*
* Goal is to estimate the energy for a fixed set of parameters.
* The parameters are updated outside of this program and a new
* OpenQASM circuit is generated for the next iteration.
*/
include "stdgates.inc";
const int[32] n = 10; // number of qubits
const int[32] layers = 3; // number of entangler layers
const int[32] prec = 16; // precision of all types
const int[32] shots = 1000; // number of shots per Pauli observable
// Parameters could be written to local variables for this
// iteration, but we will request them using extern functions
extern get_parameter(uint[prec], uint[prec]) -> angle[prec];
extern get_npaulis() -> uint[prec];
extern get_pauli(int[prec]) -> bit[2 * n];
// The energy calculation uses floating point division,
// so we do that calculation in an extern function
extern update_energy(int[prec], uint[prec], float[prec]) -> float[prec];
gate entangler q { for uint i in [0:n-2] { cx q[i], q[i+1]; } }
def xmeasure(qubit q) -> bit { h q; return measure q; }
def ymeasure(qubit q) -> bit { s q; h q; return measure q; }
/* Pauli measurement circuit.
* The first n-bits of spec are the X component.
* The second n-bits of spec are the Z component.
*/
def pauli_measurement(bit[2*n] spec, qubit[n] q) -> bit {
bit b = 0;
for uint[prec] i in [0: n - 1] {
bit temp;
if(spec[i]==1 && spec[n+i]==0) { temp = xmeasure(q[i]); }
if(spec[i]==0 && spec[n+i]==1) { temp = measure q[i]; }
if(spec[i]==1 && spec[n+i]==1) { temp = ymeasure(q[i]); }
b ^= temp;
}
return b;
}
// Circuit to prepare trial wave function
def trial_circuit(qubit[n] q) {
for int[prec] l in [0: layers - 1] {
for uint[prec] i in [0: n - 1] {
angle[prec] theta;
theta = get_parameter(l * layers + i);
ry(theta) q[i];
}
if(l != layers - 1) entangler q;
}
}
/* Apply VQE ansatz circuit and measure a Pauli operator
* given by spec. Return the number of 1 outcomes.
*/
def counts_for_term(bit[2*n] spec, qubit[n] q) -> uint[prec] {
uint[prec] counts;
for uint i in [1: shots] {
bit b;
reset q;
trial_circuit q;
b = pauli_measurement(spec, q);
counts += int[1](b);
}
return counts;
}
// Estimate the expected energy
def estimate_energy(qubit[n] q) -> float[prec] {
float[prec] energy;
uint[prec] npaulis = get_npaulis();
for int[prec] t in [0:npaulis-1] {
bit[2*n] spec = get_pauli(t);
uint[prec] counts;
counts = counts_for_term(spec, q);
energy = update_energy(t, counts, energy);
}
return energy;
}
qubit[n] q;
float[prec] energy;
energy = estimate_energy(q);