Commit 73a072c9 authored by Mccaskey, Alex's avatar Mccaskey, Alex
Browse files

working on updates to docs


Signed-off-by: Mccaskey, Alex's avatarAlex McCaskey <mccaskeyaj@ornl.gov>
parent 098dc9ab
from centos:7
run yum install libcurl-devel python3-devel git centos-release-scl make \
&& yum install devtoolset-8-gcc devtoolset-8-gcc-c++ \
devtoolset-8-gcc devtoolset-8-gcc-c++ blas-devel lapack-devel \
&& scl enable devtoolset-8 -- bash \
&& python3 -m pip install cmake
\ No newline at end of file
from fedora:30
run dnf install -y python3-devel libcurl-devel g++ gcc git make \
run dnf install -y python3-devel libcurl-devel g++ gcc git make blas-devel lapack-devel \
&& python3 -m pip install cmake
.. meta::
:scope: doxygen
Architecture
=================
Here we describe the main abstractions defined by XACC to enable quantum-classical
programming in a hardware and language independent manner.
Concepts
========
Here we describe the main concepts or abstractions defined by XACC that enable
hardware agnostic quantum-classical programming, compilation, and execution.
Layered Architecture
--------------------
The architecture of the XACC programming framework exposes a series of interfaces for hardware-agnostic quantum programming, compilation, and execution.
As shown in the figure below, the XACC framework uses a layered software architecture based upon the common
compiler decomposition of a front-end, middle-end, and back-end layers. Each layer exposes different extension
points, or interfaces, for implementing a variety of specific use cases. XACC currently includes interfaces for quantum language compilers, instructions, hardware devices (also referred to as accelerators), compiler optimizations (alternatively, passes), observable measurements, and algorithms.
%%
\begin{figure}[!ht]
\centering
\includegraphics[width=\columnwidth]{figures/layers_v2.png}
% \missingfigure[figwidth=\columnwidth]{layers}
\caption{XACC is composed of three high-level layers - the front-end, middle-end, and back-end. The overall workflow starts with quantum kernel programming at the frontend, followed by IR generation and processing, and ends with back-end execution. Each of these layers exposes a variety of critical extension points.
}
\label{fig:layered}
\end{figure}
%%
%\subsection{Overview of XACC Layers}
\par
The front-end maps quantum code expressions, i.e. source code, into an XACC intermediate representation (IR) suitable for transformations and analysis by the middle layer. More specifically, the front-end layer maps source strings expressing a \emph{quantum kernel} to an IR instance. For example, the XACC front-end may be extended to parse an input source code written in the IBM OpenQASM \cite{openqasm} dialect and enable translation into the XACC IR. Similar functionality is implemented for the Rigetti Quil \cite{quil} dialect and higher-level languages. As a framework, XACC provides an extensible quantum code transpilation or compilation interface that may be tailored to parse many different languages into a common IR for subsequent manipulation.
%in an extensible and modular fashion (see Sec. \ref{sec:compilers}).
\par
The middle layer exposes an IR object model while maintaining an application programming interface (API) for quantum programs that is agnostic to the underlying hardware. The structure of the IR provides an integration mechanism generalizing disparate programming approaches with multiple quantum devices. A critical middle layer concept is the IR transformation, which exposes a framework extension point for performing standard quantum compilation routines, including circuit synthesis, as well as the addition of error mitigation and correction techniques into the logical design.
\par
The back-end layer exposes an abstract quantum computer interface that accepts instances of the IR and executes them on a targeted hardware device (see Sec. \ref{sec:acc}). The back-end layer provides further extension points mapping the IR to hardware-specific instruction sets and the low-level controls used to execute kernels. The former is performed by taking advantage of the middle-end's IR transformation infrastructure. By using a common interface, quantum program execution via the back-end layer is easily extensible to new hardware. % Extensibility of the back-end layer uses a common interface to execute programs directly on quantum hardware.
\par
% This layered architecture is that it promotes an overall separation of concerns that enables management of the complexity of applying quantum programming methods across the high and low-level language dialects native to specific quantum computing devices.
With the layered architecture, XACC efficiently maps high-level programming languages to low-level hardware instruction sets. Where a direct mapping of $N$ languages into $M$ quantum devices would require $NM$ separate language-to-hardware mappings, XACC reduces the amount of work necessary to $N+M$ separate mapping implementations. The IR is the central construct connecting the front-end and back-end layers through a set of transformations.
Intermediate Representation
----------------------------
In order to promote interoperability and programmability across the wide range of
......
XACC Basics
===========
Here we demonstrate leveraging the XACC framework for various
quantum-classical programming tasks. We provide examples in both
C++ and Python.
`AcceleratorBuffer` Usage
-------------------------
The `AcceleratorBuffer` represents a register of qubits. Programmers allocate
this register of a certain size, and pass it by reference to all execution tasks.
These execution tasks are carried out by concrete instances of the `Accelerator`
interface, and these instances are responsible for persisting information to the
provided buffer reference. This ensures programmers have access to all execution results
and metadata upon execution completion.
Programmers can allocate a buffer through the `xacc::qalloc(const int n)` (`xacc.qalloc(int)` in Python) call.
After execution, measurement results can be queried as well as backend-specific
execution metadata. Below demonstrate some basic usage of the `AcceleratorBuffer`
.. code::
#include "xacc.hpp"
...
// Create program somehow... detailed later
program = ...
auto buffer = xacc::qalloc(3);
auto qpu = xacc::getAccelerator("ibm:ibmq_valencia");
qpu->execute(buffer, program);
std::map<std::string, int> results = buffer->getMeasurementCounts();
auto fidelities = buffer["1q-gate-fidelities"].as<std::vector<double>>();
auto expValZ = buffer->getExpectationValueZ();
in Python
.. code::
import xacc
...
// Create program somehow... detailed later
program = ...
buffer = xacc.qalloc(3)
qpu = xacc.getAccelerator('ibm:ibmq_valencia', {'shots':8192})
qpu.execute(buffer, program)
results = buffer.getMeasurementCounts()
fidelities = buffer['1q-gate-fidelities']
expValZ = buffer.getExpectationValueZ()
Intermediate Representation, Kernels, and Compilers
----------------------------------------------------
Above we mentioned a `program` variable but did not detail how it was created. This instances
is represented in XACC as a `CompositeInstruction`. The creation of `Instruction`s and
`CompositeInstruction`s is demonstrated here. First, we create this instances via an
implementation of the `IRProvider`, specifically a 3 instruction circuit with one
parameterized `Ry` on a variable `theta`.
.. code::
#include "xacc.hpp"
...
auto provider = xacc::getIRProvider("quantum");
auto program = provider->createComposite("foo", {"theta"});
auto x = provider->createInstruction("X", {0});
auto ry = provider->createInstruction("Ry", {1}, {"theta"});
auto cx = provider->createInstruction("CX", {1,0});
program->addInstructions({x, ry, cx});
in Python
.. code::
import xacc
...
provider = xacc.getIRProvider('quantum')
program = provider.createComposite('foo', ['theta'])
x = provider.createInstruction('X', [0])
ry = provider.createInstruction('Ry', [1], ['theta'])
cx = provider.createInstruction('CX', [1,0])
program.addInstructions([x,ry,cx])
We could also create IR through textual source code representations in a language
that is available to the framework. Availability here implies that there exists
a `Compiler` implementation for the language being used. `Compilers` take kernel
source strings and produce IR (one or many `CompositeInstruction`s). Here we demonstrate
the same circuit as above, but using a Quil kernel
.. code::
#include "xacc.hpp"
...
auto qpu = xacc::getAccelerator("ibm");
auto quil = xacc::getCompiler("quil");
auto ir = quil->compile(R"(
__qpu__ void ansatz(AcceleratorBuffer q, double x) {
X 0
Ry(x) 1
CX 1 0
}
__qpu__ void X0X1(AcceleratorBuffer q, double x) {
ansatz(q, x)
H 0
H 1
MEASURE 0 [0]
MEASURE 1 [1]
}
)", qpu);
auto ansatz = ir->getComposite("ansatz");
auto x0x1 = ir->getComposite("X0X1");
in Python
.. code::
import xacc
...
qpu = xacc.getAccelerator('ibm')
quil = xacc.getCompiler('quil')
ir = quil.compile('''
__qpu__ void ansatz(AcceleratorBuffer q, double x) {
X 0
Ry(x) 1
CX 1 0
}
__qpu__ void X0X1(AcceleratorBuffer q, double x) {
ansatz(q, x)
H 0
H 1
MEASURE 0 [0]
MEASURE 1 [1]
}
''', qpu)
ansatz = ir.getComposite('ansatz')
x0x1 = ir.getComposite('X0X1')
Here, `x0x1` is a `CompositeInstruction` that can be passed to `Accelerator::execute()` for
backend execution.
Next we demonstrate how one might leverate `IRTransformation` to perform general optimizations
on IR instances.
.. code::
#include "xacc.hpp"
...
auto xasmCompiler = xacc::getCompiler("xasm");
auto ir = xasmCompiler->compile(R"(__qpu__ void bell(qbit q) {
H(q[0]);
CX(q[0], q[1]);
CX(q[0], q[1]);
CX(q[0], q[1]);
Measure(q[0]);
Measure(q[1]);
})", nullptr);
auto f = ir->getComposite("bell");
assert(6 == f->nInstructions());
auto opt = xacc::getIRTransformation("circuit-optimizer");
opt->apply(f, nullptr);
assert (4 == f->nInstructions());
in Python
.. code::
import xacc
...
# Create a bell state program with too many cnots
xasm = xacc.getCompiler('xasm')
ir = xasm.compile('''__qpu__ void bell(qbit q) {
H(q[0]);
CX(q[0],q[1]);
CX(q[0],q[1]);
CX(q[0], q[1]);
Measure(q[0]);
Measure(q[1]);
}''')
f = ir.getComposite('bell')
assert(6 == f.nInstructions())
# Run the circuit-optimizer IRTransformation
optimizer = xacc.getIRTransformation('circuit-optimizer')
optimizer.apply(f, None, {})
# should have 4 instructions, not 6
assert(4 == f.nInstructions())
print(f.toString())
`Observable` Usage
------------------
The `Observable` concept in XACC dictates measurements to be performed
on unmeasured an `CompositeInstruction`. XACC provides `pauli` and `fermion`
`Observable` implementations. Below we demonstrate how one might create these objects.
.. code::
#include "xacc.hpp"
#include "xacc_observable.hpp"
...
auto x0x1 = xacc::quantum::getObservable("pauli");
x0x1->fromString('X0 X1');
// observe() returns a list of measured circuits
// here we only have one
auto measured_circuit = x0x1->observe(program)[0];
auto fermion = xacc::getObservable("fermion");
fermion->fromString("1^ 0");
auto jw = xacc::getService<ObservableTransform>("jordan-wigner");
auto spin = jw->transform(fermion);
in Python
.. code::
import xacc
...
x0x1 = xacc.getObservable('pauli', 'X0 X1')
// observe() returns a list of measured circuits
// here we only have one
measured_circuit = x0x1.observe(program)[0]
fermion = xacc.getObservable('fermion', '1^ 0')
jw = xacc.getObservableTransform('jordan-wigner')
spin = jw.transform(fermion)
`Accelerator` Usage
-------------------
The `Accelerator` is the primary interface to backend quantum computers and simulators for XACC.
The can be initialized with a heterogeneous map of input parameters, expose qubit connectivity information,
and implement execution capabilities given a valid `AcceleratorBuffer` and `CompositeInstruction`.
Here we demonstrate getting reference to an `Accelerator` and using it to execute a simple bell state.
Note this is a full example, that leverages the `xasm` compiler as well as requisite C++ framework
initialization and finalization.
.. code::
#include "xacc.hpp"
int main(int argc, char **argv) {
xacc::Initialize(argc, argv);
// Get reference to the Accelerator
auto accelerator =
xacc::getAccelerator("local-ibm", {std::make_pair("shots", 5000)});
// Allocate some qubits
auto buffer = xacc::qalloc(2);
auto xasmCompiler = xacc::getCompiler("xasm");
auto ir = xasmCompiler->compile(R"(__qpu__ void bell(qbit q) {
H(q[0]);
CX(q[0], q[1]);
Measure(q[0]);
Measure(q[1]);
})", accelerator);
accelerator->execute(buffer, ir->getComposites()[0]);
buffer->print();
xacc::Finalize();
return 0;
}
in Python
.. code::
import xacc
accelerator = xacc.getAccelerator('local-ibm', {'shots':5000})
buffer = xacc.qalloc(2)
xasm = xacc.getCompiler('xasm')
ir = xasm.compile('''__qpu__ void bell(qbit q) {
H(q[0]);
CX(q[0],q[1]);
Measure(q[0]);
Measure(q[1]);
}''', accelerator)
accelerator.execute(buffer, ir.getComposites()[0])
# note accelerators can execute lists of CompositeInstructions too
# usefule for executing many circuits with one remote qpu call
# accelerator.execute(buffer, ir.getComposites())
`Optimizer` Usage
-----------------
This abstraction is meant for the injection of general classical multi-variate function
optimization routines. XACC provides implementations leveraging NLOpt and MLPack C++ libraries.
`Optimizer`s expose an `optimize()` method that takes as input an `OptFunction`, which serves as
a thin wrapper for functor-like objects exposing a specific argument structure (must take as first
arg a `vector<double>` representing current iterate's parameters, and another one representing the mutable
gradient vector). Below is a demonstration of how one might use this utility:
.. code::
auto optimizer =
xacc::getOptimizer("nlopt");
optimizer->setOptions(
HeterogeneousMap{std::make_pair("nlopt-maxeval", 200),
std::make_pair("nlopt-optimizer", "l-bfgs")});
OptFunction f(
[](const std::vector<double> &x, std::vector<double> &grad) {
if (!grad.empty()) {
grad[0] = -2 * (1 - x[0]) + 400 * (std::pow(x[0], 3) - x[1] * x[0]);
grad[1] = 200 * (x[1] - std::pow(x[0],2));
}
return = 100 * std::pow(x[1] - std::pow(x[0], 2), 2) + std::pow(1 - x[0], 2);
},
2);
auto result = optimizer->optimize(f);
auto opt_val = result.first;
auto opt_params = result.second;
or in Python
.. code::
def rosen_with_grad(x):
g = [-2*(1-x[0]) + 400.*(x[0]**3 - x[1]*x[0]), 200 * (x[1] - x[0]**2)]
xx = (1.-x[0])**2 + 100*(x[1]-x[0]**2)**2
return xx, g
optimizer = xacc.getOptimizer('mlpack',{'mlpack-optimizer':'l-bfgs'})
opt_val, opt_params = optimizer.optimize(rosen_with_grad,2)
`xacc::qasm' Usage
------------------
To improve programming efficiency, readability, and utility of the quantum kernel string
compilation, XACC exposes a `qasm()` function. This function takes as input an enhanced quantum
kernel source string syntax and compiles it to XACC IR. This source string is *enhanced* in that
it requires that extra metadata be present in order to adequately compile the quantum code.
Specifically, the source string must contain the following key words:
* a single *.compiler NAME*, to indicate which XACC compiler implementation to use.
* one or many *.circuit NAME* calls to give the created CompositeInstruction (circuit) a name.
* one *.parameters PARAM 1, PARAM 2, .., PARAM N* for each parameterized circuit to tell the Compiler the names of the parameters.
* A *.qbit NAME* optional keyword can be provided when the source code itself makes reference to the `qbit` or `AcceleratorBuffer`
Running this command with the appropriately provided keywords will compile the source string to XACC IR and store it an
internal compilation database (standard map of CompositeInstruction names to CompositeInstructions), and users
can get reference to the individual CompositeInstructions via an exposed `getCompiled()` XACC API call. The
code below demonstrates how one would use `qasm()` and its overall utility.
.. code::
#include "xacc.hpp"
...
xacc::qasm(R"(
.compiler xasm
.circuit deuteron_ansatz
.parameters x
.qbit q
for (int i = 0; i < 2; i++) {
H(q[0]);
}
exp_i_theta(q, x, {{"pauli", "X0 Y1 - Y0 X1"}});
)");
auto ansatz =
xacc::getCompiled("deuteron_ansatz");
// Quil example, multiple kernels
xacc::qasm(R"(.compiler quil
.circuit ansatz
.parameters theta, phi
X 0
H 2
CNOT 2 1
CNOT 0 1
Rz(theta) 0
Ry(phi) 1
H 0
.circuit x0x1
ansatz(theta, phi)
H 0
H 1
MEASURE 0 [0]
MEASURE 1 [1]
)");
auto x0x1 = xacc::getCompiled("x0x1");
or in Python
.. code::
import xacc
...
xacc.qasm('''
.compiler xasm
.circuit deuteron_ansatz
.parameters x
.qbit q
for (int i = 0; i < 2; i++) {
X(q[0]);
}
exp_i_theta(q, x, {{"pauli", "X0 Y1 - Y0 X1"}});
''')
ansatz =
xacc.getCompiled('deuteron_ansatz')
# Quil example, multiple kernels
xacc.qasm('''.compiler quil
.circuit ansatz
.parameters theta, phi
X 0
H 2
CNOT 2 1
CNOT 0 1
Rz(theta) 0
Ry(phi) 1
H 0
.circuit x0x1
ansatz(theta, phi)
H 0
H 1
MEASURE 0 [0]
MEASURE 1 [1]
''')
x0x1 = xacc.getCompiled('x0x1')
......@@ -15,7 +15,7 @@ XACC is an extensible compilation framework for hybrid quantum-classical
computing architectures. It provides extensible language frontend and hardware
backend compilation components glued together via a novel, polymorphic quantum intermediate
representation. XACC currently supports quantum-classical programming and enables
the execution of quantum kernels on IBM, Rigetti, and D-Wave QPUs, as well as a
the execution of quantum kernels on IBM, Rigetti, IonQ, and D-Wave QPUs, as well as a
number of quantum computer simulators.
The XACC programming model follows the traditional co-processor model, akin to OpenCL or CUDA for GPUs, but
......@@ -39,6 +39,11 @@ Accelerators, and IR. To enable support for various compilers and accelerators
(like the OpenQasm or Quil compilers, or the IBM or Rigetti QPUs) you
can install the appropriate plugin (see `XACC Plugins <plugins.html>`_).
Description of Architecture
---------------------------
For a comprehensive discussion of all components of the XACC programming model and architecture,
please refer to this `manuscript <https://arxiv.org/abs/1911.02452>`_.
XACC Development Team
----------------------
......@@ -66,27 +71,23 @@ You can ask questions by creating a new issue with the question tag.
:caption: Contents:
install
arch
plugins
tutorials
apps
em
bench
basics
Publications
------------
The following publications describe XACC or experiments leveraging the it.
[1] `XACC: A System-Level Software Infrastructure for Heterogeneous Quantum-Classical Computing <https://arxiv.org/abs/1911.02452>`_
[1] `A language and hardware independent approach to quantum-classical computing <https://www.sciencedirect.com/science/article/pii/S2352711018300700>`_
[2] `A language and hardware independent approach to quantum-classical computing <https://www.sciencedirect.com/science/article/pii/S2352711018300700>`_
[2] `Validating Quantum-Classical Programming Models with Tensor Network Simulations <https://arxiv.org/abs/1807.07914>`_
[3] `Validating Quantum-Classical Programming Models with Tensor Network Simulations <https://arxiv.org/abs/1807.07914>`_
[3] `Hybrid Programming for Near-term Quantum Computing Systems <https://arxiv.org/abs/1805.09279>`_
[4] `Hybrid Programming for Near-term Quantum Computing Systems <https://arxiv.org/abs/1805.09279>`_
Publications Leveraging XACC
----------------------------
[1] `Cloud Quantum Computing of an Atomic Nucleus <https://journals.aps.org/prl/abstract/10.1103/PhysRevLett.120.210501>`_
[5] `Cloud Quantum Computing of an Atomic Nucleus <https://journals.aps.org/prl/abstract/10.1103/PhysRevLett.120.210501>`_
[2] `Quantum-Classical Computations of Schwinger Model Dynamics using Quantum Computers <https://journals.aps.org/pra/abstract/10.1103/PhysRevA.98.032331>`_
[6] `Quantum-Classical Computations of Schwinger Model Dynamics using Quantum Computers <https://journals.aps.org/pra/abstract/10.1103/PhysRevA.98.032331>`_
.. toctree::
......
Installation
============
This section provide guidelines for installing XACC and its TPLs.
Note that you must have a C++14 compliant compiler and a recent version of CMake (version 3.12+). We
recommend installing with the Python API (although you may choose not to). This discussion will
describe the build process with the Python API enabled. For this you will need a Python 3 executable and
development install. To interact with remote QPUs, you will need CURL with OpenSSL development
headers and libraries.
Ubuntu 16.04 Prerequisites
--------------------------
Here we will demonstrate installing from a bare Ubuntu install using GCC 8. We
install BLAS and LAPACK as well, which is required to build some optional simulators.
We install libunwind-dev which is also optional, but provides verbose stack-trace printing
upon execution error.
Pre-Requisites
--------------
.. code::
$ sudo apt-get update && sudo apt-get install -y software-properties-common
$ sudo add-apt-repository ppa:ubuntu-toolchain-r/test && sudo apt-get update
$ sudo apt-get -y install gcc-8 g++-8 git libcurl4-openssl-dev python3 libunwind-dev \
libpython3-dev python3-pip libblas-dev liblapack-dev
$ sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-8 50
$ sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-8 50
The following software is required before building XACC:
Ubuntu 18.04 Prerequisites
--------------------------
Here we will demonstrate installing from a bare Ubuntu install using GCC 7 (default on 18.04). We
install BLAS and LAPACK as well, which is required to build some optional simulators.
We install libunwind-dev which is also optional, but provides verbose stack-trace printing
upon execution error.
+------------------------+------------+-----------+
| Packages | Dependency | Version |
+========================+============+===========+
| C++11 Compiler | Required | See below |
+------------------------+------------+-----------+
| OpenSSL | Required | 1.0 |
+------------------------+------------+-----------+
| CMake | Required | 3.2+ |
+------------------------+------------+-----------+
.. code::
Note that you must have a C++11 compliant compiler. If you prefer ``gcc/g++``,
it is recommended that you use at least version 5.0 and up. Using ``[4.8,5)`` will
cause XACC to skip building and installing Antlr, which is required for most XACC
Compiler extensions.
$ sudo apt-get update
$ sudo apt-get -y install gcc g++ git libcurl4-openssl-dev python3 libunwind-dev \
libpython3-dev python3-pip libblas-dev liblapack-dev
The other dependencies are relatively easy to install on various operating
systems. Any of the following commands will work for Mac, Fedora/RedHat/CentOS, or Ubuntu:
Centos 7 Prerequisites
--------------------------
Here we will demonstrate installing from a bare Centos 7 install using GCC 8. We
install BLAS and LAPACK as well, which is required to build some optional simulators.
.. code::
$ (macosx) brew/port install cmake openssl
$ (fedora) dnf install cmake openssl-devel
$ (ubuntu) apt-get install cmake libssl-dev
Building XACC
-------------
$ sudo yum install libcurl-devel python3-devel git centos-release-scl make \
devtoolset-8-gcc devtoolset-8-gcc-c++ blas-devel lapack-devel
$ scl enable devtoolset-8 -- bash [ you might put this in your .bashrc ]
Clone the XACC repository:
Fedora 30 Prerequisites
--------------------------
Here we will demonstrate installing from a bare Fedora 30 install using GCC 9. We
install BLAS and LAPACK as well, which is required to build some optional simulators.
.. code::
$ git clone --recursive https://github.com/eclipse/xacc
$ sudo dnf install python3-devel libcurl-devel git g++ gcc make blas-devel lapack-devel
$ sudo python3 -m pip install cmake
Note you must pass the ``--recursive`` flag. If you don't you must run
``git submodule update --init --recursive``.
Mac OS X Prerequisites
--------------------------
Ensure that you have XCode command utilities installed. A common issue seen is missing
standard includes like `wchar.h` and others. See `here <https://stackoverflow.com/a/52530212>`_
for proper XCode install and configuring to address these types of issues. Here we assume you
have Homebrew installed.
XACC requires CMake 3.2+. Run the following to
configure and build XACC:
.. code::
.. code:: bash
$ brew install python3 openssl curl
$ cd xacc && mkdir build && cd build
$ cmake ..
$ make install
Build XACC
----------
The best way to install a recent version of CMake is through Python Pip.
This will build and install XACC to ``$HOME/.xacc`` by default. If you would
like to install XACC somewhere else, replace the above ``cmake`` command with the following
.. code::
$ sudo python3 -m pip install cmake
Now clone and build XACC