From 77d20f90a5d3c801cd5b097e4d7ed9a0f8c8c8d8 Mon Sep 17 00:00:00 2001 From: Josh Izaac Date: Fri, 18 Oct 2019 15:09:46 -0400 Subject: [PATCH 1/4] v0.6_update --- .github/CHANGELOG.md | 17 ++++++++++++ pennylane_pq/_version.py | 2 +- pennylane_pq/devices.py | 33 ++++++++++++++---------- requirements.txt | 2 +- setup.py | 2 +- tests/test_compare_with_default_qubit.py | 2 +- 6 files changed, 41 insertions(+), 17 deletions(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 564b76c..05db14b 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -1,3 +1,20 @@ +# Version 0.6.0 + +### Bug fixes + +* The way measurement statistics works has changed in the latest version of PennyLane. Now, rather + than shots=0 referring to 'analytic' mode, there is a separate analytic argument. + Further, the num_shots argument has been removed from Device.samples(). + ([#53](https://github.com/XanaduAI/pennylane-pq/pull/53)) + +### Contributors + +This release contains contributions from (in alphabetical order): + +Josh Izaac + +--- + # Version 0.4.1 ### Bug fixes diff --git a/pennylane_pq/_version.py b/pennylane_pq/_version.py index ded0df0..daa7cf4 100644 --- a/pennylane_pq/_version.py +++ b/pennylane_pq/_version.py @@ -16,4 +16,4 @@ Version number (major.minor.patch[-label]) """ -__version__ = '0.5.0-dev' +__version__ = '0.6.0' diff --git a/pennylane_pq/devices.py b/pennylane_pq/devices.py index 4d2edc0..0db5497 100644 --- a/pennylane_pq/devices.py +++ b/pennylane_pq/devices.py @@ -94,10 +94,13 @@ class _ProjectQDevice(Device): #pylint: disable=abstract-method Args: wires (int): The number of qubits of the device. Default 1 if not specified. - shots (int): number of circuit evaluations/random samples used to estimate - expectation values of observables. For simulator devices, a value of 0 (default) - results in the exact expectation value being returned. For the IBMBackend the - default is 1024. + shots (int): How many times the circuit should be evaluated (or sampled) to estimate + the expectation values. Defaults to 1024 if not specified. + If ``analytic == True``, then the number of shots is ignored + in the calculation of expectation values and variances, and only controls the number + of samples returned by ``sample``. + analytic (bool): indicates if the device should calculate expectations + and variances analytically Keyword Args: backend (string): Name of the backend, i.e., either "Simulator", @@ -124,7 +127,7 @@ class _ProjectQDevice(Device): #pylint: disable=abstract-method name = 'ProjectQ PennyLane plugin' short_name = 'projectq' pennylane_requires = '>=0.4.0' - version = '0.4.0' + version = '0.4.2' plugin_version = __version__ author = 'Christian Gogolin' _capabilities = {'backend': list(["Simulator", "ClassicalSimulator", "IBMBackend"])} @@ -141,7 +144,7 @@ def _observable_map(self): def _backend_kwargs(self): raise NotImplementedError - def __init__(self, wires=1, shots=0, *, backend, **kwargs): + def __init__(self, wires=1, shots=0, analytic=True, *, backend, **kwargs): # overwrite shots with num_runs if given if 'num_runs' in kwargs: shots = kwargs['num_runs'] @@ -242,9 +245,13 @@ class ProjectQSimulator(_ProjectQDevice): Args: wires (int): The number of qubits of the device. Default 1 if not specified. - shots (int): number of random samples used to estimate expectation values of - observables. A value of 0 (default) results in the exact expectation value - being returned. + shots (int): How many times the circuit should be evaluated (or sampled) to estimate + the expectation values. Defaults to 1000 if not specified. + If ``analytic == True``, then the number of shots is ignored + in the calculation of expectation values and variances, and only controls the number + of samples returned by ``sample``. + analytic (bool): indicates if the device should calculate expectations + and variances analytically Keyword Args: gate_fusion (bool): If True, operations are cached and only executed once a @@ -298,9 +305,9 @@ class ProjectQSimulator(_ProjectQDevice): _circuits = {} _backend_kwargs = ['gate_fusion', 'rnd_seed'] - def __init__(self, wires=1, shots=0, **kwargs): + def __init__(self, wires=1, shots=1024, analytic=True, **kwargs): kwargs['backend'] = 'Simulator' - super().__init__(wires=wires, shots=shots, **kwargs) + super().__init__(wires=wires, shots=shots, analytic=analytic, **kwargs) def reset(self): """Reset/initialize the device by initializing the backend and engine, and allocating qubits. @@ -448,7 +455,7 @@ def __init__(self, wires=1, shots=1024, **kwargs): import projectq.setups.ibm #pylint: disable=unused-variable kwargs['backend'] = 'IBMBackend' - super().__init__(wires=wires, shots=shots, **kwargs) + super().__init__(wires=wires, shots=shots, analytic=False, **kwargs) def reset(self): """Reset/initialize the device by initializing the backend and engine, and allocating qubits. @@ -549,7 +556,7 @@ class ProjectQClassicalSimulator(_ProjectQDevice): def __init__(self, wires=1, **kwargs): kwargs['backend'] = 'ClassicalSimulator' - super().__init__(wires=wires, shots=0, **kwargs) + super().__init__(wires=wires, shots=1, analytic=True, **kwargs) def reset(self): """Reset/initialize the device by initializing the backend and engine, and allocating qubits. diff --git a/requirements.txt b/requirements.txt index f8a8fc4..52df0e9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,2 @@ projectq -pennylane>=0.4 +pennylane>=0.6 diff --git a/setup.py b/setup.py index 140b56d..734579f 100644 --- a/setup.py +++ b/setup.py @@ -19,7 +19,7 @@ version = f.readlines()[-1].split()[-1].strip("\"'") # pylint: disable=invalid-name -requirements = ["projectq>=0.4.1", "pennylane>=0.4"] # pylint: disable=invalid-name +requirements = ["projectq>=0.4.1", "pennylane>=0.6"] # pylint: disable=invalid-name info = { # pylint: disable=invalid-name diff --git a/tests/test_compare_with_default_qubit.py b/tests/test_compare_with_default_qubit.py index 62c889f..6babe4a 100644 --- a/tests/test_compare_with_default_qubit.py +++ b/tests/test_compare_with_default_qubit.py @@ -141,7 +141,7 @@ def circuit(): #if we could run the circuit on more than one device assert that both should have given the same output for (key,val) in outputs.items(): if len(val) >= 2: - self.assertAllElementsAlmostEqual(val.values(), delta=self.tol, msg="Outputs "+str(list(val.values()))+" of devices ["+', '.join(list(val.keys()))+"] do not agree for a circuit consisting of a "+str(key[0])+" Operation followed by a "+str(key[1])+" Expectation." ) + self.assertAllElementsAlmostEqual(val.values(), delta=0.2, msg="Outputs "+str(list(val.values()))+" of devices ["+', '.join(list(val.keys()))+"] do not agree for a circuit consisting of a "+str(key[0])+" Operation followed by a "+str(key[1])+" Expectation." ) if __name__ == '__main__': From 6ed3a9ad7b6cb191226275137ff37e135352491a Mon Sep 17 00:00:00 2001 From: Josh Izaac Date: Fri, 18 Oct 2019 15:13:25 -0400 Subject: [PATCH 2/4] fix --- pennylane_pq/devices.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane_pq/devices.py b/pennylane_pq/devices.py index 0db5497..8a905aa 100644 --- a/pennylane_pq/devices.py +++ b/pennylane_pq/devices.py @@ -339,7 +339,7 @@ def expval(self, observable, wires, par): # pq.ops.QubitOperator("Z"+'0'), [qubit]) # for qubit in self._reg] - if self.shots != 0 and observable != 'Identity': + if not self.analytic and observable != 'Identity': p0 = (expval+1)/2 p0 = max(min(p0, 1), 0) n0 = np.random.binomial(self.shots, p0) From f2b729a9ed04d1e6e2eb55cb5dcbbc0f5beb1652 Mon Sep 17 00:00:00 2001 From: Josh Izaac Date: Fri, 18 Oct 2019 15:14:21 -0400 Subject: [PATCH 3/4] fix --- pennylane_pq/devices.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pennylane_pq/devices.py b/pennylane_pq/devices.py index 8a905aa..9a21d2e 100644 --- a/pennylane_pq/devices.py +++ b/pennylane_pq/devices.py @@ -155,6 +155,7 @@ def __init__(self, wires=1, shots=0, analytic=True, *, backend, **kwargs): if 'verbose' not in kwargs: kwargs['verbose'] = False + self.analytic = analytic self._backend = backend self._kwargs = kwargs self._eng = None From 16e2045ade042eedee967b51e410d806dac331dd Mon Sep 17 00:00:00 2001 From: Josh Izaac Date: Fri, 18 Oct 2019 18:40:19 -0400 Subject: [PATCH 4/4] suggested changes --- .github/CHANGELOG.md | 2 +- pennylane_pq/devices.py | 4 ++-- tests/test_compare_with_default_qubit.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 05db14b..759228e 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -3,7 +3,7 @@ ### Bug fixes * The way measurement statistics works has changed in the latest version of PennyLane. Now, rather - than shots=0 referring to 'analytic' mode, there is a separate analytic argument. + than `shots=0` referring to 'analytic' mode, there is a separate analytic argument. Further, the num_shots argument has been removed from Device.samples(). ([#53](https://github.com/XanaduAI/pennylane-pq/pull/53)) diff --git a/pennylane_pq/devices.py b/pennylane_pq/devices.py index 9a21d2e..21b59d1 100644 --- a/pennylane_pq/devices.py +++ b/pennylane_pq/devices.py @@ -144,7 +144,7 @@ def _observable_map(self): def _backend_kwargs(self): raise NotImplementedError - def __init__(self, wires=1, shots=0, analytic=True, *, backend, **kwargs): + def __init__(self, wires=1, shots=1024, analytic=True, *, backend, **kwargs): # overwrite shots with num_runs if given if 'num_runs' in kwargs: shots = kwargs['num_runs'] @@ -557,7 +557,7 @@ class ProjectQClassicalSimulator(_ProjectQDevice): def __init__(self, wires=1, **kwargs): kwargs['backend'] = 'ClassicalSimulator' - super().__init__(wires=wires, shots=1, analytic=True, **kwargs) + super().__init__(wires=wires, shots=1024, analytic=True, **kwargs) def reset(self): """Reset/initialize the device by initializing the backend and engine, and allocating qubits. diff --git a/tests/test_compare_with_default_qubit.py b/tests/test_compare_with_default_qubit.py index 6babe4a..62c889f 100644 --- a/tests/test_compare_with_default_qubit.py +++ b/tests/test_compare_with_default_qubit.py @@ -141,7 +141,7 @@ def circuit(): #if we could run the circuit on more than one device assert that both should have given the same output for (key,val) in outputs.items(): if len(val) >= 2: - self.assertAllElementsAlmostEqual(val.values(), delta=0.2, msg="Outputs "+str(list(val.values()))+" of devices ["+', '.join(list(val.keys()))+"] do not agree for a circuit consisting of a "+str(key[0])+" Operation followed by a "+str(key[1])+" Expectation." ) + self.assertAllElementsAlmostEqual(val.values(), delta=self.tol, msg="Outputs "+str(list(val.values()))+" of devices ["+', '.join(list(val.keys()))+"] do not agree for a circuit consisting of a "+str(key[0])+" Operation followed by a "+str(key[1])+" Expectation." ) if __name__ == '__main__':