Skip to content

Commit

Permalink
Ac/dta2 270 implement pauli tracker (#150)
Browse files Browse the repository at this point in the history
* fix: save before help from PJ

* fix: save before help from PJ (again)

* Moving ruby slippers file into folder

* Replacing icmop with orquestra circuits

* Making julia functions compatible with orquestra circuit input and adding proxy for op_list

* fix: rbs with pauli tracker works

* fix: pauli tracker

* feat: commit before breaking rbs

* fix: old rbs tests

* feat: added sdk parallelization

* feat: faster temporal DAG creation

* fix: incorrect task imports

* fix: move wf definition

* fix: move wf definition again

* feat: slow space optimal

* feat: faster kahns algo

* fix: stuff

* fix: move tasks out of transformer

* feat: parallelized pipeline

* feat: rigetti instances

* fix: remove graph production method as input

* fix: problems

* feat: better low qubit counts

* fix: orquestra integration

* fix: commit before removing unneeded sections

* feat: better costing

* fix: updated new example to new api

Got rid of transpile to clifford + T usage as this should no longer be the defaut method.

* fix: examples run

* fix: some tests

* fix: more tests pass

* fix: graph estimator tests pass

* fix: sre_constants no longer fail tests

* fix: all tests pass

* fix: passes style

* fix: remove union from singledispatch

* fix: pyright issues

* fix: pyright issues

* fix: tests pass

* fix: line too long

* fix: simplified jabalizer integration

* fix: added choice to install jabalizer

* fix: azure example

* Updating pauli tracker docstring

* feat: resource breakdowns

* fix: merge conflicts

* fix: don't use jabalizer unless installed

* fix: added individual testing for stitching

* fix: tests pass

* feat: eliminate max independent set

---------

Co-authored-by: Peter Johnson <peter.d.johnson22@gmail.com>
Co-authored-by: Max Radin <radin.max@gmail.com>
  • Loading branch information
3 people authored May 15, 2024
1 parent 01970f7 commit adb12c5
Show file tree
Hide file tree
Showing 117 changed files with 7,791 additions and 4,998 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,6 @@ juliapkg.json

# igonore mlflow run files
*mlruns*

# ignore jabalizer files
jabalizer_temp/
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ style: flake8p mypy pyright black isort
@echo This project passes style!

test:
$(PYTHON) -m pytest -W error tests
$(PYTHON) -m pytest tests

coverage:
$(PYTHON) -m pytest -W error\
$(PYTHON) -m pytest \
--cov=src \
--cov-fail-under=$(MIN_COVERAGE) tests \
--no-cov-on-fail \
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ On some systems, the installation of PySCF can be problematic. If you're a Windo
#### Azure Quantum Resource Estimation
To run resource estimation using Azure Quantum Resource Estimation (QRE) tool, one needs to have Azure QRE package configure. See [this tutorial](https://learn.microsoft.com/en-us/azure/quantum/intro-to-resource-estimation) for more information.

#### Jabalizer
Jabalizer is an alternate graph state compilation toolchain to ruby slippers. To install Jabalizer, you will need to have the Rust programming language installed on your machine and run `pip install '.[jabalizer]'` from the top-level directory of this repository.

Jabalizer can provide drastically reduced resource counts for some circuits, but it is considerably slower than ruby slippers. It is recommended to use Jabalizer only for smaller circuits.

## Usage
See the [`examples`](examples) directory to learn more about how to use Bench-Q.

Expand Down
24 changes: 14 additions & 10 deletions benchmarks/test_get_qsp_program.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
import zipfile
from pathlib import Path

import openfermion
import pytest

from benchq.algorithms.time_evolution import _n_block_encodings_for_time_evolution
from benchq.problem_embeddings import get_qsp_program
from benchq.conversions import get_pyliqtr_operator
from benchq.problem_embeddings.qsp import get_qsp_program
from benchq.problem_ingestion import get_hamiltonian_from_file, get_vlasov_hamiltonian
from benchq.problem_ingestion.molecular_hamiltonians import (
get_hydrogen_chain_hamiltonian_generator,
Expand All @@ -27,9 +29,10 @@ def vlasov_test_case():
failure_tolerance = 1e-3

operator = get_vlasov_hamiltonian(k, alpha, nu, N)
pyliqtr_operator = get_pyliqtr_operator(operator)

n_block_encodings = _n_block_encodings_for_time_evolution(
operator, evolution_time, failure_tolerance
pyliqtr_operator, evolution_time, failure_tolerance
)

return pytest.param(operator, n_block_encodings, id="vlasov")
Expand All @@ -40,22 +43,23 @@ def jw_test_case():
failure_tolerance = 1e-3
n_hydrogens = 2

operator = get_hydrogen_chain_hamiltonian_generator(
n_hydrogens
).get_active_space_hamiltonian()
instance = generate_hydrogen_chain_instance(n_hydrogens)
interaction_operator = instance.get_active_space_hamiltonian()
jw_operator = openfermion.jordan_wigner(interaction_operator)
pyliqtr_jw_operator = get_pyliqtr_operator(jw_operator)

n_block_encodings = _n_block_encodings_for_time_evolution(
operator, evolution_time, failure_tolerance
pyliqtr_jw_operator, evolution_time, failure_tolerance
)

return pytest.param(
operator,
pyliqtr_jw_operator,
n_block_encodings,
id=f"jw-{n_hydrogens}",
)


def fast_load_test_cases():
def fast_load_hamiltonians():
evolution_time = 5
failure_tolerance = 1e-3
base_location = "./examples/data/"
Expand All @@ -74,7 +78,7 @@ def _load_hamiltonian(name):

return [
pytest.param(
(operator := _load_hamiltonian(name)),
(operator := get_pyliqtr_operator(_load_hamiltonian(name))),
_n_block_encodings_for_time_evolution(
operator, evolution_time, failure_tolerance
),
Expand All @@ -92,7 +96,7 @@ def _load_hamiltonian(name):
@pytest.mark.benchmark
@pytest.mark.parametrize(
"operator, n_block_encodings",
[vlasov_test_case(), jw_test_case(), *fast_load_test_cases()],
[vlasov_test_case(), jw_test_case(), *fast_load_hamiltonians()],
)
def test_get_qsp_program(benchmark, operator, n_block_encodings):
benchmark(get_qsp_program, operator, n_block_encodings)
3 changes: 2 additions & 1 deletion benchmarks/test_ruby_slippers_performance.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
import pytest
from orquestra.quantum.circuits import CNOT, RX, Circuit, H, S, X, Z

from benchq.compilation import jl, pyliqtr_transpile_to_clifford_t
from benchq.compilation.circuits import pyliqtr_transpile_to_clifford_t
from benchq.compilation.graph_states import jl


@pytest.mark.parametrize(
Expand Down
12 changes: 7 additions & 5 deletions benchmarks/test_substrate_scheduler_performance.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import networkx as nx
import pytest

from benchq.resource_estimators.graph_estimators import substrate_scheduler
from benchq.compilation.graph_states.substrate_scheduler.python_substrate_scheduler import (
python_substrate_scheduler,
)


@pytest.mark.parametrize("preset", ["fast", "optimized"])
Expand All @@ -13,7 +15,7 @@ class TestSubstrateScheduler:
@pytest.mark.parametrize("size", [10, 100, 1000])
def test_substrate_scheduler_timing(self, benchmark, graph, size, preset):
graph = graph(size)
benchmark(substrate_scheduler, graph, preset)
benchmark(python_substrate_scheduler, graph, preset)

@pytest.mark.parametrize(
"graph",
Expand All @@ -24,20 +26,20 @@ def test_substrate_scheduler_timing_with_pre_mapping_optimizer(
self, benchmark, graph, size, preset
):
graph = graph(size)
benchmark(substrate_scheduler, graph, preset)
benchmark(python_substrate_scheduler, graph, preset)

@pytest.mark.parametrize("chain_size", [10, 100])
@pytest.mark.parametrize("bell_size", [10, 100])
def test_substrate_scheduler_timing_barbell_graph(
self, benchmark, chain_size, bell_size, preset
):
graph = nx.barbell_graph(chain_size, bell_size)
benchmark(substrate_scheduler, graph, preset)
benchmark(python_substrate_scheduler, graph, preset)

@pytest.mark.parametrize("size", [10, 100])
@pytest.mark.parametrize("probablity_of_edge", [0.01, 0.1])
def test_substrate_scheduler_timing_erdos_renyi(
self, benchmark, size, probablity_of_edge, preset
):
graph = nx.erdos_renyi_graph(size, probablity_of_edge, seed=123)
benchmark(substrate_scheduler, graph, preset)
benchmark(python_substrate_scheduler, graph, preset)
5 changes: 2 additions & 3 deletions examples/data/single_rotation.qasm
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
OPENQASM 2.0;
include "qelib1.inc";
qreg q[4];
h q[0];
rz(0.20103392) q[0];
qreg q[1];
rx(0.20103392) q[0];
79 changes: 30 additions & 49 deletions examples/ex_11_utility_scale.py → examples/ex_10_utility_scale.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,27 @@
import datetime
import json
import os
import typing
import warnings
from pathlib import Path
from typing import Literal

from benchq.algorithms.time_evolution import qsp_time_evolution_algorithm
from benchq.compilation import get_ruby_slippers_compiler
from benchq.compilation.graph_states.circuit_compilers import (
get_ruby_slippers_circuit_compiler,
)
from benchq.compilation.graph_states.implementation_compiler import (
get_implementation_compiler,
)
from benchq.decoder_modeling import DecoderModel
from benchq.problem_ingestion.solid_state_hamiltonians.ising import (
generate_ising_hamiltonian_on_cubic_lattice,
generate_ising_hamiltonian_on_kitaev_lattice,
generate_ising_hamiltonian_on_triangular_lattice,
)
from benchq.quantum_hardware_modeling import DETAILED_ION_TRAP_ARCHITECTURE_MODEL
from benchq.resource_estimators.footprint_estimators.openfermion_estimator import (
footprint_estimator,
)
from benchq.resource_estimators.graph_estimators import (
ExtrapolationResourceEstimator,
create_big_graph_from_subcircuits,
get_custom_extrapolated_estimate,
remove_isolated_nodes,
transpile_to_native_gates,
from benchq.quantum_hardware_modeling import (
BASIC_SC_ARCHITECTURE_MODEL,
DETAILED_ION_TRAP_ARCHITECTURE_MODEL,
)
from benchq.resource_estimators.graph_estimator import GraphResourceEstimator
from benchq.resource_estimators.openfermion_estimator import openfermion_estimator


def get_resources(lattice_type: str, size: int, decoder_data_file: str):
Expand All @@ -38,60 +35,44 @@ def get_resources(lattice_type: str, size: int, decoder_data_file: str):
else:
raise ValueError(f"Lattice type {lattice_type} not supported")

architecture_model = DETAILED_ION_TRAP_ARCHITECTURE_MODEL
architecture_model = BASIC_SC_ARCHITECTURE_MODEL

print("Getting algorithm implementation...")
evolution_time = 1
failure_tolerance = 1e-4
failure_tolerance = 1e-3
algorithm_implementation = qsp_time_evolution_algorithm(
operator, evolution_time, failure_tolerance
)

print("Setting resource estimation parameters...")
decoder_model = DecoderModel.from_csv(decoder_data_file)
my_estimator = ExtrapolationResourceEstimator(
architecture_model,
[2, 4, 6, 8, 10],
n_measurement_steps_fit_type="logarithmic",
optimization="space",
decoder_model=decoder_model,
circuit_compiler = get_ruby_slippers_circuit_compiler(
teleportation_threshold=80, optimal_dag_density=10
)

# select teleportation threshold to tune number of logical qubits
if lattice_type == "triangular":
gpm = get_ruby_slippers_compiler(teleportation_threshold=70)
elif lattice_type == "kitaev":
gpm = get_ruby_slippers_compiler(teleportation_threshold=60)
elif lattice_type == "cubic":
gpm = get_ruby_slippers_compiler(teleportation_threshold=70)
else:
raise ValueError(f"Lattice type {lattice_type} not supported")
implementation_compiler = get_implementation_compiler(
circuit_compiler, destination="single-thread"
)
estimator = GraphResourceEstimator(optimization="Space", verbose=True)

print("Estimating resources via graph state compilation...")
gsc_resources = get_custom_extrapolated_estimate(
gsc_resources = estimator.compile_and_estimate(
algorithm_implementation,
my_estimator,
transformers=[
transpile_to_native_gates,
create_big_graph_from_subcircuits(gpm),
remove_isolated_nodes,
],
)

total_t_gates = my_estimator.get_n_total_t_gates(
gsc_resources.extra.n_t_gates,
gsc_resources.extra.n_rotation_gates,
algorithm_implementation.error_budget.transpilation_failure_tolerance,
implementation_compiler,
architecture_model,
decoder_model,
)

total_t_gates = algorithm_implementation.n_t_gates_after_transpilation
hw_tolerance = algorithm_implementation.error_budget.hardware_failure_tolerance
footprint_resources = footprint_estimator(

footprint_resources = openfermion_estimator(
algorithm_implementation.program.num_data_qubits,
num_t=total_t_gates,
architecture_model=my_estimator.hw_model,
architecture_model=architecture_model,
hardware_failure_tolerance=hw_tolerance,
decoder_model=decoder_model,
)

return gsc_resources, footprint_resources


Expand Down Expand Up @@ -138,7 +119,7 @@ def main(
save_results = False
path_to_save_results = "."

utiliy_scale_problems: typing.Dict[
utility_scale_problems: typing.Dict[
Literal["triangular", "kitaev", "cubic"], int
] = {"triangular": 30, "kitaev": 22, "cubic": 10}

Expand All @@ -152,7 +133,7 @@ def main(
decoder_data,
save_results,
lattice_type,
utiliy_scale_problems[lattice_type],
utility_scale_problems[lattice_type],
path_to_save_results,
)

Expand Down
42 changes: 14 additions & 28 deletions examples/ex_1_from_qasm.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,14 @@

import os

from orquestra.integrations.qiskit.conversions import import_from_qiskit
from qiskit.circuit import QuantumCircuit

from benchq.algorithms.data_structures import AlgorithmImplementation, ErrorBudget
from benchq.problem_embeddings import get_program_from_circuit
from benchq.quantum_hardware_modeling import BASIC_SC_ARCHITECTURE_MODEL
from benchq.resource_estimators.graph_estimators import (
GraphResourceEstimator,
create_big_graph_from_subcircuits,
get_custom_resource_estimation,
synthesize_clifford_t,
transpile_to_native_gates,
from benchq.compilation.graph_states.implementation_compiler import (
get_implementation_compiler,
)
from benchq.quantum_hardware_modeling import BASIC_SC_ARCHITECTURE_MODEL
from benchq.resource_estimators.graph_estimator import GraphResourceEstimator


def main(file_name):
Expand All @@ -43,32 +38,23 @@ def main(file_name):
qiskit_circuit, error_budget, 1
)

# Here we run the resource estimation pipeline:
# Architecture model is used to define the hardware model.
architecture_model = BASIC_SC_ARCHITECTURE_MODEL

# Here we run the resource estimation pipeline.
# In this case before performing estimation we use the following transformers:
# 1. Simplify rotations – it is a simple transpilation that removes redundant
# rotations from the circuit, such as RZ(0) or RZ(2pi) and replaces RX and RY
# gates with RZs
# 2. Gate synthesis – replaces all RZ gates with Clifford+T gates
# 3. Create big graph from subcircuits – this transformer is used to create
# a graph from subcircuits. It is needed to perform resource estimation using
# the graph resource estimator. In this case we use delayed gate synthesis, as
# we have already performed gate synthesis in the previous step.
gsc_resource_estimates = get_custom_resource_estimation(
# Create the estimator object, we can optimize for "Time" or "Space"
estimator = GraphResourceEstimator(optimization="Time", verbose=True)
# Use the default compiler
compiler = get_implementation_compiler()
# Put all the pieces together to get a resource estimate
gsc_resource_estimates = estimator.compile_and_estimate(
algorithm_implementation,
estimator=GraphResourceEstimator(architecture_model),
transformers=[
transpile_to_native_gates,
synthesize_clifford_t(error_budget),
create_big_graph_from_subcircuits(),
],
compiler,
architecture_model,
)
print("Resource estimation results:")
print(gsc_resource_estimates)


if __name__ == "__main__":
current_directory = os.path.dirname(__file__)
main(current_directory + "/data/example_circuit.qasm")
main(current_directory + "/data/ghz_circuit.qasm")
Loading

0 comments on commit adb12c5

Please sign in to comment.