Skip to content

Commit

Permalink
Allow Generator object for seed in QuantumVolume circuit (#4867)
Browse files Browse the repository at this point in the history
* Fix RNG in QuantumVolume circuit

* Add seed back to circuit name

Note that if seed is a generator object the name contain [num_qubits, depth, Generator(PCG64)at<memory>]

* Add reno

* Add labels back to unitaries

This means we are not using the shared Generator object, but instead instantiating new generator objects with fixed integer seeds for each call to random_unitary.

* fixup

* Update releasenotes/notes/quantum_volume_rng-2e6f46e3821aebeb.yaml

Co-authored-by: Matthew Treinish <mtreinish@kortar.org>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
  • Loading branch information
3 people committed Aug 5, 2020
1 parent e9d29ee commit e4c3b39
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 13 deletions.
25 changes: 16 additions & 9 deletions qiskit/circuit/library/quantum_volume.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

"""Quantum Volume model circuit."""

from typing import Optional
from typing import Optional, Union

import numpy as np
from qiskit.quantum_info.random import random_unitary
Expand Down Expand Up @@ -62,30 +62,37 @@ class QuantumVolume(QuantumCircuit):
def __init__(self,
num_qubits: int,
depth: Optional[int] = None,
seed: Optional[int] = None,
seed: Optional[Union[int, np.random.Generator]] = None,
classical_permutation: bool = True) -> None:
"""Create quantum volume model circuit of size num_qubits x depth.
Args:
num_qubits: number of active qubits in model circuit.
depth: layers of SU(4) operations in model circuit.
seed: randomization seed.
seed: Random number generator or generator seed.
classical_permutation: use classical permutations at every layer,
rather than quantum.
"""
depth = depth or num_qubits # how many layers of SU(4)
width = int(np.floor(num_qubits/2)) # how many SU(4)s fit in each layer

# Initialize RNG
if seed is None:
rng_set = np.random.default_rng()
seed = rng_set.integers(low=1, high=1000)
if isinstance(seed, np.random.Generator):
rng = seed
else:
rng = np.random.default_rng(seed)

# Parameters
depth = depth or num_qubits # how many layers of SU(4)
width = int(np.floor(num_qubits/2)) # how many SU(4)s fit in each layer
name = "quantum_volume_" + str([num_qubits, depth, seed]).replace(' ', '')

super().__init__(num_qubits, name=name)

rng = np.random.default_rng(seed)

# Generator random unitary seeds in advance.
# Note that this means we are constructing multiple new generator
# objects from low-entropy integer seeds rather than pass the shared
# generator object to the random_unitary function. This is done so
# that we can use the integer seed as a label for the generated gates.
unitary_seeds = rng.integers(low=1, high=1000, size=[depth, width])

# For each layer, generate a permutation of qubits
Expand Down
5 changes: 5 additions & 0 deletions releasenotes/notes/quantum_volume_rng-2e6f46e3821aebeb.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
features:
- |
Allow passing in a Numpy random ``Generator`` object for the ``seed`` kwarg
in :class:`qiskit.circuit.library.QuantumVolume`.
17 changes: 13 additions & 4 deletions test/python/circuit/test_library.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,11 +274,20 @@ class TestQuantumVolumeLibrary(QiskitTestCase):

def test_qv(self):
"""Test qv circuit."""
circuit = QuantumVolume(2, 2, seed=2, classical_permutation=False)
seed = 10203
rng1 = np.random.default_rng(seed)
rng2 = np.random.default_rng(seed)

depth = 2
width = 1
circuit = QuantumVolume(2, depth, seed=rng1, classical_permutation=False)

expected = QuantumCircuit(2)
expected.swap(0, 1)
expected.append(random_unitary(4, seed=837), [0, 1])
expected.append(random_unitary(4, seed=262), [0, 1])
unitary_seeds = rng2.integers(low=1, high=1000, size=[depth, width])
for d in range(depth):
if rng2.permutation([0, 1]).tolist() == [1, 0]:
expected.swap(0, 1)
expected.append(random_unitary(4, seed=unitary_seeds[d][0]), [0, 1])
expected = Operator(expected)
simulated = Operator(circuit)
self.assertTrue(expected.equiv(simulated))
Expand Down

0 comments on commit e4c3b39

Please sign in to comment.