xacc-py.cpp 15.5 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
/*******************************************************************************
 * Copyright (c) 2018 UT-Battelle, LLC.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * and Eclipse Distribution License v1.0 which accompanies this
 * distribution. The Eclipse Public License is available at
 * http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License
 * is available at https://eclipse.org/org/documents/edl-v10.php
 *
 * Contributors:
 *   Alexander J. McCaskey - initial API and implementation
 *******************************************************************************/
13
#include "XACC.hpp"
14
15
#include "IRGenerator.hpp"

16
#include <pybind11/complex.h>
17
#include <pybind11/numpy.h>
18
19
20
21
22
23
24
25
#include <pybind11/stl.h>
#include <pybind11/stl_bind.h>
#include <pybind11/eigen.h>
#include <pybind11/iostream.h>
#include <pybind11/operators.h>

#include "GateInstruction.hpp"
#include "GateFunction.hpp"
26
#include "GateIR.hpp"
27
28
29
30
31

namespace py = pybind11;
using namespace xacc;
using namespace xacc::quantum;

32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// `boost::variant` as an example -- can be any `std::variant`-like container
namespace pybind11 { namespace detail {
    template <typename... Ts>
    struct type_caster<boost::variant<Ts...>> : variant_caster<boost::variant<Ts...>> {};

    // Specifies the function used to visit the variant -- `apply_visitor` instead of `visit`
    template <>
    struct visit_helper<boost::variant> {
        template <typename... Args>
        static auto call(Args &&...args) -> decltype(boost::apply_visitor(args...)) {
            return boost::apply_visitor(args...);
        }
    };
}} // namespace pybind11::detail

47
PYBIND11_MODULE(_pyxacc, m) {
48
49
50
51
    m.doc() = "Python bindings for XACC. XACC provides a plugin infrastructure for "
    		"programming, compiling, and executing quantum kernels in a language and "
    		"hardware agnostic manner.";

52
    py::class_<xacc::InstructionParameter> (m, "InstructionParameter",
53
54
			"The InstructionParameter provides a variant structure "
					"to provide parameters to XACC Instructions at runtime. "
55
56
57
58
59
60
61
62
					"This type can be an int, double, float, string, or complex value.")
		.def(py::init<int>(), "Construct as an int.")
		.def(py::init<double>(), "Construct as a double.")
		.def(py::init<std::string>(), "Construct as a string.")
		.def(py::init<std::complex<double>>(), "Construct as a complex double.")
		.def(py::init<float>(), "Construct as a float.");

    py::class_<xacc::Instruction, std::shared_ptr<xacc::Instruction>>(m, "Instruction", "")
63
64
65
66
67
68
69
70
71
72
73
    	.def("nParameters", &xacc::Instruction::nParameters, "")
    	.def("toString", &xacc::Instruction::toString, "")
        .def("isEnabled", &xacc::Instruction::isEnabled, "")
        .def("isComposite", &xacc::Instruction::isComposite, "")
    	.def("bits", &xacc::Instruction::bits, "")
		.def("getParameter", &xacc::Instruction::getParameter, "")
    	.def("getParameters", &xacc::Instruction::getParameters, "")
    	.def("setParameter", &xacc::Instruction::setParameter, "")
		.def("mapBits", &xacc::Instruction::mapBits, "")
        .def("getTag", &xacc::Instruction::getTag, "")
    	.def("name", &xacc::Instruction::name, "")
74
75
76
		.def("description", &xacc::Instruction::description, "");

    py::class_<xacc::Function, std::shared_ptr<xacc::Function>>(m, "Function", "")
77
    	.def("nInstructions", &xacc::Function::nInstructions, "")
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
		.def("getInstruction", &xacc::Function::getInstruction, "")
		.def("getInstructions", &xacc::Function::getInstructions, "")
		.def("removeInstruction", &xacc::Function::removeInstruction, "")
		.def("replaceInstruction", &xacc::Function::replaceInstruction, "")
		.def("insertInstruction", &xacc::Function::insertInstruction, "")
		.def("addInstruction", &xacc::Function::addInstruction, "")
		.def("addParameter", &xacc::Function::addParameter, "")
		.def("eval", &xacc::Function::operator(), "")
		.def("name", &xacc::Function::name, "")
		.def("description", &xacc::Function::description, "")
		.def("nParameters", &xacc::Function::nParameters, "")
		.def("toString", &xacc::Function::toString, "")
		.def("getParameter", &xacc::Function::getParameter, "")
		.def("getParameters", &xacc::Function::getParameters, "")
		.def("setParameter", &xacc::Function::setParameter, "")
Mccaskey, Alex's avatar
Mccaskey, Alex committed
93
94
		.def("getTag", &xacc::Function::getTag, "")
		.def("mapBits", &xacc::Function::mapBits, "");
95
96

    // Expose the IR interface
97
98
    py::class_<xacc::IR, std::shared_ptr<xacc::IR>> (m, "IR", "The XACC Intermediate Representation, "
    		"serves as a container for XACC Functions.")
99
100
    	.def("getKernels", &xacc::IR::getKernels, "Return the kernels in this IR")
		.def("addKernel", &xacc::IR::addKernel, "");
Mccaskey, Alex's avatar
Mccaskey, Alex committed
101

102
103
104
105
106
107
108
109
110
    py::class_<xacc::InstructionIterator>(m, "InstructionIterator", "")
        .def(py::init<std::shared_ptr<xacc::Function>>())
        .def("hasNext", &xacc::InstructionIterator::hasNext, "")
        .def("next", &xacc::InstructionIterator::next, "");
        
    py::class_<xacc::IRPreprocessor, std::shared_ptr<xacc::IRPreprocessor>> (m, "IRPreprocesor", "")
        .def("process", &xacc::IRPreprocessor::process, "");
    py::class_<xacc::AcceleratorBufferPostprocessor, std::shared_ptr<xacc::AcceleratorBufferPostprocessor>> (m, "AcceleratorBufferPostprocessor", "")
        .def("process", &xacc::AcceleratorBufferPostprocessor::process, "");
111

112
    py::class_<xacc::IRGenerator, std::shared_ptr<xacc::IRGenerator>>(m, "IRGenerator", "")
113
114
115
116
117
118
        .def("generate", (std::shared_ptr<xacc::Function> (xacc::IRGenerator::*)(
				std::vector<xacc::InstructionParameter>)) &xacc::IRGenerator::generate, 
                py::return_value_policy::reference, "")
        .def("generate", (std::shared_ptr<xacc::Function> (xacc::IRGenerator::*)(
				std::map<std::string, xacc::InstructionParameter>)) &xacc::IRGenerator::generate, 
                py::return_value_policy::reference, "");
119
                    
120
    // Expose the Kernel
121
122
123
124
125
126
127
    py::class_<xacc::Kernel<>, std::shared_ptr<xacc::Kernel<>>>(m, "Kernel", "The XACC Kernel is the "
    		"executable functor that executes XACC IR on the desired Accelerator.")
    		.def("getIRFunction", &xacc::Kernel<>::getIRFunction,
    				py::return_value_policy::reference,
					"Return the IR Function instance this Kernel wraps.")
		.def("execute", (void (xacc::Kernel<>::*)(std::shared_ptr<xacc::AcceleratorBuffer>,
				std::vector<xacc::InstructionParameter>)) &xacc::Kernel<>::operator()
128
					, "Execute this Kernel with the given set of "
129
130
							"InstructionParamters. This set can be empty "
							"if there are no parameters.");
131

132
133
134
	py::class_<xacc::KernelList<>>(m, "KernelList", "The XACC KernelList is a vector of "
			"Kernels that provides a operator() implementation to execute multiple kernels at once.")
		.def("execute",
135
136
			(std::vector<std::shared_ptr<xacc::AcceleratorBuffer>> (xacc::KernelList<>::*)(
					std::shared_ptr<xacc::AcceleratorBuffer>,
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
					std::vector<xacc::InstructionParameter>)) &xacc::KernelList<>::operator(),
					"Execute a list of Kernels at once.")
		.def("__getitem__", [](const xacc::KernelList<>& kl, int i) -> xacc::Kernel<> {
			if (i >= kl.size()) throw py::index_error();
			return kl[i];
		})
		.def("__setitem__", [](xacc::KernelList<>& kl, size_t i, xacc::Kernel<> v) {
			if (i >= kl.size()) throw py::index_error();
			kl[i] = v;
		})
		.def("__len__", &xacc::KernelList<>::size)
		.def("__iter__", [](const xacc::KernelList<>& kl) {
			return py::make_iterator(kl.begin(), kl.end());
			}, py::keep_alive<0,1>())
		.def("__getitem__",
152
153
154
155
156
157
158
159
160
161
162
			[]( xacc::KernelList<>& s, py::slice slice) -> xacc::KernelList<>* {
				size_t start, stop, step, slicelength;
				if (!slice.compute(s.size(), &start, &stop, &step, &slicelength))
				throw py::error_already_set();
				xacc::KernelList<> *seq = new xacc::KernelList<>(s.getAccelerator());
				for (size_t i = 0; i < slicelength; ++i) {
					(*seq).push_back(s[start]);
					start += step;
				}
				return seq;
			});
163

164
	// Expose the Accelerator
165
	py::class_<xacc::Accelerator, std::shared_ptr<xacc::Accelerator>>(m,
166
167
			"Accelerator", "Accelerator wraps the XACC C++ Accelerator class "
					"and provides a mechanism for creating buffers of qubits. Execution "
168
169
170
171
					"is handled by the XACC Kernels.")
		.def("name", &xacc::Accelerator::name, "Return the name of this Accelerator.")
		.def("createBuffer", (std::shared_ptr<xacc::AcceleratorBuffer> (xacc::Accelerator::*)(const std::string&, const int))
					&xacc::Accelerator::createBuffer, py::return_value_policy::reference,
172
173
174
175
			"Return a newly created register of qubits of the given size.")
		.def("createBuffer", (std::shared_ptr<xacc::AcceleratorBuffer> (xacc::Accelerator::*)(const std::string&))
					&xacc::Accelerator::createBuffer, py::return_value_policy::reference,
			"Return a newly allocated register of all qubits on the Accelerator.")
176
		.def("execute", (void (xacc::Accelerator::*)(std::shared_ptr<AcceleratorBuffer>, std::shared_ptr<Function>)) &xacc::Accelerator::execute, "Execute the Function with the given AcceleratorBuffer.");
177

178
	// Expose the AcceleratorBuffer
179
180
	py::class_<xacc::AcceleratorBuffer, std::shared_ptr<xacc::AcceleratorBuffer>>(m,
			"AcceleratorBuffer", "The AcceleratorBuffer models a register of qubits.")
181
		.def(py::init<const std::string&,const int>())
182
183
		.def("getExpectationValueZ", &xacc::AcceleratorBuffer::getExpectationValueZ, "Return the expectation value with respect to the Z operator.")
		.def("resetBuffer", &xacc::AcceleratorBuffer::resetBuffer, "Reset this buffer for use in another computation.")
184
		.def("appendMeasurement", (void (xacc::AcceleratorBuffer::*)(const std::string&)) &xacc::AcceleratorBuffer::appendMeasurement, "Append the measurement string")
185
186
187
		.def("getMeasurementStrings", &xacc::AcceleratorBuffer::getMeasurementStrings, "Return observed measurement bit strings")
		.def("computeMeasurementProbability", &xacc::AcceleratorBuffer::computeMeasurementProbability, "Compute the probability of a given bit string")
		.def("getMeasurementCounts", &xacc::AcceleratorBuffer::getMeasurementCounts, "Return the mapping of measure bit strings to their counts.");
188
189

	// Expose the Compiler
190
	py::class_<xacc::Compiler, std::shared_ptr<xacc::Compiler>>(m,
191
			"Compiler", "The XACC Compiler takes as input quantum kernel source code, "
192
193
194
195
196
					"and compiles it to the XACC intermediate representation.")
		.def("name", &xacc::Compiler::name, "Return the name of this Compiler.")
		.def("compile", (std::shared_ptr<xacc::IR> (xacc::Compiler::*)(const std::string&, std::shared_ptr<xacc::Accelerator>)) &xacc::Compiler::compile, "Compile the "
			"given source code against the given Accelerator.")
		.def("translate", &xacc::Compiler::translate, "Translate the given IR Function instance to source code in this Compiler's language.");
197
198

	// Expose the Program object
199
	py::class_<xacc::Program>(m,
200
			"Program", "The Program is the primary entrypoint for compilation and execution in XACC. Clients provide quantum kernel source "
201
202
203
					"code and the Accelerator instance, and the Program handles compiling the code and provides Kernel instances to execute.")
		.def(py::init<std::shared_ptr<xacc::Accelerator>, const std::string &>(), "The constructor")
		.def(py::init<std::shared_ptr<xacc::Accelerator>, std::shared_ptr<xacc::IR>>(), "The constructor")
Mccaskey, Alex's avatar
Mccaskey, Alex committed
204
205
		.def("build", (void (xacc::Program::*)(const std::string&)) &xacc::Program::build, "Compile this program with the given Compiler name.")
  		.def("build", (void (xacc::Program::*)()) &xacc::Program::build, "Compile this program.")
206
207
208
209
		.def("getKernel", (xacc::Kernel<> (xacc::Program::*)(const std::string&)) &xacc::Program::getKernel<>,
				py::return_value_policy::reference, "Return a Kernel representing the source code.")
    		.def("getKernels", &xacc::Program::getRuntimeKernels, "Return all Kernels.")
		.def("nKernels", &xacc::Program::nKernels, "Return the number of kernels compiled by this program");
210
211
212
213
214
215
216
217
218

    // Expose XACC API functions
	m.def("Initialize", (void (*)(std::vector<std::string>))
		&xacc::Initialize,
			"Initialize the framework. Can provide a list of strings to model command line arguments. For instance, "
			"to print the XACC help message, pass ['--help'] to this function, or to set the compiler to use, ['--compiler','scaffold'].");
	m.def("Initialize", (void (*)()) &xacc::Initialize,
			"Initialize the framework. Use this if there are no command line arguments to pass.");
	m.def("getAccelerator", (std::shared_ptr<xacc::Accelerator> (*)(const std::string&))
219
			&xacc::getAccelerator, py::return_value_policy::reference,
220
221
			"Return the accelerator with given name.");
	m.def("getCompiler", (std::shared_ptr<xacc::Compiler> (*)(const std::string&))
222
			&xacc::getCompiler, py::return_value_policy::reference,
223
			"Return the Compiler of given name.");
Mccaskey, Alex's avatar
Mccaskey, Alex committed
224
225
	m.def("getIRPreprocessor", (std::shared_ptr<xacc::IRPreprocessor> (*)(const std::string&))
			&xacc::getService<IRPreprocessor>, py::return_value_policy::reference,
226
227
228
229
			"Return the IRPreprocessor of given name.");
    m.def("getIRGenerator", (std::shared_ptr<xacc::IRGenerator> (*)(const std::string&))
			&xacc::getService<IRGenerator>, py::return_value_policy::reference,
			"Return the IRGenerator of given name.");
230
231
	m.def("setOption", &xacc::setOption, "Set an XACC framework option.");
	m.def("getOption", &xacc::getOption, "Get an XACC framework option.");
Mccaskey, Alex's avatar
Mccaskey, Alex committed
232
233
    m.def("hasAccelerator", &xacc::hasAccelerator, "Does XACC have the given Accelerator installed?");
    m.def("hasCompiler", &xacc::hasCompiler, "Does XACC have the given Accelerator installed?");
234
235
236
	m.def("optionExists", &xacc::optionExists, "Set an XACC framework option.");
	m.def("Finalize", &xacc::Finalize, "Finalize the framework");

237
238
239
240
241
242
243
	m.def("compileKernel", [](std::shared_ptr<Accelerator> acc, const std::string& src, const std::string& compilerName = "") -> std::shared_ptr<Function>{
		    if (!compilerName.empty()) xacc::setOption("compiler", compilerName);
			xacc::Program p(acc,src);
			p.build();
			return p.getRuntimeKernels()[0].getIRFunction();
	}, py::arg("acc"), py::arg("src"), py::arg("compilerName") = std::string(""), py::return_value_policy::move, "");
	
Mccaskey, Alex's avatar
Mccaskey, Alex committed
244
245
	m.def("functionToInstruction", [](std::shared_ptr<Function> f) {return std::dynamic_pointer_cast<Instruction>(f);}, py::return_value_policy::copy);

246
	py::module gatesub = m.def_submodule("gate", "Gate model quantum computing data structures.");
247
248
249
250
251
	gatesub.def("create",
			[](const std::string& name, std::vector<int> qbits, std::vector<InstructionParameter> params = std::vector<InstructionParameter> {}) -> std::shared_ptr<Instruction> {
				return xacc::getService<IRProvider>("gate")->createInstruction(name, qbits, params);
			}, "Convenience function for creating a new GateInstruction.",
			py::arg("name"), py::arg("qbits"),
252
			py::arg("params") = std::vector<InstructionParameter> { });
253
254
255
256
257
258
259
260
261
262
	gatesub.def("createFunction",
			[](const std::string& name, std::vector<int> qbits, std::vector<InstructionParameter> params = std::vector<InstructionParameter> {}) -> std::shared_ptr<Function> {
				return xacc::getService<IRProvider>("gate")->createFunction(name, qbits, params);
			}, "Convenience function for creating a new GateFunction.",
			py::arg("name"), py::arg("qbits"),
			py::arg("params") = std::vector<InstructionParameter> { });
	gatesub.def("createIR",
			[]() -> std::shared_ptr<IR> {
				return xacc::getService<IRProvider>("gate")->createIR();
			}, "Convenience function for creating a new GateIR.");
263

264
    gatesub.def("getState", 
265
            [](std::shared_ptr<Accelerator> acc, std::shared_ptr<Function> f) {
266
                auto results = acc->getAcceleratorState(f);
267
268
                Eigen::VectorXcd ret = Eigen::Map<Eigen::VectorXcd>(results.data(), results.size());
                return ret;
269
270
            }, "Compute and return the state after execution of the given program on the given accelerator.");

271
272
273
}