Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
5aacc06
module name
Feb 25, 2019
0e8786d
add random cliffords
Feb 26, 2019
fa0d17d
some progress towards the goal
Mar 3, 2019
57174a5
no message
Mar 4, 2019
d010da6
prototyping the sandwich
Mar 10, 2019
ea6552c
first go
Mar 11, 2019
f2d1614
no message
Mar 11, 2019
84d6b5d
Merge remote-tracking branch 'origin/master' into wholeness-n-implica…
Mar 11, 2019
b4e444f
Added notebook for personal dev.
kylegulshen Mar 12, 2019
52e5129
Minor formatting changes.
kylegulshen Mar 13, 2019
79478c2
Merge branch 'wholeness-n-implicate-order' of github.com:rigetti/fore…
kylegulshen Mar 13, 2019
d6dc3df
Copied dataclass definition over to nb.
kylegulshen Mar 18, 2019
9fdbd61
Merge remote-tracking branch 'origin/master' into wholeness-n-implica…
Mar 19, 2019
aa1bee3
Merge remote-tracking branch 'origin/master' into wholeness-n-implica…
Mar 21, 2019
19eaed6
update for new repo name
Mar 21, 2019
a775ecc
Merge branch 'wholeness-n-implicate-order' of github.com:rigetti/fore…
kylegulshen Mar 21, 2019
64d9423
Add dataclasses.
kylegulshen Mar 25, 2019
bc2d815
Merge remote-tracking branch 'origin/master' into wholeness-n-implica…
Apr 4, 2019
174329f
Merge branch 'wholeness-n-implicate-order' of github.com:rigetti/fore…
kylegulshen Apr 15, 2019
5384910
Refactored toward generative approach
kylegulshen Apr 19, 2019
9203242
simplify template
kylegulshen Jun 10, 2019
d70d5f6
Update rb functions and remove old code.
kylegulshen Jul 17, 2019
e9254bb
Merge branch 'master' into unified_vol
kylegulshen Jul 17, 2019
d5384fa
Get basic templates working.
kylegulshen Jul 17, 2019
4f8812b
Add dagger and data acquisition.
kylegulshen Jul 18, 2019
13ee647
Revert after accidental deletion.
kylegulshen Jul 19, 2019
082ec09
Expand support for patterns.
kylegulshen Jul 25, 2019
9aad290
Add x basis logic helpers and demo.
kylegulshen Jul 25, 2019
33d2fee
Add some helper method support, including for plotting.
kylegulshen Jul 25, 2019
32138bb
Demonstrate helpers in notebook.
kylegulshen Jul 25, 2019
40ec261
Clean up and add qaoa helpers.
kylegulshen Jul 29, 2019
5c08d8c
Provide some draft comments.
kylegulshen Aug 2, 2019
28229af
Analyze single circuit first, then average.
kylegulshen Aug 5, 2019
208df9b
Add basic plot of successes.
kylegulshen Aug 9, 2019
37c4701
Fix success plotting formatting.
kylegulshen Aug 12, 2019
0f0497e
Adjustments to plotting, add pareto plot, update notebook.
kylegulshen Aug 12, 2019
a87ce7e
Add sequence_transformations and some documentation.
kylegulshen Aug 13, 2019
ed48add
Pass standard arguments to sequence transforms.
kylegulshen Aug 13, 2019
1df0e09
Base success off lowerbound and correct pareto frontier.
kylegulshen Aug 15, 2019
e1e6e0d
Get quantum volume functional.
kylegulshen Aug 16, 2019
9d6f2e0
Update notebook
kylegulshen Aug 17, 2019
dea2adb
Move compilation from layers to sequence transform at end.
kylegulshen Aug 19, 2019
f7546b5
Merge branch 'master' into unified_vol
kylegulshen Aug 22, 2019
4598549
Move nb
kylegulshen Sep 10, 2019
5dbf466
remove nb
kylegulshen Sep 10, 2019
255ce08
Remove pattern, clean up some todos.
kylegulshen Sep 16, 2019
a16fbcc
Fix sampling repetitions.
kylegulshen Sep 16, 2019
94ccd55
Clean up and comment, remove some unnecessary methods.
kylegulshen Oct 7, 2019
1031bef
Merge branch 'master' into unified_vol
kylegulshen Oct 7, 2019
cf59cdb
Allow more flexible qv api and add qv test.
kylegulshen Nov 4, 2019
7550c22
Remove QAOA helpers.
kylegulshen Nov 12, 2019
c062b75
Docstring and whitespace adjustments.
kylegulshen Nov 12, 2019
4cadd0e
Cosmetic formatting changes.
kylegulshen Nov 25, 2019
c695d73
Restructure into multiple files under volumetrics folder.
kylegulshen Nov 25, 2019
fcca3d3
Import main and templates from init.
kylegulshen Nov 25, 2019
55fa2f5
Correct init import.
kylegulshen Nov 25, 2019
e0abf94
replace missing reset and measure imports in main.
kylegulshen Nov 25, 2019
19794a2
Update notebook with new import scheme.
kylegulshen Nov 25, 2019
f705768
Update test imports.
kylegulshen Nov 25, 2019
ae79fc9
Merge branch 'master' into unified_vol
kylegulshen Nov 25, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2,067 changes: 2,067 additions & 0 deletions docs/examples/volumetrics.ipynb

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions forest/benchmarking/compilation.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,8 @@ def basic_compile(program: Program):
new_prog += _H(inst.qubits[0])
elif inst.name == "X":
new_prog += _X(inst.qubits[0])
elif inst.name == "Z":
new_prog += RZ(pi, inst.qubits[0])
elif inst.name in [gate.name for gate in new_prog.defined_gates]:
if needs_dagger and inst.name not in daggered_defgates:
new_prog.defgate(inst.name + 'DAG', inst.matrix.T.conj())
Expand Down
34 changes: 34 additions & 0 deletions forest/benchmarking/tests/test_volumetrics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import numpy as np
from pyquil.numpy_simulator import NumpyWavefunctionSimulator

from forest.benchmarking.volumetrics import *
from forest.benchmarking.volumetrics.quantum_volume import (collect_heavy_outputs,
get_success_probabilities,
calculate_success_prob_est_and_err)

np.random.seed(1)


def test_ideal_sim_heavy_probs(qvm):
qvm.qam.random_seed = 1

qv_ckt_template = get_quantum_volume_template()
depths = [2, 3]
dimensions = {d: [d] for d in depths}

num_ckt_samples = 40
qv_progs = generate_volumetric_program_array(qvm, qv_ckt_template, dimensions,
num_circuit_samples=num_ckt_samples)
wfn_sim = NumpyWavefunctionSimulator(len(qvm.qubits()))
heavy_outputs = collect_heavy_outputs(wfn_sim, qv_progs)

num_shots = 50
results = acquire_volumetric_data(qvm, qv_progs, num_shots=num_shots)

probs_by_width_depth = get_success_probabilities(results, heavy_outputs)
num_successes = [sum(probs_by_width_depth[depth][depth]) * num_shots for depth in depths]

qv_success_probs = [calculate_success_prob_est_and_err(n_success, num_ckt_samples, num_shots)[0]
for n_success in num_successes]
target_probs = [0.788765, 0.852895]
np.testing.assert_allclose(qv_success_probs, target_probs, atol=.05)
2 changes: 2 additions & 0 deletions forest/benchmarking/volumetrics/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from forest.benchmarking.volumetrics._main import *
from forest.benchmarking.volumetrics._templates import *
143 changes: 143 additions & 0 deletions forest/benchmarking/volumetrics/_generators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
from typing import Sequence, List
import networkx as nx
import numpy as np
import random

from pyquil.quilbase import Pragma, Gate, DefGate, DefPermutationGate
from pyquil.quilatom import QubitPlaceholder
from pyquil.quil import Program, address_qubits, merge_programs
from pyquil.api import BenchmarkConnection
from pyquil.gates import *

from forest.benchmarking.randomized_benchmarking import get_rb_gateset
from forest.benchmarking.operator_tools.random_operators import haar_rand_unitary


def random_single_qubit_gates(graph: nx.Graph, gates: Sequence[Gate]) -> Program:
"""
Create a program comprised of random single qubit gates acting on the qubits of the
specified graph; each gate is chosen uniformly at random from the list provided.

:param graph: The graph. Nodes are used as arguments to gates, so they should be qubit-like.
:param gates: A list of gates e.g. [I, X, Z] or [I, X].
:return: A program that randomly places single qubit gates on a graph.
"""
program = Program()
for q in graph.nodes:
gate = random.choice(gates)
program += gate(q)
return program


def random_two_qubit_gates(graph: nx.Graph, gates: Sequence[Gate]) -> Program:
"""
Create a program to randomly place two qubit gates on edges of the specified graph.

:param graph: The graph. Nodes are used as arguments to gates, so they should be qubit-like.
:param gates: A list of gates e.g. [I otimes I, CZ] or [CZ, SWAP, CNOT]
:return: A program that has two qubit gates randomly placed on the graph edges.
"""
program = Program()
# TODO: two coloring with pragmas
for a, b in graph.edges:
gate = random.choice(gates)
program += gate(a, b)
return program


def random_single_qubit_cliffords(bm: BenchmarkConnection, graph: nx.Graph) -> Program:
"""
Create a program comprised of single qubit Clifford gates randomly placed on the nodes of
the specified graph. Each uniformly random choice of Clifford is implemented in the native
gateset.

:param bm: A benchmark connection that will do the grunt work of generating the Cliffords
:param graph: The graph. Nodes are used as arguments to gates, so they should be qubit-like.
:return: A program that randomly places single qubit Clifford gates on a graph.
"""
num_qubits = len(graph.nodes)

q_placeholder = QubitPlaceholder()
gateset_1q = get_rb_gateset([q_placeholder])

# the +1 is because the depth includes the inverse
clif_n_inv = bm.generate_rb_sequence(depth=(num_qubits + 1), gateset=gateset_1q, seed=None)
rand_cliffords = clif_n_inv[0:num_qubits]

prog = Program()
for q, clif in zip(graph.nodes, rand_cliffords):
gate = address_qubits(clif, qubit_mapping={q_placeholder: q})
prog += gate
return prog


def random_two_qubit_cliffords(bm: BenchmarkConnection, graph: nx.Graph) -> Program:
"""
Write a program to place random two qubit Clifford gates on edges of the graph.

:param bm: A benchmark connection that will do the grunt work of generating the Cliffords
:param graph: The graph. Nodes are used as arguments to gates, so they should be qubit-like.
:return: A program that has two qubit gates randomly placed on the graph edges.
"""
num_2q_gates = len(graph.edges)
q_placeholders = QubitPlaceholder.register(n=2)
gateset_2q = get_rb_gateset(q_placeholders)

# the +1 is because the depth includes the inverse
clif_n_inv = bm.generate_rb_sequence(depth=(num_2q_gates + 1), gateset=gateset_2q, seed=None)
rand_cliffords = clif_n_inv[0:num_2q_gates]

prog = Program()
# TODO: two coloring with PRAGMAS?
# TODO: longer term, fence to be 'simultaneous'?
for edges, clif in zip(graph.edges, rand_cliffords):
gate = address_qubits(clif, qubit_mapping={q_placeholders[0]: edges[0],
q_placeholders[1]: edges[1]})
prog += gate
return prog


def dagger_previous(sequence: List[Program], n: int = 1) -> Program:
"""
Create a program which is the inverse (conjugate transpose; adjoint; dagger) of the last n
layers of the provided sequence.

:param sequence: a sequence of PyQuil programs whose elements are layers in a circuit
:param n: the number of layers at the end of the sequence that will be inverted
:return: a program that inverts the last n layers of the provided sequence.
"""
return merge_programs(sequence[-n:]).dagger()


def random_su4_pairs(graph: nx.Graph, idx_label: int) -> Program:
"""
Create a program that enacts a Haar random 2 qubit gate on random pairs of qubits in the
graph, irrespective of graph topology.

If the graph contains an odd number of nodes, then one random qubit will not be acted upon by
any gate.

The output program will need to be compiled into native gates.

This generator is the repeated unit of the quantum volume circuits described in [QVol]_. Note
that the qubit permutation is done implicitly--the compiler will have to figure out how to
move potentially distant qubits onto a shared edge in order to enact the random two qubit gate.

:param graph: a graph containing qubits that will be randomly paired together. Note that
the graph topology (the edges) are ignored.
:param idx_label: a label that uniquely identifies the set of gate definitions used in the
output program. This prevents subsequent calls to this method from producing a program
with definitions that overwrite definitions in previously generated programs.
:return: a program with random two qubit gates between random pairs of qubits.
"""
qubits = list(graph.nodes)
qubits = [qubits[idx] for idx in np.random.permutation(range(len(qubits)))]
prog = Program()
# ignore the edges in the graph
for q1, q2 in zip(qubits[::2], qubits[1::2]):
matrix = haar_rand_unitary(4)
gate_definition = DefGate(f"LYR{idx_label}_RSU4_{q1}_{q2}", matrix)
RSU4 = gate_definition.get_constructor()
prog += gate_definition
prog += RSU4(q1, q2)
return prog
Loading