Loading lib/qsim/base/kernel_evaluator.hpp 0 → 100644 +103 −0 Original line number Diff line number Diff line #pragma once #include "objective_function.hpp" #include "qcor_observable.hpp" #include "qcor_utils.hpp" #include "quantum_kernel.hpp" #include <functional> namespace qcor { class KernelFunctor { protected: // Quantum kernel function pointer, we will use // this to cast to kernel(composite, args...). // Doing it this way means we don't template KernelFunctor void *kernel_ptr; size_t nbParams; // CompositeInstruction representation of the // evaluated quantum kernel std::shared_ptr<CompositeInstruction> kernel; qreg q; public: KernelFunctor(qreg qReg) : q(qReg){}; qreg &getQreg() { return q; } size_t nParams() const { return nbParams; } virtual std::shared_ptr<CompositeInstruction> evaluate_kernel(const std::vector<double> &in_params) { return nullptr; } }; template <typename... KernelArgs> class KernelFunctorImpl : public KernelFunctor { private: using LocalArgsTranslator = ArgsTranslator<KernelArgs...>; std::shared_ptr<CompositeInstruction> create_new_composite() { // Create a composite that we can pass to the functor std::stringstream name_ss; name_ss << this << "_qkernel"; auto _kernel = qcor::__internal__::create_composite(name_ss.str()); return _kernel; } protected: std::shared_ptr<LocalArgsTranslator> args_translator; std::shared_ptr<KernelFunctor> helper; public: KernelFunctorImpl(void *k_ptr, std::shared_ptr<LocalArgsTranslator> translator, std::shared_ptr<KernelFunctor> obj_helper, qreg qReg, size_t nParams) : KernelFunctor(qReg) { kernel_ptr = k_ptr; args_translator = translator; helper = obj_helper; nbParams = nParams; } std::shared_ptr<CompositeInstruction> evaluate_kernel(const std::vector<double> &in_params) override { // Create a new CompositeInstruction, and create a tuple // from it so we can concatenate with the tuple args auto m_kernel = create_new_composite(); auto kernel_composite_tuple = std::make_tuple(m_kernel); // Translate x parameters into kernel args (represented as a tuple) auto translated_tuple = (*args_translator)(in_params); // Concatenate the two to make the args list (kernel, args...) auto concatenated = std::tuple_cat(kernel_composite_tuple, translated_tuple); auto kernel_functor = reinterpret_cast<void (*)( std::shared_ptr<CompositeInstruction>, KernelArgs...)>(kernel_ptr); // Call the functor with those arguments qcor::__internal__::evaluate_function_with_tuple_args(kernel_functor, concatenated); return m_kernel; } }; template <typename... Args> std::shared_ptr<KernelFunctor> createKernelFunctor( void (*quantum_kernel_functor)(std::shared_ptr<CompositeInstruction>, Args...), size_t nQubits, size_t nParams) { auto q = qalloc(nQubits); auto helper = std::make_shared<KernelFunctor>(q); __internal__::ArgsTranslatorAutoGenerator auto_gen; auto args_translator = auto_gen(helper->getQreg(), std::tuple<Args...>()); void *kernel_ptr = reinterpret_cast<void *>(quantum_kernel_functor); return std::make_shared<KernelFunctorImpl<Args...>>( kernel_ptr, args_translator, helper, q, nParams); } } // namespace qcor No newline at end of file lib/qsim/base/qcor_qsim.hpp +22 −12 Original line number Diff line number Diff line Loading @@ -2,11 +2,13 @@ #include "Accelerator.hpp" #include "AcceleratorBuffer.hpp" #include "Circuit.hpp" #include "kernel_evaluator.hpp" #include "qcor.hpp" #include "qcor_utils.hpp" #include "qrt.hpp" #include <memory> #include <xacc_internal_compiler.hpp> using CompositeInstruction = xacc::CompositeInstruction; using Accelerator = xacc::Accelerator; using Identifiable = xacc::Identifiable; Loading Loading @@ -61,7 +63,9 @@ using TdObservable = std::function<PauliOperator(double)>; // Capture a quantum chemistry problem. // TODO: generalize this to capture all potential use cases. struct QuatumSimulationModel { QuatumSimulationModel() : observable(nullptr) {} // Model name. std::string name; Loading @@ -73,7 +77,7 @@ struct QuatumSimulationModel { TdObservable hamiltonian; // QuatumSimulationModel also support a user-defined (fixed) ansatz. std::shared_ptr<CompositeInstruction> user_defined_ansatz; std::shared_ptr<KernelFunctor> user_defined_ansatz; }; // Generic model builder (factory) Loading @@ -100,7 +104,8 @@ public: // - format: key to look up module/plugin to digest the input data. // - data: model descriptions in plain-text format, e.g. load from file. // - params: extra parameters to pass to the parser/generator, // e.g. any transformations required in order to generate the Observable. // e.g. any transformations required in order to generate the // Observable. static QuatumSimulationModel createModel(const std::string &format, const std::string &data, const HeterogeneousMap ¶ms = {}); Loading @@ -111,9 +116,13 @@ public: static inline QuatumSimulationModel createModel( void (*quantum_kernel_functor)(std::shared_ptr<CompositeInstruction>, Args...), Observable *obs) { Observable *obs, size_t nbQubits, size_t nbParams) { auto kernel_functor = createKernelFunctor(quantum_kernel_functor, nbQubits, nbParams); QuatumSimulationModel model; std::cout << "HOWDY\n"; model.observable = obs; model.user_defined_ansatz = kernel_functor; return model; } }; Loading @@ -127,13 +136,14 @@ using QuatumSimulationResult = HeterogeneousMap; class QuatumSimulationWorkflow : public Identifiable { public: virtual bool initialize(const HeterogeneousMap ¶ms) = 0; virtual QuatumSimulationResult execute(const QuatumSimulationModel &model) = 0; virtual QuatumSimulationResult execute(const QuatumSimulationModel &model) = 0; protected: CostFunctionEvaluator *evaluator; }; // Get workflow by name: std::shared_ptr<QuatumSimulationWorkflow> getWorkflow(const std::string &name, const HeterogeneousMap &init_params); std::shared_ptr<QuatumSimulationWorkflow> getWorkflow(const std::string &name, const HeterogeneousMap &init_params); } // namespace qcor No newline at end of file lib/qsim/impls/qsim_impl.cpp +51 −0 Original line number Diff line number Diff line #include "qsim_impl.hpp" #include "xacc_service.hpp" #include "xacc.hpp" namespace qcor { Ansatz TrotterEvolution::create_ansatz(Observable *obs, Loading Loading @@ -81,6 +82,54 @@ TimeDependentWorkflow::execute(const QuatumSimulationModel &model) { return result; } bool VqeWorkflow::initialize(const HeterogeneousMap ¶ms) { const std::string DEFAULT_OPTIMIZER = "nlopt"; optimizer.reset(); if (params.pointerLikeExists<Optimizer>("optimizer")) { optimizer = xacc::as_shared_ptr(params.getPointerLike<Optimizer>("optimizer")); } else { optimizer = createOptimizer(DEFAULT_OPTIMIZER); } // VQE workflow requires an optimizer return (optimizer != nullptr); } QuatumSimulationResult VqeWorkflow::execute(const QuatumSimulationModel &model) { // If the model includes a concrete variational ansatz: if (model.user_defined_ansatz) { auto nParams = model.user_defined_ansatz->nParams(); auto vqe = xacc::getAlgorithm("vqe"); auto qpu = xacc::internal_compiler::get_qpu(); OptFunction f( [&](const std::vector<double> &x, std::vector<double> &dx) { auto kernel = model.user_defined_ansatz->evaluate_kernel(x); // std::cout << "Kernel:\n" << kernel->toString() << "\n"; auto success = vqe->initialize({{"ansatz", kernel}, {"accelerator", qpu}, {"observable", model.observable}}); if (!success) { xacc::error("QCOR VQE Workflow Error - could not initialize " "internal xacc vqe algorithm."); } auto tmp_child = qalloc(model.user_defined_ansatz->getQreg().size()); auto energy = vqe->execute(xacc::as_shared_ptr(tmp_child.results()), {})[0]; return energy; }, nParams); auto result = optimizer->optimize(f); std::cout << "Min energy = " << result.first << "\n"; return {{"energy", result.first}, {"opt-params", result.second}}; } // TODO: support ansatz generation methods: return {}; } std::shared_ptr<QuatumSimulationWorkflow> getWorkflow(const std::string &name, const HeterogeneousMap &init_params) { auto qsim_workflow = xacc::getService<QuatumSimulationWorkflow>(name); Loading @@ -105,6 +154,8 @@ public: void Start(BundleContext context) { context.RegisterService<qcor::QuatumSimulationWorkflow>( std::make_shared<qcor::TimeDependentWorkflow>()); context.RegisterService<qcor::QuatumSimulationWorkflow>( std::make_shared<qcor::VqeWorkflow>()); } void Stop(BundleContext) {} Loading lib/qsim/impls/qsim_impl.hpp +1 −1 Original line number Diff line number Diff line Loading @@ -50,7 +50,7 @@ public: virtual const std::string name() const override { return "vqe"; } virtual const std::string description() const override { return ""; } private: Optimizer *optimizer; std::shared_ptr<Optimizer> optimizer; }; Loading lib/qsim/impls/tests/QsimQcorKernel.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -14,7 +14,7 @@ int main(int argc, char **argv) { auto H = createObservable( "5.907 - 2.1433 X0X1 - 2.1433 Y0Y1 + .21829 Z0 - 6.125 Z1"); auto problemModel = ModelBuilder::createModel(ansatz, H.get()); auto problemModel = ModelBuilder::createModel(ansatz, H.get(), q.size(), 1); auto optimizer = createOptimizer("nlopt"); auto workflow = qcor::getWorkflow("vqe", {{"optimizer", optimizer}}); Loading Loading
lib/qsim/base/kernel_evaluator.hpp 0 → 100644 +103 −0 Original line number Diff line number Diff line #pragma once #include "objective_function.hpp" #include "qcor_observable.hpp" #include "qcor_utils.hpp" #include "quantum_kernel.hpp" #include <functional> namespace qcor { class KernelFunctor { protected: // Quantum kernel function pointer, we will use // this to cast to kernel(composite, args...). // Doing it this way means we don't template KernelFunctor void *kernel_ptr; size_t nbParams; // CompositeInstruction representation of the // evaluated quantum kernel std::shared_ptr<CompositeInstruction> kernel; qreg q; public: KernelFunctor(qreg qReg) : q(qReg){}; qreg &getQreg() { return q; } size_t nParams() const { return nbParams; } virtual std::shared_ptr<CompositeInstruction> evaluate_kernel(const std::vector<double> &in_params) { return nullptr; } }; template <typename... KernelArgs> class KernelFunctorImpl : public KernelFunctor { private: using LocalArgsTranslator = ArgsTranslator<KernelArgs...>; std::shared_ptr<CompositeInstruction> create_new_composite() { // Create a composite that we can pass to the functor std::stringstream name_ss; name_ss << this << "_qkernel"; auto _kernel = qcor::__internal__::create_composite(name_ss.str()); return _kernel; } protected: std::shared_ptr<LocalArgsTranslator> args_translator; std::shared_ptr<KernelFunctor> helper; public: KernelFunctorImpl(void *k_ptr, std::shared_ptr<LocalArgsTranslator> translator, std::shared_ptr<KernelFunctor> obj_helper, qreg qReg, size_t nParams) : KernelFunctor(qReg) { kernel_ptr = k_ptr; args_translator = translator; helper = obj_helper; nbParams = nParams; } std::shared_ptr<CompositeInstruction> evaluate_kernel(const std::vector<double> &in_params) override { // Create a new CompositeInstruction, and create a tuple // from it so we can concatenate with the tuple args auto m_kernel = create_new_composite(); auto kernel_composite_tuple = std::make_tuple(m_kernel); // Translate x parameters into kernel args (represented as a tuple) auto translated_tuple = (*args_translator)(in_params); // Concatenate the two to make the args list (kernel, args...) auto concatenated = std::tuple_cat(kernel_composite_tuple, translated_tuple); auto kernel_functor = reinterpret_cast<void (*)( std::shared_ptr<CompositeInstruction>, KernelArgs...)>(kernel_ptr); // Call the functor with those arguments qcor::__internal__::evaluate_function_with_tuple_args(kernel_functor, concatenated); return m_kernel; } }; template <typename... Args> std::shared_ptr<KernelFunctor> createKernelFunctor( void (*quantum_kernel_functor)(std::shared_ptr<CompositeInstruction>, Args...), size_t nQubits, size_t nParams) { auto q = qalloc(nQubits); auto helper = std::make_shared<KernelFunctor>(q); __internal__::ArgsTranslatorAutoGenerator auto_gen; auto args_translator = auto_gen(helper->getQreg(), std::tuple<Args...>()); void *kernel_ptr = reinterpret_cast<void *>(quantum_kernel_functor); return std::make_shared<KernelFunctorImpl<Args...>>( kernel_ptr, args_translator, helper, q, nParams); } } // namespace qcor No newline at end of file
lib/qsim/base/qcor_qsim.hpp +22 −12 Original line number Diff line number Diff line Loading @@ -2,11 +2,13 @@ #include "Accelerator.hpp" #include "AcceleratorBuffer.hpp" #include "Circuit.hpp" #include "kernel_evaluator.hpp" #include "qcor.hpp" #include "qcor_utils.hpp" #include "qrt.hpp" #include <memory> #include <xacc_internal_compiler.hpp> using CompositeInstruction = xacc::CompositeInstruction; using Accelerator = xacc::Accelerator; using Identifiable = xacc::Identifiable; Loading Loading @@ -61,7 +63,9 @@ using TdObservable = std::function<PauliOperator(double)>; // Capture a quantum chemistry problem. // TODO: generalize this to capture all potential use cases. struct QuatumSimulationModel { QuatumSimulationModel() : observable(nullptr) {} // Model name. std::string name; Loading @@ -73,7 +77,7 @@ struct QuatumSimulationModel { TdObservable hamiltonian; // QuatumSimulationModel also support a user-defined (fixed) ansatz. std::shared_ptr<CompositeInstruction> user_defined_ansatz; std::shared_ptr<KernelFunctor> user_defined_ansatz; }; // Generic model builder (factory) Loading @@ -100,7 +104,8 @@ public: // - format: key to look up module/plugin to digest the input data. // - data: model descriptions in plain-text format, e.g. load from file. // - params: extra parameters to pass to the parser/generator, // e.g. any transformations required in order to generate the Observable. // e.g. any transformations required in order to generate the // Observable. static QuatumSimulationModel createModel(const std::string &format, const std::string &data, const HeterogeneousMap ¶ms = {}); Loading @@ -111,9 +116,13 @@ public: static inline QuatumSimulationModel createModel( void (*quantum_kernel_functor)(std::shared_ptr<CompositeInstruction>, Args...), Observable *obs) { Observable *obs, size_t nbQubits, size_t nbParams) { auto kernel_functor = createKernelFunctor(quantum_kernel_functor, nbQubits, nbParams); QuatumSimulationModel model; std::cout << "HOWDY\n"; model.observable = obs; model.user_defined_ansatz = kernel_functor; return model; } }; Loading @@ -127,13 +136,14 @@ using QuatumSimulationResult = HeterogeneousMap; class QuatumSimulationWorkflow : public Identifiable { public: virtual bool initialize(const HeterogeneousMap ¶ms) = 0; virtual QuatumSimulationResult execute(const QuatumSimulationModel &model) = 0; virtual QuatumSimulationResult execute(const QuatumSimulationModel &model) = 0; protected: CostFunctionEvaluator *evaluator; }; // Get workflow by name: std::shared_ptr<QuatumSimulationWorkflow> getWorkflow(const std::string &name, const HeterogeneousMap &init_params); std::shared_ptr<QuatumSimulationWorkflow> getWorkflow(const std::string &name, const HeterogeneousMap &init_params); } // namespace qcor No newline at end of file
lib/qsim/impls/qsim_impl.cpp +51 −0 Original line number Diff line number Diff line #include "qsim_impl.hpp" #include "xacc_service.hpp" #include "xacc.hpp" namespace qcor { Ansatz TrotterEvolution::create_ansatz(Observable *obs, Loading Loading @@ -81,6 +82,54 @@ TimeDependentWorkflow::execute(const QuatumSimulationModel &model) { return result; } bool VqeWorkflow::initialize(const HeterogeneousMap ¶ms) { const std::string DEFAULT_OPTIMIZER = "nlopt"; optimizer.reset(); if (params.pointerLikeExists<Optimizer>("optimizer")) { optimizer = xacc::as_shared_ptr(params.getPointerLike<Optimizer>("optimizer")); } else { optimizer = createOptimizer(DEFAULT_OPTIMIZER); } // VQE workflow requires an optimizer return (optimizer != nullptr); } QuatumSimulationResult VqeWorkflow::execute(const QuatumSimulationModel &model) { // If the model includes a concrete variational ansatz: if (model.user_defined_ansatz) { auto nParams = model.user_defined_ansatz->nParams(); auto vqe = xacc::getAlgorithm("vqe"); auto qpu = xacc::internal_compiler::get_qpu(); OptFunction f( [&](const std::vector<double> &x, std::vector<double> &dx) { auto kernel = model.user_defined_ansatz->evaluate_kernel(x); // std::cout << "Kernel:\n" << kernel->toString() << "\n"; auto success = vqe->initialize({{"ansatz", kernel}, {"accelerator", qpu}, {"observable", model.observable}}); if (!success) { xacc::error("QCOR VQE Workflow Error - could not initialize " "internal xacc vqe algorithm."); } auto tmp_child = qalloc(model.user_defined_ansatz->getQreg().size()); auto energy = vqe->execute(xacc::as_shared_ptr(tmp_child.results()), {})[0]; return energy; }, nParams); auto result = optimizer->optimize(f); std::cout << "Min energy = " << result.first << "\n"; return {{"energy", result.first}, {"opt-params", result.second}}; } // TODO: support ansatz generation methods: return {}; } std::shared_ptr<QuatumSimulationWorkflow> getWorkflow(const std::string &name, const HeterogeneousMap &init_params) { auto qsim_workflow = xacc::getService<QuatumSimulationWorkflow>(name); Loading @@ -105,6 +154,8 @@ public: void Start(BundleContext context) { context.RegisterService<qcor::QuatumSimulationWorkflow>( std::make_shared<qcor::TimeDependentWorkflow>()); context.RegisterService<qcor::QuatumSimulationWorkflow>( std::make_shared<qcor::VqeWorkflow>()); } void Stop(BundleContext) {} Loading
lib/qsim/impls/qsim_impl.hpp +1 −1 Original line number Diff line number Diff line Loading @@ -50,7 +50,7 @@ public: virtual const std::string name() const override { return "vqe"; } virtual const std::string description() const override { return ""; } private: Optimizer *optimizer; std::shared_ptr<Optimizer> optimizer; }; Loading
lib/qsim/impls/tests/QsimQcorKernel.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -14,7 +14,7 @@ int main(int argc, char **argv) { auto H = createObservable( "5.907 - 2.1433 X0X1 - 2.1433 Y0Y1 + .21829 Z0 - 6.125 Z1"); auto problemModel = ModelBuilder::createModel(ansatz, H.get()); auto problemModel = ModelBuilder::createModel(ansatz, H.get(), q.size(), 1); auto optimizer = createOptimizer("nlopt"); auto workflow = qcor::getWorkflow("vqe", {{"optimizer", optimizer}}); Loading