Loading python/py-qcor.cpp +101 −0 Original line number Diff line number Diff line Loading @@ -93,6 +93,69 @@ xacc::HeterogeneousMap heterogeneousMapConvert( return result; } std::shared_ptr<qcor::Observable> convertToPauliOperator(py::object op) { if (py::hasattr(op, "terms")) { // this is from openfermion if (py::hasattr(op, "is_two_body_number_conserving")) { // This is a fermion Operator auto terms = op.attr("terms"); // terms is a list of tuples std::stringstream ss; int i = 0; for (auto term : terms) { auto term_tuple = term.cast<py::tuple>(); if (!term_tuple.empty()) { ss << terms[term].cast<std::complex<double>>() << " "; for (auto element : term_tuple) { auto element_pair = element.cast<std::pair<int, int>>(); ss << element_pair.first << (element_pair.second ? "^" : "") << " "; } } else { // this was identity ss << terms[term].cast<double>(); } i++; if (i != py::len(terms)) { ss << " + "; } } auto obs_tmp = qcor::createOperator("fermion", ss.str()); return qcor::operatorTransform("jw", obs_tmp); } else { // this is a qubit operator auto terms = op.attr("terms"); // terms is a list of tuples std::stringstream ss; int i = 0; for (auto term : terms) { auto term_tuple = term.cast<py::tuple>(); if (!term_tuple.empty()) { ss << terms[term].cast<std::complex<double>>() << " "; for (auto element : term_tuple) { auto element_pair = element.cast<std::pair<int, std::string>>(); ss << element_pair.second << element_pair.first << " "; } } else { // this was identity ss << terms[term].cast<double>(); } i++; if (i != py::len(terms)) { ss << " + "; } } return qcor::createOperator(ss.str()); } } else { // throw an error qcor::error( "Invalid python object passed as a QCOR Operator/Observable. " "Currently, we only accept OpenFermion datastructures."); } } } // namespace namespace qcor { Loading Loading @@ -143,6 +206,31 @@ class PyObjectiveFunction : public qcor::ObjectiveFunction { qjit.write_cache(); } PyObjectiveFunction(py::object q, std::shared_ptr<qcor::Observable> &qq, const int n_dim, const std::string &helper_name, xacc::HeterogeneousMap opts = {}) : py_kernel(q) { // Set the OptFunction dimensions _dim = n_dim; // Set the helper objective helper = xacc::getService<qcor::ObjectiveFunction>(helper_name); // Store the observable pointer and give it to the helper observable = qq; options = opts; options.insert("observable", observable); helper->set_options(options); helper->update_observable(observable); // Extract the QJIT source code auto src = py_kernel.attr("get_internal_src")().cast<std::string>(); // QJIT compile // this will be fast if already done, and we just do it once qjit.jit_compile(src, true); qjit.write_cache(); } // Evaluate this ObjectiveFunction at the dictionary of kernel args, // return the scalar value double operator()(const KernelArgDict args, std::vector<double> &dx) { Loading Loading @@ -368,6 +456,19 @@ PYBIND11_MODULE(_pyqcor, m) { return obj; }, ""); m.def( "createObjectiveFunction", [](py::object kernel, py::object &py_obs, const int n_params, PyHeterogeneousMap &options) { auto nativeHetMap = heterogeneousMapConvert(options); auto obs = convertToPauliOperator(py_obs); auto q = ::qalloc(obs->nBits()); std::shared_ptr<qcor::ObjectiveFunction> obj = std::make_shared<qcor::PyObjectiveFunction>(kernel, obs, n_params, "vqe", nativeHetMap); return obj; }, ""); m.def( "createOperator", Loading python/tests/test_openfermion_integration.py 0 → 100644 +46 −0 Original line number Diff line number Diff line import unittest from qcor import * try: from openfermion.ops import FermionOperator as FOp from openfermion.ops import QubitOperator as QOp from openfermion.transforms import reverse_jordan_wigner, jordan_wigner class TestOpenFermion(unittest.TestCase): def test_simple_fermion(self): # Create Operator as OpenFermion FermionOperator H = FOp('', 0.0002899) + FOp('0^ 0', -.43658) + \ FOp('1 0^', 4.2866) + FOp('1^ 0', -4.2866) + FOp('1^ 1', 12.25) @qjit def ansatz(q: qreg, theta: float): X(q[0]) Ry(q[1], theta) CX(q[1], q[0]) n_params = 1 obj = createObjectiveFunction(ansatz, H, n_params, {'gradient-strategy':'parameter-shift'}) optimizer = createOptimizer('nlopt', {'nlopt-optimizer':'l-bfgs'}) results = optimizer.optimize(obj) self.assertAlmostEqual(results[0], -1.74, places=1) def test_simple_qubit(self): # Create Operator as OpenFermion FermionOperator H = QOp('', 5.907) + QOp('Y0 Y1', -2.1433) + \ QOp('X0 X1', -2.1433) + QOp('Z0', .21829) + QOp('Z1', -6.125) @qjit def ansatz(q: qreg, theta: float): X(q[0]) Ry(q[1], theta) CX(q[1], q[0]) n_params = 1 obj = createObjectiveFunction(ansatz, H, n_params, {'gradient-strategy':'parameter-shift'}) optimizer = createOptimizer('nlopt', {'nlopt-optimizer':'l-bfgs'}) results = optimizer.optimize(obj) self.assertAlmostEqual(results[0], -1.74, places=1) except: pass if __name__ == '__main__': unittest.main() No newline at end of file python/tests/test_qsim.py +4 −5 Original line number Diff line number Diff line import unittest import unittest, math from qcor import * import numpy as np class TestWorkflows(unittest.TestCase): def test_td_workflow(self): # Time-dependent Hamiltonian: # Returns the Pauli operators at a time point. def td_hamiltonian(t): Jz = 2 * np.pi * 2.86265 * 1e-3 Jz = 2 * math.pi * 2.86265 * 1e-3 epsilon = Jz omega = 4.8 * 2 * np.pi * 1e-3 return -Jz * Z(0) * Z(1) - Jz * Z(1) * Z(2) + (-epsilon * np.cos(omega * t)) * (X(0) + X(1) + X(2)) omega = 4.8 * 2 * math.pi * 1e-3 return -Jz * Z(0) * Z(1) - Jz * Z(1) * Z(2) + (-epsilon * math.cos(omega * t)) * (X(0) + X(1) + X(2)) # Observable = average magnetization observable = (1.0 / 3.0) * (Z(0) + Z(1) + Z(2)) Loading runtime/observable/qcor_observable.cpp +11 −0 Original line number Diff line number Diff line #include "qcor_observable.hpp" #include "ObservableTransform.hpp" #include "xacc.hpp" #include "xacc_quantum_gate_api.hpp" #include "xacc_service.hpp" Loading Loading @@ -85,6 +86,16 @@ std::shared_ptr<Observable> createOperator(const std::string &name, return createObservable(name, options); } std::shared_ptr<Observable> operatorTransform(const std::string &type, qcor::Observable &op) { // return xacc::getService<xacc::ObservableTransform>(type)->transform( // xacc::as_shared_ptr(*&op)); } std::shared_ptr<Observable> operatorTransform(const std::string &type, std::shared_ptr<Observable> op) { return xacc::getService<xacc::ObservableTransform>(type)->transform(op); } namespace __internal__ { std::vector<std::shared_ptr<xacc::CompositeInstruction>> observe( std::shared_ptr<xacc::Observable> obs, Loading runtime/observable/qcor_observable.hpp +2 −0 Original line number Diff line number Diff line Loading @@ -107,5 +107,7 @@ std::shared_ptr<Observable> createOperator(const std::string& name, const std::s std::shared_ptr<Observable> createOperator(const std::string &name, HeterogeneousMap&& options); std::shared_ptr<Observable> createOperator(const std::string &name, HeterogeneousMap& options); std::shared_ptr<Observable> operatorTransform(const std::string& type, qcor::Observable& op); std::shared_ptr<Observable> operatorTransform(const std::string& type, std::shared_ptr<Observable> op); } // namespace qcor No newline at end of file Loading
python/py-qcor.cpp +101 −0 Original line number Diff line number Diff line Loading @@ -93,6 +93,69 @@ xacc::HeterogeneousMap heterogeneousMapConvert( return result; } std::shared_ptr<qcor::Observable> convertToPauliOperator(py::object op) { if (py::hasattr(op, "terms")) { // this is from openfermion if (py::hasattr(op, "is_two_body_number_conserving")) { // This is a fermion Operator auto terms = op.attr("terms"); // terms is a list of tuples std::stringstream ss; int i = 0; for (auto term : terms) { auto term_tuple = term.cast<py::tuple>(); if (!term_tuple.empty()) { ss << terms[term].cast<std::complex<double>>() << " "; for (auto element : term_tuple) { auto element_pair = element.cast<std::pair<int, int>>(); ss << element_pair.first << (element_pair.second ? "^" : "") << " "; } } else { // this was identity ss << terms[term].cast<double>(); } i++; if (i != py::len(terms)) { ss << " + "; } } auto obs_tmp = qcor::createOperator("fermion", ss.str()); return qcor::operatorTransform("jw", obs_tmp); } else { // this is a qubit operator auto terms = op.attr("terms"); // terms is a list of tuples std::stringstream ss; int i = 0; for (auto term : terms) { auto term_tuple = term.cast<py::tuple>(); if (!term_tuple.empty()) { ss << terms[term].cast<std::complex<double>>() << " "; for (auto element : term_tuple) { auto element_pair = element.cast<std::pair<int, std::string>>(); ss << element_pair.second << element_pair.first << " "; } } else { // this was identity ss << terms[term].cast<double>(); } i++; if (i != py::len(terms)) { ss << " + "; } } return qcor::createOperator(ss.str()); } } else { // throw an error qcor::error( "Invalid python object passed as a QCOR Operator/Observable. " "Currently, we only accept OpenFermion datastructures."); } } } // namespace namespace qcor { Loading Loading @@ -143,6 +206,31 @@ class PyObjectiveFunction : public qcor::ObjectiveFunction { qjit.write_cache(); } PyObjectiveFunction(py::object q, std::shared_ptr<qcor::Observable> &qq, const int n_dim, const std::string &helper_name, xacc::HeterogeneousMap opts = {}) : py_kernel(q) { // Set the OptFunction dimensions _dim = n_dim; // Set the helper objective helper = xacc::getService<qcor::ObjectiveFunction>(helper_name); // Store the observable pointer and give it to the helper observable = qq; options = opts; options.insert("observable", observable); helper->set_options(options); helper->update_observable(observable); // Extract the QJIT source code auto src = py_kernel.attr("get_internal_src")().cast<std::string>(); // QJIT compile // this will be fast if already done, and we just do it once qjit.jit_compile(src, true); qjit.write_cache(); } // Evaluate this ObjectiveFunction at the dictionary of kernel args, // return the scalar value double operator()(const KernelArgDict args, std::vector<double> &dx) { Loading Loading @@ -368,6 +456,19 @@ PYBIND11_MODULE(_pyqcor, m) { return obj; }, ""); m.def( "createObjectiveFunction", [](py::object kernel, py::object &py_obs, const int n_params, PyHeterogeneousMap &options) { auto nativeHetMap = heterogeneousMapConvert(options); auto obs = convertToPauliOperator(py_obs); auto q = ::qalloc(obs->nBits()); std::shared_ptr<qcor::ObjectiveFunction> obj = std::make_shared<qcor::PyObjectiveFunction>(kernel, obs, n_params, "vqe", nativeHetMap); return obj; }, ""); m.def( "createOperator", Loading
python/tests/test_openfermion_integration.py 0 → 100644 +46 −0 Original line number Diff line number Diff line import unittest from qcor import * try: from openfermion.ops import FermionOperator as FOp from openfermion.ops import QubitOperator as QOp from openfermion.transforms import reverse_jordan_wigner, jordan_wigner class TestOpenFermion(unittest.TestCase): def test_simple_fermion(self): # Create Operator as OpenFermion FermionOperator H = FOp('', 0.0002899) + FOp('0^ 0', -.43658) + \ FOp('1 0^', 4.2866) + FOp('1^ 0', -4.2866) + FOp('1^ 1', 12.25) @qjit def ansatz(q: qreg, theta: float): X(q[0]) Ry(q[1], theta) CX(q[1], q[0]) n_params = 1 obj = createObjectiveFunction(ansatz, H, n_params, {'gradient-strategy':'parameter-shift'}) optimizer = createOptimizer('nlopt', {'nlopt-optimizer':'l-bfgs'}) results = optimizer.optimize(obj) self.assertAlmostEqual(results[0], -1.74, places=1) def test_simple_qubit(self): # Create Operator as OpenFermion FermionOperator H = QOp('', 5.907) + QOp('Y0 Y1', -2.1433) + \ QOp('X0 X1', -2.1433) + QOp('Z0', .21829) + QOp('Z1', -6.125) @qjit def ansatz(q: qreg, theta: float): X(q[0]) Ry(q[1], theta) CX(q[1], q[0]) n_params = 1 obj = createObjectiveFunction(ansatz, H, n_params, {'gradient-strategy':'parameter-shift'}) optimizer = createOptimizer('nlopt', {'nlopt-optimizer':'l-bfgs'}) results = optimizer.optimize(obj) self.assertAlmostEqual(results[0], -1.74, places=1) except: pass if __name__ == '__main__': unittest.main() No newline at end of file
python/tests/test_qsim.py +4 −5 Original line number Diff line number Diff line import unittest import unittest, math from qcor import * import numpy as np class TestWorkflows(unittest.TestCase): def test_td_workflow(self): # Time-dependent Hamiltonian: # Returns the Pauli operators at a time point. def td_hamiltonian(t): Jz = 2 * np.pi * 2.86265 * 1e-3 Jz = 2 * math.pi * 2.86265 * 1e-3 epsilon = Jz omega = 4.8 * 2 * np.pi * 1e-3 return -Jz * Z(0) * Z(1) - Jz * Z(1) * Z(2) + (-epsilon * np.cos(omega * t)) * (X(0) + X(1) + X(2)) omega = 4.8 * 2 * math.pi * 1e-3 return -Jz * Z(0) * Z(1) - Jz * Z(1) * Z(2) + (-epsilon * math.cos(omega * t)) * (X(0) + X(1) + X(2)) # Observable = average magnetization observable = (1.0 / 3.0) * (Z(0) + Z(1) + Z(2)) Loading
runtime/observable/qcor_observable.cpp +11 −0 Original line number Diff line number Diff line #include "qcor_observable.hpp" #include "ObservableTransform.hpp" #include "xacc.hpp" #include "xacc_quantum_gate_api.hpp" #include "xacc_service.hpp" Loading Loading @@ -85,6 +86,16 @@ std::shared_ptr<Observable> createOperator(const std::string &name, return createObservable(name, options); } std::shared_ptr<Observable> operatorTransform(const std::string &type, qcor::Observable &op) { // return xacc::getService<xacc::ObservableTransform>(type)->transform( // xacc::as_shared_ptr(*&op)); } std::shared_ptr<Observable> operatorTransform(const std::string &type, std::shared_ptr<Observable> op) { return xacc::getService<xacc::ObservableTransform>(type)->transform(op); } namespace __internal__ { std::vector<std::shared_ptr<xacc::CompositeInstruction>> observe( std::shared_ptr<xacc::Observable> obs, Loading
runtime/observable/qcor_observable.hpp +2 −0 Original line number Diff line number Diff line Loading @@ -107,5 +107,7 @@ std::shared_ptr<Observable> createOperator(const std::string& name, const std::s std::shared_ptr<Observable> createOperator(const std::string &name, HeterogeneousMap&& options); std::shared_ptr<Observable> createOperator(const std::string &name, HeterogeneousMap& options); std::shared_ptr<Observable> operatorTransform(const std::string& type, qcor::Observable& op); std::shared_ptr<Observable> operatorTransform(const std::string& type, std::shared_ptr<Observable> op); } // namespace qcor No newline at end of file