Unverified Commit a6fcb6af authored by Thien Nguyen's avatar Thien Nguyen Committed by GitHub
Browse files

Merge pull request #237 from tnguyen-ornl/tnguyen/pnnl-tutorials

Added source files from PNNL demo/tutorial session

Example files only, no code changes.
parents f198798c 5d580a23
Pipeline #172438 passed with stage
in 61 minutes and 21 seconds
__qpu__ void ccnot(qreg q) {
decompose {
UnitaryMatrix ccnot_mat = UnitaryMatrix::Identity(8, 8);
ccnot_mat(6, 6) = 0.0;
ccnot_mat(7, 7) = 0.0;
ccnot_mat(6, 7) = 1.0;
ccnot_mat(7, 6) = 1.0;
}
(q, QFAST);
}
int main() {
auto q = qalloc(3);
ccnot::print_kernel(q);
return 0;
}
\ No newline at end of file
from qcor import *
@qjit
def nothing(q : qreg):
# This is Z Z = I
Z(q[0])
H(q[0])
X(q[0])
H(q[0])
H(q[1])
Rx(q[1], 1.2345)
H(q[1])
set_opt_level(2)
nothing.print_kernel(qalloc(2))
\ No newline at end of file
// Demonstrate the programmability of a simple kernel
// (1) Run with QPP first
// (2) Run with noisy backend (remote Honeywell simulator)
// qcor -set-credentials honeywell
// qcor ghz.cpp -qpu honeywell:HQS-LT-S1-SIM -shots 1024
// (3) Run with IonQ
// qcor ghz.cpp -qpu ionq -shots 1024
// (4) Run with OLCF QLM simulator (QLMaaS)
// qcor ghz.cpp -qpu atos-qlm -shots 1024
// (5) Run with just print_kernel to show automatic placement
// Uncomment print_kernel
// qcor ghz.cpp -qpu ibm:ibmq_toronto
__qpu__ void ghz(qreg q) {
H(q[0]);
for (int i = 0; i < q.size() - 1; i++) {
CX(q[i], q[i + 1]);
}
Measure(q);
}
int main() {
auto q = qalloc(6);
ghz(q);
q.print();
// ghz::print_kernel(q);
}
\ No newline at end of file
from qcor import *
@qjit
def ghz(q : qreg):
H(q[0])
for i in range(q.size()-1):
X.ctrl([q[i]], q[i+1])
Measure(q)
set_qpu('ionq')
set_shots(1024)
q = qalloc(6)
ghz(q)
q.print()
# ghz.print_kernel(q)
// Create a general grover search algorithm.
// Let's create that marks 2 states
// Show figures Init - [Oracle - Amplification for i in iters] - Measure
// https://www.nature.com/articles/s41467-017-01904-7
// Show off kernel composition, common patterns,
// functional programming (kernels taking other kernels)
using GroverPhaseOracle = KernelSignature<qreg>;
__qpu__ void amplification(qreg q) {
// H q X q ctrl-ctrl-...-ctrl-Z H q Xq
// compute - action - uncompute
compute {
H(q);
X(q);
}
action {
auto ctrl_bits = q.head(q.size() - 1);
auto last_qubit = q.tail();
Z::ctrl(ctrl_bits, last_qubit);
}
}
__qpu__ void run_grover(qreg q, GroverPhaseOracle oracle,
const int iterations) {
H(q);
for (int i = 0; i < iterations; i++) {
oracle(q);
amplification(q);
}
Measure(q);
}
__qpu__ void oracle(qreg q) {
// Mark 101 and 011
CZ(q[0], q[2]);
CZ(q[1], q[2]);
}
int main() {
const int N = 3;
// Allocate some qubits
auto q = qalloc(N);
// Call grover given the oracle and n iterations
run_grover(q, oracle, 1);
// print the histogram
q.print();
}
\ No newline at end of file
__qpu__ void ansatz(qreg q, double theta) {
X(q[0]);
Ry(q[1], theta);
CX(q[1], q[0]);
}
int main() {
// Create the Hamiltonian
auto H = -2.1433 * X(0) * X(1) - 2.1433 * Y(0) * Y(1) + .21829 * Z(0) -
6.125 * Z(1) + 5.907;
std::cout << "H = " << H.toString() << "\n";
const double test_theta = 1.2345;
auto q = qalloc(2);
const double energy = ansatz::observe(H, q, test_theta);
std::cout << "E(" << test_theta << ") = " << energy << "\n";
// q.print();
}
\ No newline at end of file
__qpu__ void ansatz(qreg q, double theta) {
X(q[0]);
Ry(q[1], theta);
CX(q[1], q[0]);
}
int main() {
// Create the Hamiltonian
auto H = -2.1433 * X(0) * X(1) - 2.1433 * Y(0) * Y(1) + .21829 * Z(0) -
6.125 * Z(1) + 5.907;
const double test_theta = 1.2345;
auto q = qalloc(2);
// Gradient:
std::vector<double> dE{0.0};
const double energy = ansatz::autograd(H, dE, q, test_theta);
std::cout << "E(" << test_theta << ") = " << energy << "; dE = " << dE[0]
<< "\n";
double theta = 0.0;
for (int i = 0; i < 50; ++i) {
auto qq = qalloc(2);
const double f = ansatz::autograd(H, dE, qq, theta);
std::cout << "E(" << theta << ") = " << f << "; dE = " << dE[0] << "\n";
theta = theta - 0.01 * dE[0];
}
}
\ No newline at end of file
__qpu__ void ansatz(qreg q, double theta) {
X(q[0]);
Ry(q[1], theta);
CX(q[1], q[0]);
}
int main() {
// Create the Hamiltonian
auto H = -2.1433 * X(0) * X(1) - 2.1433 * Y(0) * Y(1) + .21829 * Z(0) -
6.125 * Z(1) + 5.907;
auto optimizer = createOptimizer("nlopt");
ObjectiveFunction opt_function(
[&](const std::vector<double> &x, std::vector<double> &dx) {
auto q = qalloc(2);
auto exp = ansatz::observe(H, q, x[0]);
print("<E(", x[0], ") = ", exp);
return exp;
},
1);
auto [energy, opt_params] = optimizer->optimize(opt_function);
print("Min energy = ", energy);
}
\ No newline at end of file
from qcor import *
import numpy as np
@qjit
def ansatz(q : qreg, theta : float):
X(q[0])
X(q[2])
with compute:
Rx(q[0], np.pi/2.)
H(q.tail(3))
for i in range(3):
X.ctrl([q[i]], q[i+1])
with action:
Rz(q.tail(), theta)
h2_geom = '''H 0.000000 0.0 0.0
H 0.0 0.0 .7474'''
H = createOperator("pyscf", {"basis": "sto-3g", "geometry": h2_geom})
print("pyscf operator:")
print(H)
H = operatorTransform("jw", H)
print("JW transform:")
print(H)
H = operatorTransform('qubit-tapering', H)
print("Reduced with qubit tapering:")
print(H)
# Run this from the command line like this
#
# python3 exp_fermion.py -shots 100
from qcor import *
from openfermion.ops import FermionOperator as FOp
@qjit
def ansatz(q: qreg, x: List[float], exp_args: List[Operator]):
X(q[0])
for i, exp_arg in enumerate(exp_args):
exp_i_theta(q, x[i], exp_args[i])
# Create OpenFermion operators for our quantum kernel...
exp_args_openfermion = [FOp('0^ 2') - FOp('2^ 0')]
# We need to translate OpenFermion ops into qcor Operators to use with kernels...
exp_args_qcor = [createOperator('fermion', fop) for fop in exp_args_openfermion]
ansatz.print_kernel(qalloc(3), [1.0], exp_args_qcor)
\ No newline at end of file
#include "qcor_qsim.hpp"
// Demonstrate qsim's Adapt-VQE workflow
/// $ qcor -qpu qpp AdaptVqeWorkflow.cpp
/// $ ./a.out
int main(int argc, char **argv) {
const auto str = std::string(
"(-0.165606823582,-0) 1^ 2^ 1 2 + (0.120200490713,0) 1^ 0^ 0 1 + "
"(-0.0454063328691,-0) 0^ 3^ 1 2 + (0.168335986252,0) 2^ 0^ 0 2 + "
"(0.0454063328691,0) 1^ 2^ 3 0 + (0.168335986252,0) 0^ 2^ 2 0 + "
"(0.165606823582,0) 0^ 3^ 3 0 + (-0.0454063328691,-0) 3^ 0^ 2 1 + "
"(-0.0454063328691,-0) 1^ 3^ 0 2 + (-0.0454063328691,-0) 3^ 1^ 2 0 + "
"(0.165606823582,0) 1^ 2^ 2 1 + (-0.165606823582,-0) 0^ 3^ 0 3 + "
"(-0.479677813134,-0) 3^ 3 + (-0.0454063328691,-0) 1^ 2^ 0 3 + "
"(-0.174072892497,-0) 1^ 3^ 1 3 + (-0.0454063328691,-0) 0^ 2^ 1 3 + "
"(0.120200490713,0) 0^ 1^ 1 0 + (0.0454063328691,0) 0^ 2^ 3 1 + "
"(0.174072892497,0) 1^ 3^ 3 1 + (0.165606823582,0) 2^ 1^ 1 2 + "
"(-0.0454063328691,-0) 2^ 1^ 3 0 + (-0.120200490713,-0) 2^ 3^ 2 3 + "
"(0.120200490713,0) 2^ 3^ 3 2 + (-0.168335986252,-0) 0^ 2^ 0 2 + "
"(0.120200490713,0) 3^ 2^ 2 3 + (-0.120200490713,-0) 3^ 2^ 3 2 + "
"(0.0454063328691,0) 1^ 3^ 2 0 + (-1.2488468038,-0) 0^ 0 + "
"(0.0454063328691,0) 3^ 1^ 0 2 + (-0.168335986252,-0) 2^ 0^ 2 0 + "
"(0.165606823582,0) 3^ 0^ 0 3 + (-0.0454063328691,-0) 2^ 0^ 3 1 + "
"(0.0454063328691,0) 2^ 0^ 1 3 + (-1.2488468038,-0) 2^ 2 + "
"(0.0454063328691,0) 2^ 1^ 0 3 + (0.174072892497,0) 3^ 1^ 1 3 + "
"(-0.479677813134,-0) 1^ 1 + (-0.174072892497,-0) 3^ 1^ 3 1 + "
"(0.0454063328691,0) 3^ 0^ 1 2 + (-0.165606823582,-0) 3^ 0^ 3 0 + "
"(0.0454063328691,0) 0^ 3^ 2 1 + (-0.165606823582,-0) 2^ 1^ 2 1 + "
"(-0.120200490713,-0) 0^ 1^ 0 1 + (-0.120200490713,-0) 1^ 0^ 1 0 + "
"(0.7080240981,0)");
Operator H_vqe("fermion", str);
auto problemModel = QuaSiMo::ModelFactory::createModel(&H_vqe);
auto optimizer = createOptimizer("nlopt", {{"nlopt-optimizer", "l-bfgs"}});
const int nElectrons = 2;
const auto pool_vqe = "qubit-pool";
auto workflow = QuaSiMo::getWorkflow("adapt", {{"optimizer", optimizer},
{"pool", pool_vqe},
{"n-electrons", nElectrons}});
auto result = workflow->execute(problemModel);
std::cout << "Final energy: " << result.get<double>("energy") << "\n";
return 0;
}
\ No newline at end of file
#include "qcor_qsim.hpp"
// Validate the ground-state energy of the Deuteron Hamiltonian operator by the
// iterative QPE procedure.
// Compile and run with:
/// $ qcor IterativeQpeVqe.cpp
/// $ ./a.out
/// Ansatz to bring the state into an eigenvector state of the Hamiltonian.
/// This optimized ansatz was found by VQE.
__qpu__ void eigen_state_prep(qreg q) {
X(q[0]);
// Theta angle found by VQE.
double opt_theta = 0.297113;
auto exponent_op = X(0) * Y(1) - Y(0) * X(1);
exp_i_theta(q, opt_theta, exponent_op);
}
int main(int argc, char **argv) {
// Create Hamiltonian:
auto H = 5.907 - 2.1433 * X(0) * X(1) - 2.143 * Y(0) * Y(1) + 0.21829 * Z(0) -
6.125 * Z(1);
auto problemModel =
QuaSiMo::ModelFactory::createModel(eigen_state_prep, H, 2, 0);
// Instantiate an IQPE workflow
// NOTE: can turn off exp_i_theta compute-action-uncompute with {"cau-opt", false}
auto workflow =
QuaSiMo::getWorkflow("iqpe", {{"time-steps", 8}, {"iterations", 8}});
auto result = workflow->execute(problemModel);
const double phaseValue = result.get<double>("phase");
const double energy = result.get<double>("energy");
auto n_insts = result.get<std::vector<int>>("n-kernel-instructions");
std::cout << "Final phase = " << phaseValue << "\n";
// Expect: ~ -1.7 (due to limited bit precision)
std::cout << "Energy = " << energy << "\n";
return 0;
}
\ No newline at end of file
#include "qcor_qsim.hpp"
// Demonstrate qsim's QAOA workflow
// Compile and run with:
/// $ qcor -qpu qsim QaoaWorkflow.cpp
/// $ ./a.out
int main(int argc, char **argv) {
// Create the Deuteron Hamiltonian
auto H = 5.907 - 2.1433 * X(0) * X(1) - 2.143 * Y(0) * Y(1) + 0.21829 * Z(0) -
6.125 * Z(1);
auto problemModel = QuaSiMo::ModelFactory::createModel(H);
auto optimizer = createOptimizer("nlopt");
// Instantiate a QAOA workflow with the nlopt optimizer
// "steps" = the (p) param in QAOA algorithm.
auto workflow = QuaSiMo::getWorkflow("qaoa", {{"optimizer", optimizer}, {"steps", 8}});
// Result should contain the ground-state energy along with the optimal
// parameters.
auto result = workflow->execute(problemModel);
const auto energy = result.get<double>("energy");
std::cout << "Ground-state energy = " << energy << "\n";
return 0;
}
\ No newline at end of file
#include "qcor_qsim.hpp"
// High-level usage of Model Builder for time-dependent quantum simulation
// problem using Trotter method.
// Compile and run with:
/// $ qcor -qpu qpp TrotterTdWorkflow.cpp
/// $ ./a.out
int main(int argc, char **argv) {
// Define the time-dependent Hamiltonian and observable operator using the
// QCOR API Time-dependent Hamiltonian
QuaSiMo::TdObservable H = [](double t) {
// Parameters:
const double Jz = 2 * M_PI * 2.86265 * 1e-3;
const double epsilon = Jz; // Values: 0.2Jz, 0.5Jz, Jz, 5Jz
const double omega = 4.8 * 2 * M_PI * 1e-3;
return -Jz * Z(0) * Z(1) - Jz * Z(1) * Z(2) -
epsilon * std::cos(omega * t) * (X(0) + X(1) + X(2));
};
// Observable = average magnetization
auto observable = (1.0 / 3.0) * (Z(0) + Z(1) + Z(2));
// Example: build model and TD workflow for Fig. 2 of
// https://journals.aps.org/prb/pdf/10.1103/PhysRevB.101.184305
auto problemModel = QuaSiMo::ModelFactory::createModel(observable, H);
// Trotter step = 3fs, number of steps = 100 -> end time = 300fs
auto workflow = QuaSiMo::getWorkflow(
"td-evolution", {{"dt", 3.0}, {"steps", 100}});
// Result should contain the observable expectation value along Trotter steps.
auto result = workflow->execute(problemModel);
// Get the observable values (average magnetization)
const auto obsVals = result.get<std::vector<double>>("exp-vals");
// Print out for debugging:
std::cout << "<Magnetization>:\n";
for (const auto &val : obsVals) {
std::cout << val << "\n";
}
return 0;
}
#include "qcor_qsim.hpp"
// High-level usage of Model Builder for typical VQE problem.
// Compile and run with:
/// $ qcor -qpu qpp VqeWithAnsatzCircuit.cpp
/// $ ./a.out
// Define a fixed ansatz as a QCOR kernel
__qpu__ void ansatz(qreg q, double theta) {
X(q[0]);
auto exponent_op = X(0) * Y(1) - Y(0) * X(1);
exp_i_theta(q, theta, exponent_op);
}
int main(int argc, char **argv) {
// Create the Deuteron Hamiltonian
auto H = 5.907 - 2.1433 * X(0) * X(1) - 2.143 * Y(0) * Y(1) + 0.21829 * Z(0) -
6.125 * Z(1);
const auto num_qubits = 2;
const auto num_params = 1;
auto problemModel =
QuaSiMo::ModelFactory::createModel(ansatz, H, num_qubits, num_params);
auto optimizer = createOptimizer("nlopt");
// Instantiate a VQE workflow with the nlopt optimizer
auto workflow = QuaSiMo::getWorkflow("vqe", {{"optimizer", optimizer}});
// Result should contain the ground-state energy along with the optimal
// parameters.
auto result = workflow->execute(problemModel);
const auto energy = result.get<double>("energy");
std::cout << "Ground-state energy = " << energy << "\n";
return 0;
}
\ No newline at end of file
#include "qcor_qsim.hpp"
// qcor qite_deuteron.cpp -qpu qsim
__qpu__ void state_prep(qreg q) { X(q[0]); }
int main(int argc, char **argv) {
using namespace QuaSiMo;
// Create the Hamiltonian
auto observable = -2.1433 * X(0) * X(1) - 2.1433 * Y(0) * Y(1) +
.21829 * Z(0) - 6.125 * Z(1) + 5.907;
// We'll run with 5 steps and .1 step size
const int nbSteps = 5;
const double stepSize = 0.1;
// Create the model (2 qubits, 0 variational params in above state_prep)
// and QITE workflow
auto problemModel = ModelFactory::createModel(state_prep, &observable, 2, 0);
auto workflow =
getWorkflow("qite", {{"steps", nbSteps}, {"step-size", stepSize}});
// Execute
auto result = workflow->execute(problemModel);
// Get the final energy and iteration values
const auto energy = result.get<double>("energy");
const auto energyAtStep = result.get<std::vector<double>>("exp-vals");
std::cout << "QITE energy: [ ";
for (const auto &val : energyAtStep) {
std::cout << val << " ";
}
std::cout << "]\n";
std::cout << "Ground state energy: " << energy << "\n";
}
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment