Unverified Commit be5a7a9f authored by Mccaskey, Alex's avatar Mccaskey, Alex Committed by GitHub
Browse files

Merge pull request #119 from amrutn/master

committing scaffold and xacclang work
parents 64454408 f4bc3ccf
Project(ScaffCompiler C CXX)
cmake_minimum_required(VERSION 3.13.3)
set(CMAKE_STANDARD_REQUIRED ON)
set(CMAKE_CXX_STANDARD 11)
option(SCAFFOLD_PATH "Path of scaffold install" "scaffcc")
find_package(XACC REQUIRED)
if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set (CMAKE_INSTALL_PREFIX "${XACC_ROOT}" CACHE PATH "default install path" FORCE )
endif()
# Modify our CMAKE_MODULE_PATH
set(CppMicroServicesConfig_DIR "${XACC_ROOT}/share/cppmicroservices4/cmake")
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${XACC_ROOT}/share/xacc")
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CppMicroServicesConfig_DIR}")
include(CppMicroServicesConfig)
add_subdirectory(compiler)
add_subdirectory(pragmas)
\ No newline at end of file
# XACC-Scaffold
XACC-Scaffold is a XACC and QCOR plugin meant to compile and run scaffold
quantum code on a quantum processor while working in a classical environment.
## Dependencies
Compiler (C++11): GNU 5+, Clang 8+
CMake 3.9+
XACC: see https://xacc.readthedocs.io/en/latest/install.html#building-xacc
QCOR: see https://github.com/ORNL-QCI/qcor/
SCAFFOLD: see https://github.com/epiqc/ScaffCC
##Build instructions
For CMake 3.9+, do not use the apt-get installer, instead use `pip`,
and ensure that `/usr/local/bin` is in your PATH:
```bash
$ python -m pip install --upgrade cmake
$ export PATH=$PATH:/usr/local/bin
```
On Ubuntu 16+, install latest clang and llvm libraries and headers (you may need sudo)
```bash
$ wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
$ echo "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial main" > /etc/apt/sources.list.d/llvm.list
$ apt-get update
$ apt-get install -y libclang-9-dev llvm-9-dev
$ ln -s /usr/bin/llvm-config-9 /usr/bin/llvm-config
```
Note that, for now, developers must clone XACC-Scaffold manually:
``` bash
$ git clone https://code.ornl.gov/qci/xacc-scaffold
$ cd xacc-scaffold
$ mkdir build && cd build
$ cmake .. -DXACC_DIR=~/.xacc (or wherever you installed XACC) -DSCAFFOLD_PATH = ~/home/project/scaffcc (Or wherever you installed scaffold)
$ make install
```
Update your PATH to ensure that the ```qcor``` compiler is available.
```bash
$ export PATH=$PATH:$HOME/.xacc/bin
```
## Example Usage
Here we demonstrate how to program, compile and run basic quantum scaffold code to make a bell state.
Create the following file called bell_state.cpp
```cpp
#include qcor
int main(int argc, char** argv) {
qcor::Initialize(argc, argv);
auto buffer = std::make_shared<AcceleratorBuffer>(2);
#pragma qcor scaffold(buffer, 2)
{
cbit out[2];
H(buffer[0]);
CNOT(buffer[0], buffer[1]);
out[0] = MeasZ(buffer[0]);
out[1] = MeasZ(buffer[1]);
}
buffer->print();
}
```
Top compile this with QCOR, run the following
```bash
$ qcor bell_state.cpp
```
Here we demonstrate how to program, compile and run quantum scaffold code with functions and modules. Create the following file
called scaff_function_example.cpp
```cpp
#include "qcor.hpp"
void biina (std::shared_ptr<xacc::AcceleratorBuffer> b) {
#pragma qcor scaffold(b, 2)
{
module hi (qbit* b1) {
H(b1[0]);
}
module hello(qbit* b1) {
int i = 0;
for (i = 0; i < 2; i++) {
hi(b1);
}
}
cbit out[2];
hello(b);
CNOT(b[0], b[1]);
out[0] = MeasZ(b[0]);
out[1] = MeasZ(b[1]);
}
b -> print();
}
int main(int argc, char** argv) {
qcor::Initialize(argc, argv);
auto buffer = std::make_shared<AcceleratorBuffer>(2);
biina(buffer);
buffer->print();
}
```
and run
```bash
$ qcor scaff_function_example.cpp
```
Here we demonstrate how to program, compile, and run a VQE problem with scaffold. Create the following file called vqe_example.cpp
```cpp
#include "qcor.hpp"
int main(int argc, char** argv) {
qcor::Initialize(argc, argv);
// Create a buffer of qubits
auto buffer = xacc::qalloc(2);
// allocate the required vqe parameters
// initialized to 0.0
std::vector<double> params(1);
// Create an Optimizer
auto optimizer = qcor::getOptimizer(
"nlopt", {{"nlopt-optimizer", "cobyla"},
{"nlopt-maxeval", 20}});
// Create the Deuteron N=2 Hamiltonian
// This will dictate measurements on our ansatz
auto op = qcor::getObservable("pauli", "5.907 - 2.1433 X0X1 "
"- 2.1433 Y0Y1"
"+ .21829 Z0 - 6.125 Z1");
// Create the ansatz with Scaffold code
// Annotate to indicate we want to use this ansatz
// for VQE, providing the qreg and its size, and
// VQE-pertinent information
#pragma qcor scaffold(buffer, 2) vqe(params, op, optimizer)
{
X(buffer[0]);
Ry(buffer[1], params[0]);
CNOT(buffer[1], buffer[0]);
}
// Print the results
std::cout << "Optimal Energy = " << mpark::get<double>(buffer->getInformation("opt-val")) << "\n";
}
```
To compile this with QCOR, run the following
```bash
$ qcor vqe_example.cpp
```
# Detect Clang libraries
#
# Defines the following variables:
# CLANG_FOUND - True if Clang was found
# CLANG_INCLUDE_DIRS - Where to find Clang includes
# CLANG_LIBRARY_DIRS - Where to find Clang libraries
#
# CLANG_LIBCLANG_LIB - Libclang C library
#
# CLANG_CLANGFRONTEND_LIB - Clang Frontend (C++) Library
# CLANG_CLANGDRIVER_LIB - Clang Driver (C++) Library
# ...
#
# CLANG_LIBS - All the Clang C++ libraries
#
# Uses the same include and library paths detected by FindLLVM.cmake
#
# See http://clang.llvm.org/docs/InternalsManual.html for full list of libraries
#=============================================================================
# Copyright 2014-2015 Kevin Funk <kfunk@kde.org>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#=============================================================================
if (${Clang_FIND_REQUIRED})
find_package(LLVM ${Clang_FIND_VERSION} REQUIRED)
else ()
find_package(LLVM ${Clang_FIND_VERSION})
endif ()
set(CLANG_FOUND FALSE)
if (LLVM_FOUND AND LLVM_LIBRARY_DIRS)
macro(FIND_AND_ADD_CLANG_LIB _libname_)
string(TOUPPER ${_libname_} _prettylibname_)
find_library(CLANG_${_prettylibname_}_LIB NAMES ${_libname_} HINTS ${LLVM_LIBRARY_DIRS})
if(CLANG_${_prettylibname_}_LIB)
set(CLANG_LIBS ${CLANG_LIBS} ${CLANG_${_prettylibname_}_LIB})
endif()
endmacro(FIND_AND_ADD_CLANG_LIB)
# note: On Windows there's 'libclang.dll' instead of 'clang.dll' -> search for 'libclang', too
find_library(CLANG_LIBCLANG_LIB NAMES clang libclang HINTS ${LLVM_LIBRARY_DIRS}) # LibClang: high-level C interface
FIND_AND_ADD_CLANG_LIB(clangFrontend)
FIND_AND_ADD_CLANG_LIB(clangDriver)
FIND_AND_ADD_CLANG_LIB(clangCodeGen)
FIND_AND_ADD_CLANG_LIB(clangSema)
FIND_AND_ADD_CLANG_LIB(clangChecker)
FIND_AND_ADD_CLANG_LIB(clangAnalysis)
FIND_AND_ADD_CLANG_LIB(clangRewriteFrontend)
FIND_AND_ADD_CLANG_LIB(clangRewrite)
FIND_AND_ADD_CLANG_LIB(clangAST)
FIND_AND_ADD_CLANG_LIB(clangASTMatchers)
FIND_AND_ADD_CLANG_LIB(clangParse)
FIND_AND_ADD_CLANG_LIB(clangLex)
FIND_AND_ADD_CLANG_LIB(clangBasic)
FIND_AND_ADD_CLANG_LIB(clangARCMigrate)
FIND_AND_ADD_CLANG_LIB(clangEdit)
FIND_AND_ADD_CLANG_LIB(clangFrontendTool)
FIND_AND_ADD_CLANG_LIB(clangRewrite)
FIND_AND_ADD_CLANG_LIB(clangSerialization)
FIND_AND_ADD_CLANG_LIB(clangTooling)
FIND_AND_ADD_CLANG_LIB(clangStaticAnalyzerCheckers)
FIND_AND_ADD_CLANG_LIB(clangStaticAnalyzerCore)
FIND_AND_ADD_CLANG_LIB(clangStaticAnalyzerFrontend)
FIND_AND_ADD_CLANG_LIB(clangSema)
FIND_AND_ADD_CLANG_LIB(clangRewriteCore)
endif()
if(CLANG_LIBS OR CLANG_LIBCLANG_LIB)
set(CLANG_FOUND TRUE)
else()
message(STATUS "Could not find any Clang libraries in ${LLVM_LIBRARY_DIRS}")
endif()
if(CLANG_FOUND)
set(CLANG_LIBRARY_DIRS ${LLVM_LIBRARY_DIRS})
set(CLANG_INCLUDE_DIRS ${LLVM_INCLUDE_DIRS})
# check whether llvm-config comes from an install prefix
execute_process(
COMMAND ${LLVM_CONFIG_EXECUTABLE} --src-root
OUTPUT_VARIABLE _llvmSourceRoot
OUTPUT_STRIP_TRAILING_WHITESPACE
)
string(FIND "${LLVM_INCLUDE_DIRS}" "${_llvmSourceRoot}" _llvmIsInstalled)
if (NOT _llvmIsInstalled)
message(STATUS "Detected that llvm-config comes from a build-tree, adding more include directories for Clang")
list(APPEND CLANG_INCLUDE_DIRS
"${LLVM_INSTALL_PREFIX}/tools/clang/include" # build dir
"${_llvmSourceRoot}/tools/clang/include" # source dir
)
endif()
message(STATUS "Found Clang (LLVM version: ${LLVM_VERSION})")
message(STATUS " Include dirs: ${CLANG_INCLUDE_DIRS}")
message(STATUS " Clang libraries: ${CLANG_LIBS}")
message(STATUS " Libclang C library: ${CLANG_LIBCLANG_LIB}")
else()
if(Clang_FIND_REQUIRED)
message(FATAL_ERROR "Could NOT find Clang")
endif()
endif()
# Find the native LLVM includes and libraries
#
# Defines the following variables
# LLVM_INCLUDE_DIRS - where to find llvm include files
# LLVM_LIBRARY_DIRS - where to find llvm libs
# LLVM_CFLAGS - llvm compiler flags
# LLVM_LFLAGS - llvm linker flags
# LLVM_MODULE_LIBS - list of llvm libs for working with modules.
# LLVM_INSTALL_PREFIX - LLVM installation prefix
# LLVM_FOUND - True if llvm found.
# LLVM_VERSION - Version string ("llvm-config --version")
#
# This module reads hints about search locations from variables
# LLVM_ROOT - Preferred LLVM installation prefix (containing bin/, lib/, ...)
#
# Note: One may specify these as environment variables if they are not specified as
# CMake variables or cache entries.
#=============================================================================
# Copyright 2014 Kevin Funk <kfunk@kde.org>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#=============================================================================
if (NOT LLVM_ROOT AND DEFINED ENV{LLVM_ROOT})
file(TO_CMAKE_PATH "$ENV{LLVM_ROOT}" LLVM_ROOT)
endif()
# if the user specified LLVM_ROOT, use that and fail otherwise
if (LLVM_ROOT)
find_program(LLVM_CONFIG_EXECUTABLE NAMES llvm-config HINTS ${LLVM_ROOT}/bin DOC "llvm-config executable" NO_DEFAULT_PATH)
else()
# find llvm-config, prefer the one with a version suffix, e.g. llvm-config-3.5
# note: FreeBSD installs llvm-config as llvm-config35 and so on
# note: on some distributions, only 'llvm-config' is shipped, so let's always try to fallback on that
string(REPLACE "." "" LLVM_FIND_VERSION_CONCAT ${LLVM_FIND_VERSION})
find_program(LLVM_CONFIG_EXECUTABLE NAMES llvm-config-${LLVM_FIND_VERSION} llvm-config${LLVM_FIND_VERSION_CONCAT} llvm-config DOC "llvm-config executable")
# other distributions don't ship llvm-config, but only some llvm-config-VERSION binary
# try to deduce installed LLVM version by looking up llvm-nm in PATH and *then* find llvm-config-VERSION via that
if (NOT LLVM_CONFIG_EXECUTABLE)
find_program(_llvmNmExecutable llvm-nm)
if (_llvmNmExecutable)
execute_process(COMMAND ${_llvmNmExecutable} --version OUTPUT_VARIABLE _out)
string(REGEX REPLACE ".*LLVM version ([^ \n]+).*" "\\1" _versionString "${_out}")
find_program(LLVM_CONFIG_EXECUTABLE NAMES llvm-config-${_versionString} DOC "llvm-config executable")
endif()
endif()
endif()
set(LLVM_FOUND FALSE)
if (LLVM_CONFIG_EXECUTABLE)
# verify that we've found the correct version of llvm-config
execute_process(COMMAND ${LLVM_CONFIG_EXECUTABLE} --version
OUTPUT_VARIABLE LLVM_VERSION
OUTPUT_STRIP_TRAILING_WHITESPACE)
if (NOT LLVM_VERSION)
set(_LLVM_ERROR_MESSAGE "Failed to parse version from llvm-config")
elseif (LLVM_FIND_VERSION VERSION_GREATER LLVM_VERSION)
set(_LLVM_ERROR_MESSAGE "LLVM version too old: ${LLVM_VERSION}")
else()
set(LLVM_FOUND TRUE)
endif()
else()
set(_LLVM_ERROR_MESSAGE "Could NOT find 'llvm-config' executable")
endif()
if (LLVM_FOUND)
execute_process(
COMMAND ${LLVM_CONFIG_EXECUTABLE} --includedir
OUTPUT_VARIABLE LLVM_INCLUDE_DIRS
OUTPUT_STRIP_TRAILING_WHITESPACE
)
execute_process(
COMMAND ${LLVM_CONFIG_EXECUTABLE} --libdir
OUTPUT_VARIABLE LLVM_LIBRARY_DIRS
OUTPUT_STRIP_TRAILING_WHITESPACE
)
execute_process(
COMMAND ${LLVM_CONFIG_EXECUTABLE} --cppflags
OUTPUT_VARIABLE LLVM_CFLAGS
OUTPUT_STRIP_TRAILING_WHITESPACE
)
execute_process(
COMMAND ${LLVM_CONFIG_EXECUTABLE} --ldflags
OUTPUT_VARIABLE LLVM_LFLAGS
OUTPUT_STRIP_TRAILING_WHITESPACE
)
execute_process(
COMMAND ${LLVM_CONFIG_EXECUTABLE} --libs core bitreader asmparser analysis
OUTPUT_VARIABLE LLVM_MODULE_LIBS
OUTPUT_STRIP_TRAILING_WHITESPACE
)
execute_process(
COMMAND ${LLVM_CONFIG_EXECUTABLE} --libfiles
OUTPUT_VARIABLE LLVM_LIBS
OUTPUT_STRIP_TRAILING_WHITESPACE
)
string(REPLACE " " ";" LLVM_LIBS ${LLVM_LIBS}) # Make it consistent with --libs
execute_process(
COMMAND ${LLVM_CONFIG_EXECUTABLE} --system-libs
OUTPUT_VARIABLE LLVM_SYSTEM_LIBS
OUTPUT_STRIP_TRAILING_WHITESPACE
)
execute_process(
COMMAND ${LLVM_CONFIG_EXECUTABLE} --prefix
OUTPUT_VARIABLE LLVM_INSTALL_PREFIX
OUTPUT_STRIP_TRAILING_WHITESPACE
)
# potentially add include dir from binary dir for non-installed LLVM
execute_process(
COMMAND ${LLVM_CONFIG_EXECUTABLE} --src-root
OUTPUT_VARIABLE _llvmSourceRoot
OUTPUT_STRIP_TRAILING_WHITESPACE
)
string(FIND "${LLVM_INCLUDE_DIRS}" "${_llvmSourceRoot}" _llvmIsInstalled)
if (NOT _llvmIsInstalled)
list(APPEND LLVM_INCLUDE_DIRS "${LLVM_INSTALL_PREFIX}/include")
endif()
endif()
if (LLVM_FIND_REQUIRED AND NOT LLVM_FOUND)
message(FATAL_ERROR "Could not find LLVM: ${_LLVM_ERROR_MESSAGE}")
elseif(_LLVM_ERROR_MESSAGE)
message(STATUS "Could not find LLVM: ${_LLVM_ERROR_MESSAGE}")
endif()
if (LLVM_FOUND)
message(STATUS "Found LLVM (version: ${LLVM_VERSION}): (using ${LLVM_CONFIG_EXECUTABLE})")
message(STATUS " Include dirs: ${LLVM_INCLUDE_DIRS}")
message(STATUS " LLVM libraries: ${LLVM_LIBS}")
message(STATUS " LLVM System libraries: ${LLVM_SYSTEM_LIBS}")
endif()
# PLUGIN STUFF HERE
set(LIBRARY_NAME xacc-scaffold)
configure_file(ScaffCompiler.in.cpp ${CMAKE_BINARY_DIR}/compiler/ScaffCompiler.cpp)
set(SRC SCAFFCompilerActivator.cpp ${CMAKE_BINARY_DIR}/compiler/ScaffCompiler.cpp)
usfunctiongetresourcesource(TARGET ${LIBRARY_NAME} OUT SRC)
usfunctiongeneratebundleinit(TARGET ${LIBRARY_NAME} OUT SRC)
add_library(${LIBRARY_NAME} SHARED ${SRC})
target_include_directories(${LIBRARY_NAME} PUBLIC . ${XACC_INCLUDE_DIRS})
target_link_libraries(${LIBRARY_NAME} PUBLIC xacc CppMicroServices)
set(_bundle_name xacc_scaffold)
set_target_properties(${LIBRARY_NAME}
PROPERTIES COMPILE_DEFINITIONS
US_BUNDLE_NAME=${_bundle_name}
US_BUNDLE_NAME
${_bundle_name})
usfunctionembedresources(TARGET
${LIBRARY_NAME}
WORKING_DIRECTORY
${CMAKE_CURRENT_SOURCE_DIR}
FILES
manifest.json)
install(TARGETS ${LIBRARY_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/plugins)
add_subdirectory(tests)
#add_subdirectory(clang)
\ No newline at end of file
#include "ScaffCompiler.hpp"
// FIXME WHAT IF QCOR not installed???
#ifdef QCOR_EXISTS
#include "ScaffoldPragmaHandler.hpp"
#endif
#include "cppmicroservices/BundleActivator.h"
#include "cppmicroservices/BundleContext.h"
#include <memory>
#include <set>
using namespace cppmicroservices;
namespace {
/**
*/
class US_ABI_LOCAL SCAFFActivator : public BundleActivator {
public:
SCAFFActivator() {}
/**
*/
void Start(BundleContext context) {
auto s = std::make_shared<scaffold::ScaffCompiler>();
context.RegisterService<xacc::Compiler>(s);
#ifdef QCOR_EXISTS
auto ph = std::make_shared<scaffold::compiler::ScaffoldPragmaHandler>();
context.RegisterService<qcor::compiler::QCORPragmaHandler>(ph);
#endif
}
/**
*/
void Stop(BundleContext /*context*/) {}
};
} // namespace
CPPMICROSERVICES_EXPORT_BUNDLE_ACTIVATOR(SCAFFActivator)
/***********************************************************************************
*
* Contributors:
* Initial API and implementation - Alex McCaskey, Amrut Nadgir
*
**********************************************************************************/
#ifndef COMPILER_SCAFFCOMPILER_HPP_
#define COMPILER_SCAFFCOMPILER_HPP_
#include "XACC.hpp"
using namespace xacc;
namespace scaffold {
/**
* The PyXACCCompiler is an XACC Compiler that compiles
* python-like gate instruction source code to produce a
* XACC IR.
*/
class ScaffCompiler : public xacc::Compiler {
public:
/**
* The Compiler.
*/
ScaffCompiler() {}
/*
* Erase First Occurrence of given substring from main string.
*/
std::string eraseSubStr(std::string mainStr, const std::string toErase) {
// Search for the substring in string
size_t pos = mainStr.find(toErase);
if (pos != std::string::npos) {
// If found then erase it from string
mainStr.erase(pos, toErase.length());
}
return mainStr;
}
/**
* Helper function for the compile method.
* Takes in source string and writes to a scaffold file.
* @param src The source code