https://github.com/epiqc/ScaffCC
Tip revision: 4d7bfa034cfaea4e8346396c6198cdd3e271d272 authored by Andrew Litteken on 23 April 2020, 16:55:47 UTC
Version 5 Upgrade! (#40)
Version 5 Upgrade! (#40)
Tip revision: 4d7bfa0
ground_state_estimation.h2.scaffold
#include <math.h>
#include <../../Library/cRz/cRz.scaffold>
#define M 4 //number of bottom register qubits
#define TROTTER 8
#define _upper_sz 4
#define _iteration 0
#define _estimate 0
enum spin {alpha, beta};
const enum spin sigma[M] = {
alpha,
beta,
alpha,
beta
};
// LIQUID DATA
// tst=0
// info=0.00,0.7414
// nuc=0.713776188
// Ehf=-1.116685636
// 0,0=-1.252477495 -1.2563390710389655
// 1,1=-0.475934275 -0.4718960093502949
// 0,0,0,0=0.674493166 0.6757101541858549
// 0,1,0,1=0.181287518 0.18093119996471013
// 0,1,1,0=0.663472101 0.664581729691277
// 1,1,1,1=0.697398010
// h_double[0][1][1][0]=h_double[1][0][0][1]=0.6757101541858549;
// h_double[0][2][2][0]=h_double[2][0][0][2]=0.664581729691277;
// h_double[0][3][3][0]=h_double[3][0][0][3]=0.664581729691277;
// h_double[1][2][2][1]=h_double[2][1][1][2]=0.664581729691277;
// h_double[1][3][3][1]=h_double[3][1][1][3]=0.664581729691277;
// h_double[2][3][3][2]=h_double[3][2][2][3]=0.697398010;
//
// h_double[0][2][0][2]=h_double[1][3][1][3]=0.18093119996471013;
// h_double[2][0][2][0]=h_double[3][1][3][1]=0.18093119996471013;
// h_double[0][3][1][2]=h_double[0][1][3][2]=0.18093119996471013;
// according to 1.4768229
// h_double[2][1][3][0]=h_double[2][3][1][0]=0.18093119996471013;
const double h_single[M][M] = {
{-1.2563390710389655, 0.0, 0.0, 0.0},
{0.0, -1.2563390710389655, 0.0, 0.0},
{0.0, 0.0, -0.4718960093502949, 0.0},
{0.0, 0.0, 0.0, -0.4718960093502949}
};
const double h_double[M][M][M][M] =
{
{
{{0.0,0.0,0.0,0.0},{0.0,0.0,0.0,0.0},{0.0,0.0,0.0,0.0},{0.0,0.0,0.0,0.0}},
{{0.0,0.0,0.0,0.0},{0.6757101541858549,0.0,0.0,0.0},{0.0,0.0,0.0,0.0},{0.0,0.0,0.18093119996471013,0.0}},
{{0.0,0.0,0.18093119996471013,0.0},{0.0,0.0,0.0,0.0},{0.664581729691277,0.0,0.0,0.0},{0.0,0.0,0.0,0.0}},
{{0.0,0.0,0.0,0.0},{0.0,0.0,0.18093119996471013,0.0},{0.0,0.0,0.0,0.0},{0.664581729691277,0.0,0.0,0.0}}
},
{
{{0.0,0.6757101541858549,0.0,0.0},{0.0,0.0,0.0,0.0},{0.0,0.0,0.0,0.0},{0.0,0.0,0.0,0.0}},
{{0.0,0.0,0.0,0.0},{0.0,0.0,0.0,0.0},{0.0,0.0,0.0,0.0},{0.0,0.0,0.0,0.0}},
{{0.0,0.0,0.0,0.0},{0.0,0.0,0.0,0.0},{0.0,0.664581729691277,0.0,0.0},{0.0,0.0,0.0,0.0}},
{{0.0,0.0,0.0,0.0},{0.0,0.0,0.0,0.18093119996471013},{0.0,0.0,0.0,0.0},{0.0,0.664581729691277,0.0,0.0}}
},
{
{{0.0,0.0,0.664581729691277,0.0},{0.0,0.0,0.0,0.0},{0.18093119996471013,0.0,0.0,0.0},{0.0,0.0,0.0,0.0}},
{{0.0,0.0,0.0,0.0},{0.0,0.0,0.664581729691277,0.0},{0.0,0.0,0.0,0.0},{0.0,0.0,0.0,0.0}},
{{0.0,0.0,0.0,0.0},{0.0,0.0,0.0,0.0},{0.0,0.0,0.0,0.0},{0.0,0.0,0.0,0.0}},
{{0.0,0.0,0.0,0.0},{0.0,0.0,0.0,0.0},{0.0,0.0,0.0,0.0},{0.0,0.0,0.697398010,0.0}}
},
{
{{0.0,0.0,0.0,0.664581729691277},{0.0,0.0,0.0,0.0},{0.0,0.0,0.0,0.0},{0.0,0.0,0.0,0.0}},
{{0.0,0.0,0.0,0.0},{0.0,0.0,0.0,0.664581729691277},{0.0,0.0,0.0,0.0},{0.0,0.18093119996471013,0.0,0.0}},
{{0.0,0.0,0.0,0.0},{0.0,0.0,0.0,0.0},{0.0,0.0,0.0,0.697398010},{0.0,0.0,0.0,0.0}},
{{0.0,0.0,0.0,0.0},{0.0,0.0,0.0,0.0},{0.0,0.0,0.0,0.0},{0.0,0.0,0.0,0.0}}
}
};
// Controlled Phase gate
// controlled-[e^(i*theta) 0;0 e^(i*theta)] is equivalent to the phase shift gate [1 0; 0 e^(i*theta)] on the control qubit
// can be written as a product of G(theta/2) and Rz(theta); G is physically unobservable so it can be neglected
scaff_module ControlledPhase (
qbit control,
qbit target,
double theta
) {
// Rz(control, theta);
}
// Implement the Y gate defined in the GFIs Y=Rx(-PI/2), we'll name it Y_Rx
scaff_module Y_Rx(qbit target)
{
// G(target,-PI/4); //indistinguishable global phase
Z(target);
H(target);
S(target);
H(target);
Z(target);
}
// Implement the dagger of the Y gate = Rx(PI/2)
scaff_module Y_Rx_Dagger(qbit target)
{
// G(target,-PI/4);
H(target);
S(target);
H(target);
}
scaff_module DoubleExcitationOperator (
qbit control,
qbit reg[M],
int p,
int q,
int r,
int s,
double theta0,
double theta1,
double theta2,
double theta3
) {
// Prerequisite: p > q > r > s
// See Double Excitation Operator circuit in Table A1 of Whitfield et al 2010
for (int i = 0; i < 4; i++) {
// NB(pranav): for some reason, ScaffCC wouldn't let me move the M operator
// into a separate scaff_module. Seems like a ScaffCC bug.
switch (i) { // M operator (as defined in A1)
case 0: H(reg[p]); H(reg[q]); Y_Rx(reg[r]); Y_Rx(reg[s]); break;
case 1: Y_Rx(reg[p]); Y_Rx(reg[q]); H(reg[r]); H(reg[s]); break;
case 2: H(reg[p]); Y_Rx(reg[q]); Y_Rx(reg[r]); H(reg[s]); break;
case 3: Y_Rx(reg[p]); H(reg[q]); H(reg[r]); Y_Rx(reg[s]); break;
}
CNOT(reg[p], reg[q]); CNOT(reg[q], reg[r]); CNOT(reg[r], reg[s]);
switch (i) { // M operator (as defined in A1)
case 0: cRz(control, reg[s], theta0); break;
case 1: cRz(control, reg[s], theta1); break;
case 2: cRz(control, reg[s], theta2); break;
case 3: cRz(control, reg[s], theta3); break;
}
CNOT(reg[r], reg[s]); CNOT(reg[q], reg[r]); CNOT(reg[p], reg[q]);
switch (i) { // M^dagger operator is identical since matrices are Hermitian
case 0: H(reg[p]); H(reg[q]); Y_Rx_Dagger(reg[r]); Y_Rx_Dagger(reg[s]); break;
case 1: Y_Rx_Dagger(reg[p]); Y_Rx_Dagger(reg[q]); H(reg[r]); H(reg[s]); break;
case 2: H(reg[p]); Y_Rx_Dagger(reg[q]); Y_Rx_Dagger(reg[r]); H(reg[s]); break;
case 3: Y_Rx_Dagger(reg[p]); H(reg[q]); H(reg[r]); Y_Rx_Dagger(reg[s]); break;
}
}
}
int main ()
{
qbit bottomregister[M];
// eigenstate electron orbital assignments
// bonding orbitals
PrepZ ( bottomregister[0], 1 );
PrepZ ( bottomregister[1], 1 );
// anitbonding orbitals
PrepZ ( bottomregister[2], 0 );
PrepZ ( bottomregister[3], 0 );
qbit topregister[2];
PrepZ ( topregister[0], 0 );
H(topregister[0]);
for (int unitary=0; unitary<(1<<(_upper_sz-_iteration-1)); unitary++) {
double time_step = 1.0/(double)TROTTER;
for (int rep=0; rep<TROTTER; rep++) {
// single electron operators
for (int i=0; i<M; i++) {
ControlledPhase (
topregister[0],
bottomregister[i],
0.5 * h_single[i][i] * time_step
);
}
// two electron operators: number-number operators
double theta = 0.0;
for (int q=0; q<M; q++) {
for (int p=0; p<q; p++) {
theta += 0.25 * h_double[p][q][q][p];
if (sigma[p]==sigma[q]) {
theta -= 0.25 * h_double[p][q][p][q];
}
}
}
Rz (topregister[0], theta * time_step);
// single electron operators
for (int i=0; i<M; i++) {
cRz (
topregister[0],
bottomregister[i],
- 0.5 * h_single[i][i] * time_step
);
}
for (int p=0; p<M; p++) {
double thetas = 0.0;
for (int q=0; q<M; q++) {
if (p!=q) { // DONE: check this against UCSB documentation
thetas += h_double[p][q][q][p];
if (sigma[p]==sigma[q]) {
thetas -= h_double[p][q][p][q]; // h2020 and h3131 are missing; McArdle confirms they are zero
}
}
}
cRz (
topregister[0],
bottomregister[p],
- 0.25 * thetas * time_step
);
}
// Cross validated against Seeley 2012
for (int t=3; t>=0; t--) {
for (int c=t-1; c>=0; c--) {
CNOT(bottomregister[c], bottomregister[t]);
double eta = 0.25 * h_double[c][t][t][c];
if (sigma[c]==sigma[t]) eta -= 0.25*h_double[c][t][c][t];
cRz(topregister[0], bottomregister[t], eta*time_step);
CNOT(bottomregister[c], bottomregister[t]);
}
}
// two electron operators: excitation-exitation operators
DoubleExcitationOperator (
topregister[0],
bottomregister,
0, 1, 2, 3,
-time_step * (h_double[0][3][1][2]+h_double[0][1][3][2]) / 8.0,
-time_step * (h_double[0][3][1][2]+h_double[0][1][3][2]) / 8.0,
time_step * (h_double[0][3][1][2]+h_double[0][1][3][2]) / 8.0,
time_step * (h_double[0][3][1][2]+h_double[0][1][3][2]) / 8.0
);
}
}
for (int c=0; c<_iteration; c++) {
if ((_estimate>>c)&1) {
Rz ( topregister[0], -M_PI/pow(2,_iteration-c) );
}
}
H(topregister[0]);
}