Skip to content

Commit

Permalink
Version 1.5 Release
Browse files Browse the repository at this point in the history
* JKQ QCEC now provides full Python bindings and is available on [PyPI](https://pypi.org/project/jkq.qcec/) (#2)
* Configuration options now also include optimization passes applied before equivalence checking
* New optimization `removeDiagonalGatesBeforeMeasure` (#4)
* removed `--extern` from git submodule update
* Updated README.md

Signed-off-by: Lukas Burgholzer <lukas.burgholzer@jku.at>
  • Loading branch information
burgholzer committed Oct 19, 2020
1 parent e2d83e7 commit edefee1
Show file tree
Hide file tree
Showing 15 changed files with 287 additions and 142 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ jobs:
- CIBW_MANYLINUX_X86_64_IMAGE="manylinux2014"
- CIBW_MANYLINUX_AARCH64_IMAGE="manylinux2014"
- CIBW_BUILD="cp3?-*"
- CIBW_SKIP="*-win32 *-manylinux_i686"
- CIBW_SKIP="*-win32 *-manylinux_i686 cp35-*"
- CIBW_BUILD_VERBOSITY=1
- CIBW_TEST_COMMAND="python -c \"from jkq import qcec\""
- CC=gcc CXX=g++
Expand Down
8 changes: 4 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
cmake_minimum_required(VERSION 3.10...3.16)
cmake_minimum_required(VERSION 3.10...3.19)
if(${CMAKE_VERSION} VERSION_LESS 3.12)
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
endif()

project(qcec
VERSION 1.4.5
VERSION 1.5.0
DESCRIPTION "A JKQ tool for quantum circuit equivalence checking (JKQ QCEC)"
LANGUAGES CXX)

Expand All @@ -27,11 +27,11 @@ macro(handle_submodule MODULENAME)
find_package(Git QUIET)
if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git" AND GIT_SUBMODULE)
message(STATUS "${MODULENAME} update")
execute_process(COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive --remote -- extern/${MODULENAME}
execute_process(COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive -- extern/${MODULENAME}
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 --recursive --remote -- extern/${MODULENAME} failed with ${GIT_SUBMOD_RESULT}.")
message(FATAL_ERROR "git submodule update --init --recursive -- extern/${MODULENAME} failed with ${GIT_SUBMOD_RESULT}.")
endif()
endif()

Expand Down
173 changes: 93 additions & 80 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
[![Build Status](https://travis-ci.com/iic-jku/qcec.svg?branch=master)](https://travis-ci.com/iic-jku/qcec)
[![codecov](https://codecov.io/gh/iic-jku/qcec/branch/master/graph/badge.svg)](https://codecov.io/gh/iic-jku/qcec)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![arXiv](https://img.shields.io/static/v1?label=arXiv&message=2004.08420&color=inactive)](https://arxiv.org/abs/2004.08420)
[![arXiv](https://img.shields.io/static/v1?label=arXiv&message=2009.02376&color=inactive)](https://arxiv.org/abs/2009.02376)
[![toolset: JKQ](https://img.shields.io/badge/toolset-JKQ-blue)](https://github.com/iic-jku/jkq)
[![PyPI](https://img.shields.io/pypi/v/jkq.qcec?logo=pypi&style=plastic)](https://pypi.org/project/jkq.qcec/)
[![Travis (.com) branch](https://img.shields.io/travis/com/iic-jku/qcec/master?logo=travis&style=plastic)](https://travis-ci.com/iic-jku/qcec)
[![Codecov branch](https://img.shields.io/codecov/c/github/iic-jku/qcec/master?label=codecov&logo=codecov&style=plastic)](https://codecov.io/gh/iic-jku/qcec)
![GitHub](https://img.shields.io/github/license/iic-jku/qcec?style=plastic)
[![arXiv](https://img.shields.io/static/v1?label=arXiv&message=2004.08420&color=inactive&style=plastic)](https://arxiv.org/abs/2004.08420)
[![arXiv](https://img.shields.io/static/v1?label=arXiv&message=2009.02376&color=inactive&style=plastic)](https://arxiv.org/abs/2009.02376)
[![toolset: JKQ](https://img.shields.io/badge/toolset-JKQ-blue?style=plastic)](https://github.com/iic-jku/jkq)

# JKQ QCEC - A JKQ tool for **Q**uantum **C**ircuit **E**quivalence **C**hecking

Expand Down Expand Up @@ -34,59 +35,93 @@ If you have any questions, feel free to contact us via [iic-quantum@jku.at](mail

## Usage

This tool can either be used as a **standalone executable** with command-line interface, or as a **library** for the incorporation in other projects. [Python bindings](#python-bindings) are available since version 1.4.5.
- The standalone executable is launched in the following way:
```commandline
qcec_app <PATH_TO_FILE_1> <PATH_TO_FILE_2> (--method <method>)
JKQ QCEC is mainly developed as a C++ library with a [commandline interface](#command-line-executable). However, using it in Python is as easy as
```bash
pip install jkq.qcec
```
and then in Python
```python
from jkq import qcec
qcec.verify(...)
```
where the `verify` function is defined as follows:
```python
"""
Interface to the JKQ QCEC tool for verifying quantum circuits
Params:
file1 – Path to first file (required)
file2 – Path to second file (required)
method – Equivalence checking method to use (reference | naive | *proportional* | lookahead | simulation | compilation flow)
tolerance – Numerical tolerance used during computation
nsims – Number of simulations to conduct (for simulation method)
fidelity – Fidelity limit for comparison (for simulation method)
csv – Create CSV string for result
statistics – Print statistics
swapGateFusion – Optimization pass reconstructing SWAP operations
singleQubitGateFusion – Optimization pass fusing consecutive single qubit gates
removeDiagonalGatesBeforeMeasure – Optimization pass removing diagonal gates before measurements
Returns:
JSON object containing results
"""
def verify(file1: Union[str, bytes, PathLike],
file2: Union[str, bytes, PathLike],
method: Method = Method.proportional,
tolerance: float = 1e-13,
nsims: int = 16,
fidelity: float = 0.999,
csv: bool = False,
statistics: bool = False,
swapGateFusion: bool = False,
singleQubitGateFusion: bool = False,
removeDiagonalGatesBeforeMeasure: bool = False) -> object
```
### Command-line Executable
JKQ QCEC also provides a **standalone executable** with command-line interface called `qcec_app`.
It provides the same options as the Python module as flags (e.g., `--ps` for printing statistics, or `--method <method>`for setting the method). Per default, this produces JSON formatted output.
If the `--csv` flag is present, a CSV entry according to the following header is printed
```csv
filename1;nqubits1;ngates1;filename2;nqubits2;ngates2;expectedEquivalent;equivalent;method;time;maxActive;nsims
```
For a full list of options, call `qcec_app --help`.

### Library Organisation
Internally the JKQ QCEC library works in the following way
- Import both input files into a `qc::QuantumComputation` object
```c++
std::string file1 = "<PATH_TO_FILE_1>";
qc::QuantumComputation qc1(file1);

std::string file2 = "<PATH_TO_FILE_2>";
qc::QuantumComputation qc2(file2);
```
where *\<method\>* is one of
- reference
- naive
- proportional (**default**)
- lookahead
- simulation
- compilationflow
An optional parameter ```--tol e``` allows to specify the numerical tolerance *e* (default: *1e-13*) used during the computation.
The ```simulation``` method has two optional parameters ```--nsims r``` and ```--fid F```, controlling the maximum number of simulations *r* (default: *16*) and the considered fidelity limit *F* (default *0.999*), respectively.
The executable performs the equivalence check and prints its result to the standard output. Per default, this produces JSON formatted output. Additional statistics (e.g., verification time, maximum number of nodes, required simulations, etc.) can be obtained by additionally providing the `--ps` flag.
If the `--csv` flag is present, a CSV entry according to the following header is printed
```csv
filename1;nqubits1;ngates1;filename2;nqubits2;ngates2;expectedEquivalent;equivalent;method;time;maxActive;nsims
```

- Internally the library works in the following way
- Import both input files into a `qc::QuantumComputation` object
```c++
std::string file1 = "<PATH_TO_FILE_1>";
qc::QuantumComputation qc1(file1);

std::string file2 = "<PATH_TO_FILE_2>";
qc::QuantumComputation qc2(file2);
```
- Instantiate an `ec::EquivalenceChecker` object with both circuits
```c++
ec::Method method = ec::{ Reference | Naive | Proportional | Lookahead };
auto eq = ec::ImprovedDDEquivalenceChecker(qc1, qc2, method);
```
or
```c++
auto eq = ec::PowerOfSimulationEquivalenceChecker(qc1, qc2);
```
or
```c++
auto eq = ec::CompilationFlowEquivalenceChecker(qc1, qc2);
```
- Perform the actual equivalence check
```c++
eq.check();
```
- Print the results
```c++
eq.printResult();
```
or access them through the ```eq.results``` member.
- Instantiate an `ec::EquivalenceChecker` object with both circuits
```c++
ec::Method method = ec::{ Reference | Naive | Proportional | Lookahead };
auto eq = ec::ImprovedDDEquivalenceChecker(qc1, qc2, method);
```
or
```c++
auto eq = ec::PowerOfSimulationEquivalenceChecker(qc1, qc2);
```
or
```c++
auto eq = ec::CompilationFlowEquivalenceChecker(qc1, qc2);
```
- Set configuration options, e.g.,
```c++
ec::Configuration config{};
config.printStatistics = true;
```
- Perform the actual equivalence check
```c++
eq.check(config);
```
- Print the results
```c++
ec.printJSONResult(config.printStatistics);
```
or access them through the ```eq.results``` member.

### System requirements

Expand Down Expand Up @@ -132,28 +167,6 @@ In order to build the library execute the following in the project's main direct
target_link_libraries(${TARGET_NAME} PRIVATE JKQ::qcec)
```
### Python Bindings
Running `pip install .` in the main project directory creates Python bindings for the JKQ QCEC tool. Then, using it in Python is as simple as:
```python
from jkq import qcec
qcec.verify({"file1": "<PATH_TO_FILE_1>", "file2:": "<PATH_TO_FILE_2>"})
```
The full list of parameters as described in [Usage](#usage) which can be passed to `qcec.verify(...)` as a Python dictionary, are:
```python
instance = {
"file1": "<PATH_TO_FILE_1>", # required
"file2": "<PATH_TO_FILE_2>", # required
"method": "proportional",
"tolerance": 1e-13,
"nsims": 16,
"fidelity": 0.999,
"statistics": False,
"csv": False,
}
```


## Reference
If you use our tool for your research, we will be thankful if you refer to it by citing the appropriate publication:
Expand Down
49 changes: 30 additions & 19 deletions apps/app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,30 @@
#include "PowerOfSimulationEquivalenceChecker.hpp"

void show_usage(const std::string& name) {
std::cerr << "Usage: " << name << " <PATH_TO_FILE_1> <PATH_TO_FILE_2> (--method <method>) " << std::endl;
std::cerr << "Supported file formats: " << std::endl;
std::cerr << " .real " << std::endl;
std::cerr << " .qasm " << std::endl;
std::cerr << " .tfc " << std::endl;
std::cerr << " .qc " << std::endl;
std::cerr << "Available methods: " << std::endl;
std::cerr << " reference " << std::endl;
std::cerr << " naive " << std::endl;
std::cerr << " proportional (default) " << std::endl;
std::cerr << " lookahead " << std::endl;
std::cerr << " simulation " << std::endl;
std::cerr << " compilationflow " << std::endl;
std::cerr << "Options: " << std::endl;
std::cerr << " --ps: Print statistics " << std::endl;
std::cerr << " --csv: Print results as csv string " << std::endl;
std::cerr << " --tol e (default 1e-13): Numerical tolerance used during computation " << std::endl;
std::cerr << " --nsims r (default 16): Number of simulations to conduct (for simulation method)" << std::endl;
std::cerr << " --fid F (default 0.999): Fidelity limit for comparison (for simulation method) " << std::endl;
std::cerr << "Usage: " << name << " <PATH_TO_FILE_1> <PATH_TO_FILE_2> (--method <method>) " << std::endl;
std::cerr << "Supported file formats: " << std::endl;
std::cerr << " .real " << std::endl;
std::cerr << " .qasm " << std::endl;
std::cerr << " .tfc " << std::endl;
std::cerr << " .qc " << std::endl;
std::cerr << "Available methods: " << std::endl;
std::cerr << " reference " << std::endl;
std::cerr << " naive " << std::endl;
std::cerr << " proportional (default) " << std::endl;
std::cerr << " lookahead " << std::endl;
std::cerr << " simulation " << std::endl;
std::cerr << " compilationflow " << std::endl;
std::cerr << "Result Options: " << std::endl;
std::cerr << " --ps: Print statistics " << std::endl;
std::cerr << " --csv: Print results as csv string " << std::endl;
std::cerr << "Verification Parameters: " << std::endl;
std::cerr << " --tol e (default 1e-13): Numerical tolerance used during computation " << std::endl;
std::cerr << " --nsims r (default 16): Number of simulations to conduct (for simulation method)" << std::endl;
std::cerr << " --fid F (default 0.999): Fidelity limit for comparison (for simulation method) " << std::endl;
std::cerr << "Optimization Options: " << std::endl;
std::cerr << " --swapGateFusion: reconstruct SWAP operations " << std::endl;
std::cerr << " --singleQubitGateFusion: fuse consecutive single qubit gates " << std::endl;
std::cerr << " --removeDiagonalGatesBeforeMeasure: remove diagonal gates before measurements " << std::endl;
}

int main(int argc, char** argv){
Expand Down Expand Up @@ -141,6 +146,12 @@ int main(int argc, char** argv){
show_usage(argv[0]);
return 1;
}
} else if (cmd == "--swapGateFusion") {
config.swapGateFusion = true;
} else if (cmd == "--singleQubitGateFusion") {
config.singleQubitGateFusion = true;
} else if (cmd == "--removeDiagonalGatesBeforeMeasure") {
config.removeDiagonalGatesBeforeMeasure = true;
} else {
show_usage(argv[0]);
return 1;
Expand Down
2 changes: 1 addition & 1 deletion extern/qfr
Submodule qfr updated from fb6386 to aa978a
6 changes: 0 additions & 6 deletions include/CompilationFlowEquivalenceChecker.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
#include <utility>

#include "ImprovedDDEquivalenceChecker.hpp"
#include "CircuitOptimizer.hpp"

namespace ec {
using CostFunction = std::function<unsigned short(const qc::OpType&, unsigned short)>;
Expand All @@ -25,11 +24,6 @@ namespace ec {
public:
CompilationFlowEquivalenceChecker(qc::QuantumComputation& qc1, qc::QuantumComputation& qc2, CostFunction costFunction = IBMCostFunction): ImprovedDDEquivalenceChecker(qc1, qc2), costFunction(std::move(costFunction)) {
method = results.method = CompilationFlow;
qc::CircuitOptimizer::swapGateFusion(qc1);
qc::CircuitOptimizer::singleGateFusion(qc1);

qc::CircuitOptimizer::swapGateFusion(qc2);
qc::CircuitOptimizer::singleGateFusion(qc2);
}

void check(const Configuration& config) override;
Expand Down
6 changes: 6 additions & 0 deletions include/EquivalenceChecker.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <chrono>

#include "QuantumComputation.hpp"
#include "CircuitOptimizer.hpp"
#include "EquivalenceCheckingResults.hpp"

#define DEBUG_MODE_EC 0
Expand All @@ -23,6 +24,11 @@ namespace ec {
bool printStatistics = false;
fp tolerance = CN::TOLERANCE;

// configuration options for optimizations
bool singleQubitGateFusion = false;
bool swapGateFusion = false;
bool removeDiagonalGatesBeforeMeasure = false;

// configuration options for PowerOfSimulation equivalence checker
double fidelity_limit = 0.999;
unsigned long long max_sims = 16;
Expand Down
2 changes: 1 addition & 1 deletion jkq/qcec/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ add_library(pybind11 ALIAS pybind11::pybind11)

add_subdirectory("${PROJECT_SOURCE_DIR}/extern/pybind11_json" "extern/pybind11_json")

pybind11_add_module(py${PROJECT_NAME} bindings.cpp EXCLUDE_FROM_ALL)
pybind11_add_module(py${PROJECT_NAME} bindings.cpp)
target_link_libraries(py${PROJECT_NAME} PUBLIC pybind11_json ${PROJECT_NAME})
Loading

0 comments on commit edefee1

Please sign in to comment.