Skip to content

openqasm/qe-qasm

Repository files navigation

qe-qasm

The Quantum Engine's implementation of an OpenQASM v3.0 lexer and parser written in C++. The Quantum Engine is a system comprised of low-level software components enabling the execution of quantum programs in quantum hardware. The parser is based on Flex and Bison, and therefore it is a LALR parser.

This is a CMake Project. It builds four libraries:

  • libqasmParser.{so|a}
  • libqasmAST.{so|a}
  • libqasmFrontend.{so|a}
  • libqasmDIAG.{so|a}

and a simple CLI tool QasmParser for demonstrations and testing.

These libraries can be used to work on further development of a fully functional OpenQASM 3 compiler. In particular, the library is used by the qe-compiler to parse OpenQASM 3 source files to MLIR.

Contents

Building from source

The parser's build system is driven by Cmake. For simplicity of building, packaging and distribution we provide a conan packager and recommend this for development/integration.

Currently the supported platforms are Linux and OSX. It is possible to build on Windows using WSL.

Conan

  • Clone this repo: git clone git@github.com:openqasm/qe-qasm.git
  • Install build dependencies: pip install -r requirements-dev.txt
    • It is recommended to use a Python virtual environment for this
  • The package may be built and installed to conan with: conan create . --build=outdated -pr:h default -pr:b default
    • This will build the conan package and install it locally. The version will be detected automatically from the repo tag.
    • If you wish to override the package name, version or remote do so by calling conan with conan create . <package>/<version>@remote -pr:h default -pr:b default

Building for development and debugging

  • Create a build directory: mkdir build && cd build/
  • Install package with: conan install .. --build=outdated -pr:h default -pr:b default which will install and build all missing dependencies
  • Build the package with: conan build ..
  • The package tests may be run with: conan build .. --test

Make

  • Clone this repo: git clone git@github.com:openqasm/qe-qasm.git

  • Install build dependencies: pip install -r requirements-dev.txt

    • It is recommended to use a Python virtual environment for this
  • Install a recent GCC or LLVM/clang compiler that supports C++17, GNU MP, GNU MPFR, GNU MPC, GNU Flex and GNU Bison installed on your system. Please make sure you install the devel packages for GNU MP, GNU MPFR and GNU MPC.

    Recommended versions are:

    • GCC: >= 9.2
    • LLVM: >= 10.0
  • Install the package dependencies:

    • Versions:
    • Bison: >= 3.6.2
    • Flex: >= 2.6.1
    • GNU MP: >= 5.0.0
    • GNU MPFR: >= 4.0.0
    • GNU MPC >= 1.0.0
    • CMake: >= 3.17.0
    • Platforms:
      • Linux: Recent versions of Fedora (32 or 33) or Ubuntu (20.X.X) should satisfy these version requirements.

      • On Fedora (RedHat), the names of the packages are:

      • gmp(gmp-devel)

      • mpfr(mpfr-devel)

      • libmpc(libmpc-devel)

      • Apple Darwin (MacOS):

      • GCC is a symlink to clang. Building with GCC on MacOS is not supported.

      • You need XCode >= 14.2. Lower versions do not handle static initializations correctly on MacOS M1 (AArch64).

      • Most of the Toolchain utilities provided by Darwin by default in /usr/bin are much too old to be able to build qe-qasm correctly. Recent equivalents of these tools must be downloaded from Homebrew [ https://brew.sh/ ].

      • List of dependencies that must be installed from Homebrew:

        • flex
        • bison
        • gmake
        • cmake
        • gmp
        • mpfr
        • libmpc
        • m4
      • Please consult the Homebrew documentation on how to use Homebrew.

      • If you want to use the Homebrew LLVM: The LLVM lld linker [lld] needs a symlink created to itself in order to work correctly. To do so:

        • cd to the Homebrew LLVM installation directory:
          • /opt/homebrew/opt/llvm/bin on MacOS M1
          • /usr/local/opt/llvm/bin on MacOS x86_64
        • ln -sf lld ld64.lld
  • Prepare the build directory: mkdir build && cd build

  • Configure: cmake -G "Unix Makefiles" ..

    • If dependencies are not installed or properly setup errors may be raised
  • Build with: make

    • This will build both static and shared libraries
  • Running: make DESTDIR=/path/to/DESTDIR/ in the build directory will install the required libraries and header files to /path/to/DESTDIR/.

Running Tests

  • There are a number of OpenQASM 2.0 and OpenQASM 3.0 tests in the directory `./tests``.
  • You can run any of these tests manually as: ./QasmParser -I../../qasm/tests/include ../../qasm/tests/src/<test-name>.qasm from the 'build/bin' directory.
  • You can also run the ./short-run-tests.sh shell script found in the tests directory. It runs all the tests in the ../../tests/src directory. This script is intended to be run from the build/bin`` directory. Alternatively, you can run the 'make test' target from the toplevel build`` directory. This will run all the tests using the CMake CTest utility.
  • QasmParser will tell you if it could parse and generate the AST for the OpenQASM program correctly, or if it encountered an errror.
  • A pseudo-XML output of the AST being built by the parser will be printed either to stdout, or to the file used to capture QasmParser's output.

Static Code Checks

The easiest, fastest, and most automated way to integrate the formatting into your workflow is via pre-commit. Note that this tool requires an internet connection to initially setup because the formatting tools needs to be downloaded.

In environments without an internet connection, please see one of the other solutions documented below.

These should be installed and setup prior to any development work so that they are not forgotten about. The setup is straight forward:

pip install pre-commit
pre-commit install

The first time pre-commit install is run, it will take a minute to setup the environment.

After installation, the hooks will be run prior to every commit, and will be run against all staged changes. Optionally, you can trigger this run via pre-commit run.

If you wish to run the hooks against the entire repository, run:

pre-commit run --all-files

The other checks that are performed can be seen in .pre-commit-config.yaml. At the time of writing, these are:

  • No direct committing to main, or release/*
  • Check json for validity
  • Ensure newline character at the end of files
  • Trim end of line whitespace characters
  • Check for no merge conflict lines accidentally being staged
  • Clang format
  • Python block (line length 100)

CI and Release Cycle

Please keep the following points in mind when developing:

CI

CI is currently run on every pull request against the main branch. All CI processes are based on the conan package build.

Branches

  • main: The main branch is used for the development of the next release. It is updated frequently and should not be considered stable. On the development branch, breaking changes can and will be introduced. All efforts should be made to ensure that the development branch is maintained in a self-consistent state that is passing continuous integration (CI). Changes should not be merged unless they are verified by CI.
  • release/<major.minor> branches: Branches under release/<major.minor> are used to maintain released versions of the qe-qasm parser. They contain the version of the parser corresponding to the release as identified by its semantic version. For example, release/1.5 would be the compiler version for major version 1 and minor version 5. On these branches, the parser is considered stable. The only changes that may be merged to a release branch are patches/bugfixes. When a patch is required when possible the fix should first be made to the development branch through a pull request. The fix should then be backported from the development branch to the target release branch (of name release/<major.minor>) by creating a pull request on Github into the target release branch with the relevant cherry-picked commits. The new release branch HEAD should be tagged (see Tags) with a new <major.minor.patch> version and pushed to Github.

Tags

Git tags are used to tag the specific commit associated with a versioned release. Tags must take the form of v<major>.<minor>.<patch>-<labels>. For example the semver v1.5.1 would point to the parser release with major version 1, minor version 5, and, patch version 1. The current development version would therefore be MINOR+1 v1.6.0. All official releases when tagged must always point to the current HEAD of a release branch.

Release cycle

To release a version a new version:

  • (Option A) If releasing a major/minor version create a new release branch for the version (See Branches). This should be cut from the latest development branch.
    git checkout -b release/<version> <base>
    git push -u origin release/<version>
  • (Option B) If releasing a patch version:
    • checkout the existing release branch for your target major/minor version to apply the patch
    git checkout -b <backport>-<desc>-release/<version> release/<version>
    • Apply your changes (or cherry-pick existing commits) to your new branch and then push your branch to Github
    git push -u origin <your-branch>
    • Make a PR from your new branch into the target release/<version> branch with the form [Backport] <Title> and merge the PR
  • Create a new tag with the required semantic version number (see Tags), tagging the HEAD of the target release/<version> branch. Push the tag to Github which will trigger CI.
    git tag -a v<version> -m "<description> e.g. release v<x>.<y>.<z>" # <- where version is the version number of the tag.
    git push -u origin v<version>

Example release cycle

For this example assume the current release of the parser is version 0.5.1. This will correspond to a commit on release/0.5. The project's development branch reflects the development state of the next release - 0.6.0 and is referred to by version as 0.6.0-dev.

To trigger a bugfix release - 0.5.2:

  1. Create a PR into release/0.5 with all required changes. The PR ideally should begin with title of the form [Backport] <Title>. These may be backported commits from main.
  2. Upon merger of the PR tag the HEAD of release/0.5 with v0.5.2 and push to Github.

To trigger a minor release - 0.6.0:

  1. Create a new release branch release/0.6 using the current development branch (main) as the base branch, eg., git checkout -b release/0.6 main.
    • Note: Branch protection rules are in place for release branches and these steps may only be completed by project administrators.
  2. Push this branch to Github.
  3. Tag the branch with v0.6.0 and push to Github.