Skip to content

Commit

Permalink
Documentation and Cleanup for Release (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
idavis authored Nov 24, 2021
1 parent c68d735 commit e32984b
Show file tree
Hide file tree
Showing 32 changed files with 804 additions and 206 deletions.
8 changes: 6 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
name: CI
on:
push:
branches: [ $default-branch ]
branches:
- main
pull_request:
branches: [ $default-branch ]
branches:
- main
- feature/*
- features/*

env:
CARGO_TERM_COLOR: always
Expand Down
21 changes: 20 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,21 @@
# PyQIR: Python APIs for QIR
# PyQIR

PyQIR is a set of APIs for generating, parsing, and evaluating [Quantum Intermediate Representation (QIR)](https://github.com/microsoft/qsharp-language/tree/main/Specifications/QIR#quantum-intermediate-representation-qir).

- [pyqir-generator](./pyqir-generator/README.md) : Python API for generating QIR ([bitcode](https://www.llvm.org/docs/BitCodeFormat.html#id10) and [IR](https://llvm.org/docs/LangRef.html)).
- Examples
- [Bernstein-Vazirani](examples/generator/bernstein_vazirani.py)
- [Bell pair](examples/generator/bell_pair.py)
- [pyqir-jit](./pyqir-jit/README.md) : Python API for evaluating QIR using [JIT compilation](https://en.wikipedia.org/wiki/Just-in-time_compilation).
- Examples
- [Bernstein-Vazirani](examples/jit/bernstein_vazirani.py)
- [pyqir-parser](./pyqir-parser/README.md) : Python API for parsing QIR into an object model for analysis.
- [qirlib](./qirlib/README.md): Rust library wrapping [LLVM](https://llvm.org/) libraries for working with QIR.

## Documentation

- [Installing PyQIR](./docs/installing.md)
- [Building PyQIR from source](./docs/building.md)
- [Compatibility](./docs/compatibility.md)

## Installation
125 changes: 125 additions & 0 deletions docs/building.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# Building PyQIR from Source

## Local Environment

### Requirements

- [Rust 1.56+](https://rustup.rs/)
- [Python 3.6+](https://www.python.org)
- [PowerShell 7+ (Core)](https://github.com/powershell/powershell#get-powershell)
- [LLVM/Clang 11.1.0](https://llvm.org/) - See [Installing LLVM](#installing-llvm)

### Linux (Ubuntu)

Install python and libs:

```bash
sudo apt-get install -y --no-install-recommends python3-dev python3-pip
python3 -m pip install --user -U pip
python3 -m pip install --user maturin tox
```

Install Rust from [rustup](https://rustup.rs/).

### Windows

Install Python 3.6+ from one of the following and make sure it is added to the path.
- [Windows store](https://docs.microsoft.com/en-us/windows/python/beginners#install-python)
- [Miniconda](https://docs.conda.io/en/latest/miniconda.html#latest-miniconda-installer-links)
- [Python.org](https://www.python.org/downloads/)

In a command prompt:

```bash
python -m pip install --user maturin tox
```

Install Rust from [rustup](https://rustup.rs/).

### MacOS

Install Python 3.6+ from [Python.org](https://www.python.org/downloads/macos/).

or brew:
```
brew install '[email protected]'
python -m pip install --user maturin tox
```

Install Rust from [rustup](https://rustup.rs/).

### Installing Clang

If you have a working installation of LLVM and [Clang](https://clang.llvm.org/), each project can be built by running `cargo build` in the project directory. If not, you can install Clang manually:

- Linux (Ubuntu)
- ```
apt-get update
apt-get install -y clang-11 lldb-11 lld-11 clangd-11
```
- Windows
- Download and install the `LLVM-11.1.0-win64.exe` from the [11.1.0 Release](https://github.com/llvm/llvm-project/releases/tag/llvmorg-11.1.0) page.
- This package only contains the Clang components. There is no package that contains Clang and LLVM.
- MacOS
- Should be preinstalled.
### Installing LLVM
The build scripts will automatically download an LLVM toolchain which is detailed in the [Development](#development) section. The build installs the toolchain to `$HOME/.pyqir` (Windows: `$HOME\.pyqir`) and configures Rust to use this installation by setting the `LLVM_SYS_110_PREFIX` environment variable in the root `.cargo/config.toml`
## Development
Running `build.(ps1|sh|cmd)` will initialize your local environment and build the solution. The [Environment Variables](#environment-variables) section details ways to change this behavior.
Within each project folder, the build can be run specifically for that project.
Build commands:
- `maturin build`: Build the crate into python packages
- `maturin build --release`: Build and pass --release to cargo
- `maturin build --help`: to view more options
- `maturin develop`: Installs the crate as module in the current virtualenv
- `maturin develop && pytest`: Installs the crate as module in the current virtualenv and runs the Python tests
If you do not wish to package and test the Python wheels, `cargo` can be used to build the project and run Rust tests.
- `cargo build`: Build the Rust cdylib
- `cargo build --release`: Build the Rust cdylib in release mode
- `cargo test`: Build and run the Rust cdylib tests
- `cargo test --release`: Build and run the Rust cdylib tests in release mode
[Tox](https://tox.readthedocs.io/) can be used as well:
Two targets are available for tox:
- `python -m tox -e test`
- Runs the python tests in an isolated environment
- `python -m tox -e pack`
- Packages all wheels in an isolated environment
### Environment Variables
- `PYQIR_LLVM_EXTERNAL_DIR`
- Path to where LLVM is already installed by user. Useful if you want to use your own LLVM builds for testing.
- `PYQIR_DOWNLOAD_LLVM`
- Indicator to whether the build should download LLVM cached builds.
- Build will download LLVM if needed unless this variable is defined and set to `false`
- `PYQIR_LLVM_BUILDS_URL`
- Url from where LLVM builds will be downloaded.
- Default: `https://msquantumpublic.blob.core.windows.net/llvm-builds`
- `PYQIR_CACHE_DIR`
- Root insallation path for LLVM builds
- Default if not specified:
- Linux/Mac: `$HOME/.pyqir`
- Windows: `$HOME\.pyqir`
- `LLVM_SYS_110_PREFIX`
- Required by `llvm-sys` and will be set to the version of LLVM used for configuration.
- Version dependent and will change as LLVM is updated. (`LLVM_SYS_120_PREFIX`, `LLVM_SYS_130_PREFIX`, etc)
- Not needed if you have a working LLVM installation on the path.
### Packaging
The `build.(ps1|sh|cmd)`, `maturin`, and `tox` builds all generate Python wheels to the `target/wheels` folder. The default Python3 installation will be used targeting Python ABI 3.6.
The manylinux support uses a Docker image in the build scripts to run the builds in the CI environment.
The Windows packaging will look for python installations available and build for them. More information on [supporting multiple python versions on Windows](https://tox.readthedocs.io/en/latest/developers.html?highlight=windows#multiple-python-versions-on-windows)
29 changes: 29 additions & 0 deletions docs/compatibility.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# PyQIR compatible systems

## Operating systems

PyQIR runs on most x86-64 operating systems that can run Python 3.6+; however, not all of these systems are equally compatible. Operating systems are grouped into tiers that represent the level of compatibility users can expect.

* Tier 1 systems are compatible. For tier 1 systems:
* operating system is used in automated tests
* installation packages provided for them
* Tier 2 systems should be compatible with PyQIR and can be used relatively easily. For tier 2 systems:
* informal testing may have been done
* the packages for tier 1 systems will likely work in tier 2 systems

### Tier 1

- Windows Server 2019
- [Ubuntu 20.04](https://wiki.ubuntu.com/FocalFossa/ReleaseNotes)
- [Debian 9](https://www.debian.org/releases/stretch/)
- macOS 10.15

### Tier 2
- Windows 10
- Windows 11
- [Ubuntu 18.04](https://wiki.ubuntu.com/BionicBeaver/ReleaseNotes)
- [Debian 10](https://www.debian.org/releases/buster/)
- [Debian 11](https://www.debian.org/releases/bullseye/)
- macOS 10.7-14
- macOS 11
- macOS 12
4 changes: 4 additions & 0 deletions docs/installing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Installing PyQIR

This documentation will be updated soon.
In the meantime, instructions for how to build PyQIR from source can be found [here](building.md)
3 changes: 2 additions & 1 deletion eng/build.ps1
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@

# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

#Requires -PSEdition Core

<#
.SYNOPSIS
Build: Bootstraps psake and invokes the build.
Expand Down
9 changes: 5 additions & 4 deletions eng/psakefile.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ function Install-LlvmFromSource {
$Env:PKG_NAME = Get-PackageName
$Env:CMAKE_INSTALL_PREFIX = $packagePath
$Env:INSTALL_LLVM_PACKAGE = $true
Assert $false -failureMessage "TODO: Migration in progress"
. (Join-Path (Get-RepoRoot) "build" "llvm.ps1")
Use-LlvmInstallation $packagePath
}
Expand All @@ -172,18 +173,18 @@ function Initialize-Environment {
Use-ExternalLlvmInstallation
}
else {
$PYQIR_LLVM_PACKAGE_GIT_VERSION = Get-LlvmSha
Write-BuildLog "llvm-project sha: $PYQIR_LLVM_PACKAGE_GIT_VERSION"
$llvmSha = Get-LlvmSha
Write-BuildLog "llvm-project sha: $llvmSha"
$packageName = Get-PackageName

$packagePath = Get-InstallationDirectory $packageName
if (Test-Path $packagePath) {
Write-BuildLog "LLVM target $($PYQIR_LLVM_PACKAGE_GIT_VERSION) is already installed."
Write-BuildLog "LLVM target $($llvmSha) is already installed."
# LLVM is already downloaded
Use-LlvmInstallation $packagePath
}
else {
Write-BuildLog "LLVM target $($PYQIR_LLVM_PACKAGE_GIT_VERSION) is not installed."
Write-BuildLog "LLVM target $($llvmSha) is not installed."
if (Test-AllowedToDownloadLlvm) {
Write-BuildLog "Downloading LLVM target $packageName "
Install-LlvmFromBuildArtifacts $packagePath
Expand Down
14 changes: 2 additions & 12 deletions eng/utils.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -160,19 +160,9 @@ function Use-LlvmInstallation {
}

# Gets the LLVM version git hash
# on the CI this will come as an env var
function Get-LlvmSha {
# Sometimes the CI fails to initilize PYQIR_LLVM_PACKAGE_GIT_VERSION correctly
# so we need to make sure it isn't empty.
if ((Test-Path env:\PYQIR_LLVM_PACKAGE_GIT_VERSION) -and ![string]::IsNullOrWhiteSpace($Env:PYQIR_LLVM_PACKAGE_GIT_VERSION)) {
Write-BuildLog "Use environment submodule version: $($env:PYQIR_LLVM_PACKAGE_GIT_VERSION)"
$env:PYQIR_LLVM_PACKAGE_GIT_VERSION
}
else {
$sha = exec { Get-LlvmSubmoduleSha }
Write-BuildLog "Use cached submodule version: $sha"
$sha
}
$sha = exec { Get-LlvmSubmoduleSha }
$sha
}

function Get-PackageName {
Expand Down
41 changes: 41 additions & 0 deletions examples/generator/bell_pair.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/usr/bin/env python3

# Copyright(c) Microsoft Corporation.
# Licensed under the MIT License.

from pyqir_generator import QirBuilder


class BellPair:
"""
This operation creates a Bell pair and returns the result
of measuring each qubit.
"""

def __init__(self):
self.builder = QirBuilder("Bell")
self.apply()

def apply(self):
self.builder.add_quantum_register("qubit", 2)
self.builder.add_classical_register("output", 2)

self.builder.h("qubit0")
self.builder.cx("qubit0", "qubit1")

self.builder.m("qubit0", "output0")
self.builder.m("qubit1", "output1")

def write_ir_file(self, file_path: str):
self.builder.write(file_path)

def get_ir_string(self) -> str:
return self.builder.get_ir_string()

def generate_ir_file(file_path: str):
instance = BellPair()
instance.write(file_path)


if __name__ == "__main__":
print(BellPair().get_ir_string())
Loading

0 comments on commit e32984b

Please sign in to comment.