Loading python/py-qcor.cpp +42 −0 Original line number Diff line number Diff line Loading @@ -50,10 +50,16 @@ struct visit_helper<mpark::variant> { namespace { // We only allow certain argument types for quantum kernel functors in python // Here we enumerate them as a Variant using AllowedKernelArgTypes = xacc::Variant<bool, int, double, std::string, xacc::internal_compiler::qreg, std::vector<double>>; // We will take as input a mapping of arg variable names to the argument itself. using KernelArgDict = std::map<std::string, AllowedKernelArgTypes>; // Utility for mapping KernelArgDict to a HeterogeneousMap class KernelArgDictToHeterogeneousMap { protected: xacc::HeterogeneousMap &m; Loading Loading @@ -90,6 +96,16 @@ xacc::HeterogeneousMap heterogeneousMapConvert( namespace qcor { // PyObjectiveFunction implements ObjectiveFunction to // enable the utility of pythonic quantum kernels with the // existing qcor ObjectiveFunction infrastructure. This class // keeps track of the quantum kernel as a py::object, which it uses // in tandem with the QCOR QJIT engine to create an executable // functor representation of the quantum code at runtime. It exposes // the ObjectiveFunction operator()() overloads to map vector<double> // x to the correct pythonic argument structure. It delegates to the // usual helper ObjectiveFunction (like vqe) for execution of the // actual pre-, execution, and post-processing. class PyObjectiveFunction : public qcor::ObjectiveFunction { protected: py::object py_kernel; Loading @@ -103,28 +119,46 @@ class PyObjectiveFunction : public qcor::ObjectiveFunction { PyObjectiveFunction(py::object q, qcor::PauliOperator &qq, const int n_dim, const std::string &helper_name) : 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 = xacc::as_shared_ptr(&qq); 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); } // Evaluate this ObjectiveFunction at the dictionary of kernel args, // return the scalar value double operator()(const KernelArgDict args) { // Map the kernel args to a hetmap xacc::HeterogeneousMap m; for (auto &item : args) { KernelArgDictToHeterogeneousMap vis(m, item.first); mpark::visit(vis, item.second); } // Get the kernel as a CompositeInstruction auto kernel_name = py_kernel.attr("kernel_name")().cast<std::string>(); kernel = qjit.extract_composite_with_hetmap(kernel_name, m); helper->update_kernel(kernel); // FIXME, handle gradients std::vector<double> dx; return (*helper)(qreg, dx); } // Evaluate this ObjectiveFunction at the parameters x double operator()(const std::vector<double> &x, std::vector<double> &dx) override { current_iterate_parameters = x; Loading @@ -136,6 +170,7 @@ class PyObjectiveFunction : public qcor::ObjectiveFunction { // args will be a dictionary, arg_name to arg return operator()(args); } virtual double operator()(xacc::internal_compiler::qreg &qreg, std::vector<double> &dx) { throw std::bad_function_call(); Loading @@ -143,6 +178,11 @@ class PyObjectiveFunction : public qcor::ObjectiveFunction { } }; // PyKernelFunctor is a subtype of KernelFunctor from the qsim library // that returns a CompositeInstruction representation of a pythonic // quantum kernel given a vector of parameters x. This will // leverage the QJIT infrastructure to create executable functor // representation of the python kernel. class PyKernelFunctor : public qcor::KernelFunctor { protected: py::object py_kernel; Loading @@ -158,6 +198,8 @@ class PyKernelFunctor : public qcor::KernelFunctor { qjit.jit_compile(src, true); } // Delegate to QJIT to create a CompositeInstruction representation // of the pythonic quantum kernel. std::shared_ptr<xacc::CompositeInstruction> evaluate_kernel( const std::vector<double> &x) override { // Translate x into kernel args Loading Loading
python/py-qcor.cpp +42 −0 Original line number Diff line number Diff line Loading @@ -50,10 +50,16 @@ struct visit_helper<mpark::variant> { namespace { // We only allow certain argument types for quantum kernel functors in python // Here we enumerate them as a Variant using AllowedKernelArgTypes = xacc::Variant<bool, int, double, std::string, xacc::internal_compiler::qreg, std::vector<double>>; // We will take as input a mapping of arg variable names to the argument itself. using KernelArgDict = std::map<std::string, AllowedKernelArgTypes>; // Utility for mapping KernelArgDict to a HeterogeneousMap class KernelArgDictToHeterogeneousMap { protected: xacc::HeterogeneousMap &m; Loading Loading @@ -90,6 +96,16 @@ xacc::HeterogeneousMap heterogeneousMapConvert( namespace qcor { // PyObjectiveFunction implements ObjectiveFunction to // enable the utility of pythonic quantum kernels with the // existing qcor ObjectiveFunction infrastructure. This class // keeps track of the quantum kernel as a py::object, which it uses // in tandem with the QCOR QJIT engine to create an executable // functor representation of the quantum code at runtime. It exposes // the ObjectiveFunction operator()() overloads to map vector<double> // x to the correct pythonic argument structure. It delegates to the // usual helper ObjectiveFunction (like vqe) for execution of the // actual pre-, execution, and post-processing. class PyObjectiveFunction : public qcor::ObjectiveFunction { protected: py::object py_kernel; Loading @@ -103,28 +119,46 @@ class PyObjectiveFunction : public qcor::ObjectiveFunction { PyObjectiveFunction(py::object q, qcor::PauliOperator &qq, const int n_dim, const std::string &helper_name) : 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 = xacc::as_shared_ptr(&qq); 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); } // Evaluate this ObjectiveFunction at the dictionary of kernel args, // return the scalar value double operator()(const KernelArgDict args) { // Map the kernel args to a hetmap xacc::HeterogeneousMap m; for (auto &item : args) { KernelArgDictToHeterogeneousMap vis(m, item.first); mpark::visit(vis, item.second); } // Get the kernel as a CompositeInstruction auto kernel_name = py_kernel.attr("kernel_name")().cast<std::string>(); kernel = qjit.extract_composite_with_hetmap(kernel_name, m); helper->update_kernel(kernel); // FIXME, handle gradients std::vector<double> dx; return (*helper)(qreg, dx); } // Evaluate this ObjectiveFunction at the parameters x double operator()(const std::vector<double> &x, std::vector<double> &dx) override { current_iterate_parameters = x; Loading @@ -136,6 +170,7 @@ class PyObjectiveFunction : public qcor::ObjectiveFunction { // args will be a dictionary, arg_name to arg return operator()(args); } virtual double operator()(xacc::internal_compiler::qreg &qreg, std::vector<double> &dx) { throw std::bad_function_call(); Loading @@ -143,6 +178,11 @@ class PyObjectiveFunction : public qcor::ObjectiveFunction { } }; // PyKernelFunctor is a subtype of KernelFunctor from the qsim library // that returns a CompositeInstruction representation of a pythonic // quantum kernel given a vector of parameters x. This will // leverage the QJIT infrastructure to create executable functor // representation of the python kernel. class PyKernelFunctor : public qcor::KernelFunctor { protected: py::object py_kernel; Loading @@ -158,6 +198,8 @@ class PyKernelFunctor : public qcor::KernelFunctor { qjit.jit_compile(src, true); } // Delegate to QJIT to create a CompositeInstruction representation // of the pythonic quantum kernel. std::shared_ptr<xacc::CompositeInstruction> evaluate_kernel( const std::vector<double> &x) override { // Translate x into kernel args Loading