Skip to content

Commit

Permalink
Merge pull request #542 from chriseclectic/openpulse-sim-rebase
Browse files Browse the repository at this point in the history
Add PulseSimulator feature branch to master
  • Loading branch information
chriseclectic authored Jan 24, 2020
2 parents f6e84e9 + afb13af commit 40d9037
Show file tree
Hide file tree
Showing 96 changed files with 15,503 additions and 16 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@
*.o
out/*
*.so
rhs*_op.pyx
*.pyc
*_skbuild*
*_cmake_test_compile*
*.whl
*.egg*
build/*
qiskit/providers/aer/backends/libomp.dylib

# Ignore macOS DS_Store
.DS_Store
Expand All @@ -33,4 +35,3 @@ test/.asv
docs/_build/
docs/stubs/
docs/api/

3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "src/third-party/headers/muparserx"]
path = src/third-party/headers/muparserx
url = https://github.com/beltoforion/muparserx
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Changelog](http://keepachangelog.com/en/1.0.0/).

Added
-----

- Added high level pulse simulator tests (\#379)
Changed
-------

Expand Down
55 changes: 48 additions & 7 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ set(AER_SIMULATOR_CPP_EXTERNAL_LIBS
"${AER_SIMULATOR_CPP_SRC_DIR}/third-party/headers"
"${AER_SIMULATOR_CPP_SRC_DIR}/third-party/macos/lib"
"${AER_SIMULATOR_CPP_SRC_DIR}/third-party/win64/lib"
"${AER_SIMULATOR_CPP_SRC_DIR}/third-party/linux/lib"
"${USER_LIB_PATH}")

# TODO: We may want to change the prefix path for all the environments
Expand Down Expand Up @@ -178,17 +179,54 @@ endif()

message(STATUS "BLAS library found: ${BLAS_LIBRARIES}")

message(STATUS "Looking for spdlog library...")
find_package(spdlog)
if(spdlog_FOUND)
message(STATUS "spdlog found.")
set(SPDLOG_LIB spdlog::spdlog)
else()
message(STATUS "spdlog not found.")
set(SPDLOG_LIB "")
endif()

message(STATUS "Uncompressing muparserx static library...")
if(MSVC)
set(PLATFORM "win64")
elseif(APPLE)
set(PLATFORM "macos")
elseif(UNIX)
set(PLATFORM "linux")
endif()
execute_process(COMMAND ${CMAKE_COMMAND} -E tar "xvfj" "${AER_SIMULATOR_CPP_SRC_DIR}/third-party/${PLATFORM}/lib/muparserx.7z"
WORKING_DIRECTORY "${AER_SIMULATOR_CPP_SRC_DIR}/third-party/${PLATFORM}/lib/")
set(MUPARSERX_LIB_PATH "${AER_SIMULATOR_CPP_SRC_DIR}/third-party/${PLATFORM}/lib")

find_library(MUPARSERX_LIB NAMES libmuparserx.a muparserx HINTS ${MUPARSERX_LIB_PATH})
if(${MUPARSERX_LIB} MATCHES "MUPARSERX_LIB-NOTFOUND")
message(FATAL_ERROR "No muparserx library found")
endif()
message(STATUS "Muparserx library found: ${MUPARSERX_LIB}")
get_muparserx_source_code()
# I keep this disabled on purpose, just in case I need to debug muparserx related problems
# file(GLOB MUPARSERX_SOURCES "${AER_SIMULATOR_CPP_SRC_DIR}/third-party/headers/muparserx/parser/*.cpp")


# Set dependent libraries
set(AER_LIBRARIES
${OPENMP_EXTERNAL_LIB}
${BLAS_LIBRARIES}
nlohmann_json
Threads::Threads
${CMAKE_DL_LIBS})
${OPENMP_EXTERNAL_LIB}
${BLAS_LIBRARIES}
nlohmann_json
Threads::Threads
${SPDLOG_LIB}
${CMAKE_DL_LIBS}
${MUPARSERX_LIB})

# Cython build is only enabled if building through scikit-build.
if(SKBUILD) # Terra Addon build
add_subdirectory(qiskit/providers/aer/openpulse/cy)
add_subdirectory(qiskit/providers/aer/openpulse/qutip_lite/cy)
add_subdirectory(qiskit/providers/aer/backends/wrappers)
add_subdirectory(src/simulators/open_pulse)
else() # Standalone build
add_executable(qasm_simulator ${AER_SIMULATOR_CPP_MAIN})
set_target_properties(qasm_simulator PROPERTIES
Expand All @@ -202,10 +240,13 @@ else() # Standalone build
target_link_libraries(qasm_simulator PRIVATE ${AER_LIBRARIES})
# Linter
# This will add the linter as part of the compiling build target
add_linter(qasm_simulator)
#add_linter(qasm_simulator)
endif()

# Tests
if(BUILD_TESTS)
add_subdirectory(test)
# These tests were meant to be as an example, or template for C++ specific
# code, but they're not being maintained, so we are disabling them until we
# have real C++ tests in the codebase.
# add_subdirectory(test)
endif()
4 changes: 3 additions & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@ recursive-include src *
recursive-include contrib *
include CMakeLists.txt
include cmake/*.cmake

# Exclude static libraries (they are all compressed with 7z)
exclude src/third-party/*/lib/*.a
exclude src/third-party/*/lib/*.lib
3 changes: 3 additions & 0 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ jobs:
python.version: '3.7'
steps:
- checkout: self
submodules: true
- task: UsePythonVersion@0
inputs:
versionSpec: '$(python.version)'
Expand Down Expand Up @@ -48,6 +49,8 @@ jobs:
Python38:
python.version: '3.8'
steps:
- checkout: self
submodules: true
- powershell: Write-Host "##vso[task.prependpath]$env:CONDA\Scripts"
displayName: Add conda to PATH
- script: conda create --yes --quiet --name qiskit-aer-$(Build.BuildNumber) python=%PYTHON_VERSION%
Expand Down
38 changes: 38 additions & 0 deletions cmake/compiler_utils.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ function(enable_cxx_compiler_flag_if_supported flag)
endif()
endfunction()


function(get_version version_str)
string(REPLACE "." ";" VERSION_LIST ${version_str})
list(GET VERSION_LIST 0 TMP_MAJOR_VERSION)
Expand All @@ -19,3 +20,40 @@ function(get_version version_str)
set(MINOR_VERSION ${TMP_MINOR_VERSION} PARENT_SCOPE)
set(PATCH_VERSION ${TMP_PATCH_VERSION} PARENT_SCOPE)
endfunction()


function(get_muparserx_source_code)
find_package(Git QUIET)
if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
# if we have cloned the sources, muparserx is a submodule, so we need
# to initialize it
if(EXISTS "${PROJECT_SOURCE_DIR}/.gitmodules")
# Update submodules as needed
message(STATUS "Submodule update")
execute_process(COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
RESULT_VARIABLE GIT_SUBMOD_RESULT)
if(NOT GIT_SUBMOD_RESULT EQUAL "0")
message(FATAL_ERROR "git submodule update --init failed with ${GIT_SUBMOD_RESULT}, please checkout submodules")
endif()
endif()
# Not comming from git, so probably: pip install https://...zip or similar.
# This time, we want to clone muparserx and change the latests stable release
elseif(GIT_FOUND)
execute_process(COMMAND ${GIT_EXECUTABLE} clone --branch v4.0.8 https://github.com/beltoforion/muparserx.git ${PROJECT_SOURCE_DIR}/src/third-party/headers/muparserx
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
RESULT_VARIABLE GIT_SUBMOD_RESULT)
if(NOT GIT_SUBMOD_RESULT EQUAL "0")
message(FATAL_ERROR "git clone failed with ${GIT_SUBMOD_RESULT},\
please checkout muparserx manually from https://github.com/beltoforion/muparserx.git and \
checkout latest stable relase")
endif()
# TODO: If there's no git, we have to get muparserx using other method (curl)
endif()

if(NOT EXISTS "${PROJECT_SOURCE_DIR}/src/third-party/headers/muparserx/CMakeLists.txt")
message(FATAL_ERROR "MuparserX doesn't exist! GIT_SUBMODULE was turned off or download failed.\
Please download MuparserX library from https://github.com/beltoforion/muparserx.git \
and checkout latest stable release")
endif()
endfunction()
60 changes: 60 additions & 0 deletions cmake/cython_utils.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
find_package(PythonExtensions REQUIRED)
find_package(Cython REQUIRED)
find_package(PythonLibs REQUIRED)
find_package(NumPy REQUIRED)

# Variables for input user data:
#
# CYTHON_USER_INCLUDE_DIRS:
# - For Cython modules that need to import some header file not in the paths, example:
# set(CYTHON_USER_INCLUDE_DIRS "/opt/my/include")
# CYTHON_USER_LIB_DIRS:
# - For Cython modules that need to link with external libs, example:
# set(CYTHON_USER_LIB_DIRS "/opt/my/lib")
# CYTHON_INSTALL_DIR:
# - Where to install the resulting shared libraries
# set(CYTHON_INSTALL_DIR "/opt/my/lib")


# Set default values
set(CYTHON_USER_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR})
unset(CYTHON_USER_LIB_DIRS)
set(CYTHON_INSTALL_DIR "qiskit/providers/aer/backends")

function(add_cython_module module)
add_cython_target(${module} ${module}.pyx CXX)
add_library(${module} MODULE ${module} ${ARGV1})
set_target_properties(${module} PROPERTIES
LINKER_LANGUAGE CXX
CXX_STANDARD 14)

if(APPLE)
set_target_properties(${module} PROPERTIES
LINK_FLAGS ${AER_LINKER_FLAGS})
endif()

# We only need to pass the linter once, as the codebase is the same for
# all controllers
# add_linter(target)
target_include_directories(${module}
PRIVATE ${AER_SIMULATOR_CPP_SRC_DIR}
PRIVATE ${AER_SIMULATOR_CPP_EXTERNAL_LIBS}
PRIVATE ${PYTHON_INCLUDE_DIRS}
PRIVATE ${NumPy_INCLUDE_DIRS}
PRIVATE ${CYTHON_USER_INCLUDE_DIRS})

target_link_libraries(${module}
${AER_LIBRARIES}
${PYTHON_LIBRARIES}
${CYTHON_USER_LIB_DIRS})

python_extension_module(${module}
FORWARD_DECL_MODULES_VAR fdecl_module_list)

python_modules_header(modules
FORWARD_DECL_MODULES_LIST ${fdecl_module_list})

include_directories(${modules_INCLUDE_DIRS})
# TODO Where to put the target files
install(TARGETS ${module} LIBRARY DESTINATION ${CYTHON_INSTALL_DIR})
endfunction()
Empty file added qiskit/__init__.pxd
Empty file.
Empty file added qiskit/providers/__init__.pxd
Empty file.
4 changes: 3 additions & 1 deletion qiskit/providers/aer/aerprovider.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from .backends.qasm_simulator import QasmSimulator
from .backends.statevector_simulator import StatevectorSimulator
from .backends.unitary_simulator import UnitarySimulator
from .backends.pulse_simulator import PulseSimulator


class AerProvider(BaseProvider):
Expand All @@ -31,7 +32,8 @@ def __init__(self, *args, **kwargs):
# Populate the list of Aer simulator providers.
self._backends = [QasmSimulator(provider=self),
StatevectorSimulator(provider=self),
UnitarySimulator(provider=self)]
UnitarySimulator(provider=self),
PulseSimulator(provider=self)]

def get_backend(self, name=None, **kwargs):
return super().get_backend(name=name, **kwargs)
Expand Down
113 changes: 113 additions & 0 deletions qiskit/providers/aer/backends/pulse_simulator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2018, 2019.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.
# pylint: disable=arguments-differ, missing-return-type-doc

"""
Qiskit Aer OpenPulse simulator backend.
"""

import uuid
import time
import datetime
import logging
from numpy import inf
from qiskit.result import Result
from qiskit.providers.models import BackendConfiguration, PulseDefaults
from .aerbackend import AerBackend
from ..aerjob import AerJob
from ..version import __version__
from ..openpulse.qobj.digest import digest_pulse_obj
from ..openpulse.solver.opsolve import opsolve

logger = logging.getLogger(__name__)


class PulseSimulator(AerBackend):
"""Aer OpenPulse simulator
"""
DEFAULT_CONFIGURATION = {
'backend_name': 'pulse_simulator',
'backend_version': __version__,
'n_qubits': 20,
'coupling_map': None,
'url': 'https://github.com/Qiskit/qiskit-aer',
'simulator': True,
'meas_levels': [0, 1, 2],
'local': True,
'conditional': True,
'open_pulse': True,
'memory': False,
'max_shots': 10**6,
'description': 'A pulse-based Hamiltonian simulator',
'gates': [],
'basis_gates': []
}

def __init__(self, configuration=None, provider=None):

# purpose of defaults is to pass assemble checks
self._defaults = PulseDefaults(qubit_freq_est=[inf],
meas_freq_est=[inf],
buffer=0,
cmd_def=[],
pulse_library=[])
super().__init__(self,
BackendConfiguration.from_dict(self.DEFAULT_CONFIGURATION),
provider=provider)

def run(self, qobj,
system_model,
backend_options=None,
validate=False):
"""Run a qobj on the backend."""
# Submit job
job_id = str(uuid.uuid4())
aer_job = AerJob(self, job_id, self._run_job, qobj, system_model,
backend_options, validate)
aer_job.submit()
return aer_job

def _run_job(self, job_id, qobj,
system_model,
backend_options,
validate):
"""Run a qobj job"""
start = time.time()
if validate:
self._validate(qobj, backend_options, noise_model=None)
# Send to solver
openpulse_system = digest_pulse_obj(qobj, system_model, backend_options)
results = opsolve(openpulse_system)
end = time.time()
return self._format_results(job_id, results, end - start, qobj.qobj_id)

def _format_results(self, job_id, results, time_taken, qobj_id):
"""Construct Result object from simulator output."""
# Add result metadata
output = {}
output['qobj_id'] = qobj_id
output['results'] = results
output['success'] = True
output["job_id"] = job_id
output["date"] = datetime.datetime.now().isoformat()
output["backend_name"] = self.name()
output["backend_version"] = self.configuration().backend_version
output["time_taken"] = time_taken
return Result.from_dict(output)

def defaults(self):
"""Return defaults.
Returns:
PulseDefaults: object for passing assemble.
"""
return self._defaults
1 change: 1 addition & 0 deletions qiskit/providers/aer/backends/qasm_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""
Qiskit Aer qasm simulator backend.
"""
Expand Down
Loading

0 comments on commit 40d9037

Please sign in to comment.