Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add integ tests for result types for local and aws simulators and exa… #93

Merged
merged 1 commit into from
Jun 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
13 changes: 13 additions & 0 deletions examples/bell.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
# Copyright 2019-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"). You
# may not use this file except in compliance with the License. A copy of
# the License is located at
#
# http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.

import boto3
from braket.aws import AwsQuantumSimulator, AwsQuantumSimulatorArns
from braket.circuits import Circuit
Expand Down
62 changes: 62 additions & 0 deletions examples/bell_result_types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Copyright 2019-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"). You
# may not use this file except in compliance with the License. A copy of
# the License is located at
#
# http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.

from braket.circuits import Circuit, Observable
from braket.devices import LocalSimulator

device = LocalSimulator()

print("Example for shots=0")
# Result types can be requested in the circuit
# Example of result types for shots=0
bell = (
Circuit()
.h(0)
.cnot(0, 1)
.probability(target=[0])
.expectation(observable=Observable.Z(), target=[1])
.amplitude(state="00")
.state_vector()
)

# State vector and amplitude can only be requested when shots=0 for a simulator
# When shots=0 for a simulator, probability, expectation, variance are the exact values,
# not calculated from measurements
# Users cannot request Sample as a result when shots=0
result = device.run(bell).result()
print("Marginal probability for target 0 in computational basis:", result.values[0])
print("Expectation of target 1 in the computational basis:", result.values[1])
print("Amplitude of state 00:", result.values[2])
print("State vector:", result.values[3])

print("\nExample for shots>0")
# Example of result types for shots > 0
bell = (
Circuit()
.h(0)
.cnot(0, 1)
.probability()
.expectation(observable=Observable.Y() @ Observable.X(), target=[0, 1])
.variance(observable=Observable.Y() @ Observable.X(), target=[0, 1])
.sample(observable=Observable.Y() @ Observable.X(), target=[0, 1])
)

# When shots>0 for a simulator, probability, expectation, variance are calculated from measurements
# Users can request sample as a result when shots > 0
result = device.run(bell, shots=100).result()
print("Probability of all states in computational basis:", result.values[0])
print("Expectation of target 0, 1 in the basis of Pauli-Y @ Pauli-X:", result.values[1])
print("Variance of target 0, 1 in the basis of Pauli-Y @ Pauli-X:", result.values[2])
print("Samples of target 0, 1 in the basis of Pauli-Y @ Pauli-X:", result.values[3])

# Probability, sample, expectation, and variance are also supported for QPU devices
13 changes: 13 additions & 0 deletions examples/debug_bell.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
# Copyright 2019-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"). You
# may not use this file except in compliance with the License. A copy of
# the License is located at
#
# http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.

import logging
import sys

Expand Down
13 changes: 13 additions & 0 deletions examples/local_bell.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
# Copyright 2019-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"). You
# may not use this file except in compliance with the License. A copy of
# the License is located at
#
# http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.

from braket.circuits import Circuit
from braket.devices import LocalSimulator

Expand Down
34 changes: 20 additions & 14 deletions src/braket/circuits/circuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ class Circuit:
"""

_ALL_QUBITS = "ALL" # Flag to indicate all qubits in _qubit_observable_mapping
_EXISTING_QUBITS = "EXISTING" # Flag to indicate existing qubits in _qubit_observable_mapping

@classmethod
def register_subroutine(cls, func: SubroutineCallable) -> None:
Expand Down Expand Up @@ -147,17 +146,20 @@ def basis_rotation_instructions(self) -> List[Instruction]:
if isinstance(result_type, ObservableResultType)
)

added_observables_targets = set()
for return_type in observable_return_types:
target: List[int] = return_type.target
observable: Observable = return_type.observable
if not target:
# There will be only one result type in observable_return_types,
# and its observable acts on all qubits
for target in self._moments.qubits:
basis_rotation_instructions += Circuit._observable_to_instruction(
observable, target
)
else:
targets: List[List[int]] = [return_type.target] if return_type.target else [
QubitSet(qubit) for qubit in self._moments.qubits
]

for target in targets:
# only add gates for observables and targets that
# have not been processed
str_observables_target = f"{observable}; {target}"
if str_observables_target in added_observables_targets:
continue
added_observables_targets.add(str_observables_target)
basis_rotation_instructions += Circuit._observable_to_instruction(
observable, target
)
Expand Down Expand Up @@ -267,18 +269,22 @@ def _add_to_qubit_observable_mapping(self, result_type: ResultType) -> None:
observable = result_type.observable
else:
return
targets = result_type.target if result_type.target else Circuit._EXISTING_QUBITS

targets = result_type.target or self._qubit_observable_mapping.keys()
all_qubits_observable = self._qubit_observable_mapping.get(Circuit._ALL_QUBITS)

for target in targets:
current_observable = all_qubits_observable or self._qubit_observable_mapping.get(target)
if current_observable and current_observable != observable:
raise ValueError(
f"Existing result type for observable {current_observable} for target {target}"
+ f"conflicts with observable {observable} for new result type"
f" conflicts with observable {observable} for new result type"
)
self._qubit_observable_mapping[target] = observable
self._qubit_observable_mapping[Circuit._EXISTING_QUBITS] = observable
if result_type.target:
self._qubit_observable_mapping[target] = observable

if not result_type.target:
self._qubit_observable_mapping[Circuit._ALL_QUBITS] = observable
avawang1 marked this conversation as resolved.
Show resolved Hide resolved

def add_instruction(
self,
Expand Down
12 changes: 8 additions & 4 deletions src/braket/circuits/observables.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,10 +171,10 @@ def __init__(self, observables: List[Observable]):
>>> t2.factors
(Z('qubit_count': 1), Y('qubit_count': 1), X('qubit_count': 1))

Note: You must provide the list of observables for the tensor product to be evaluated
in the order that you want the tensor product to be calculated.
For `TensorProduct(observables=[ob1, ob2, ob3])`, the tensor product's matrix is the
result of the tensor product of `ob1`, `ob2`, `ob3`, or `np.kron(np.kron(ob1.to_matrix(),
Note: You must provide the list of observables for the tensor product to be evaluated
in the order that you want the tensor product to be calculated.
For `TensorProduct(observables=[ob1, ob2, ob3])`, the tensor product's matrix is the
result of the tensor product of `ob1`, `ob2`, `ob3`, or `np.kron(np.kron(ob1.to_matrix(),
ob2.to_matrix()), ob3.to_matrix())`.
"""
self._observables = tuple(observables)
Expand Down Expand Up @@ -329,6 +329,10 @@ def _get_eigendecomposition(self) -> Dict[str, np.ndarray]:
}
return Hermitian._eigenpairs[mat_key]

def __repr__(self):
matrix_str = np.array2string(self.to_matrix()).replace("\n", ",")
return f"{self.name}('qubit_count': {self.qubit_count}, 'matrix': {matrix_str})"


Observable.register_observable(Hermitian)

Expand Down
12 changes: 6 additions & 6 deletions src/braket/circuits/result_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,8 @@ def __copy__(self):
class Probability(ResultType):
"""Probability in the computational basis as the requested result type.

It can be the probability of all states if no targets are specified, or the marginal
probability of a restricted set of states if only a subset of all qubits are specified as
It can be the probability of all states if no targets are specified, or the marginal
probability of a restricted set of states if only a subset of all qubits are specified as
targets.

For `shots>0`, this is calculated by measurements. For `shots=0`, this is supported
Expand Down Expand Up @@ -228,7 +228,7 @@ def __init__(self, observable: Observable, target: QubitSetInput = None):
operate only on 1 qubit and it is applied to all qubits in parallel.

Raises:
ValueError: If the observable's qubit count does not equal the number of target
ValueError: If the observable's qubit count does not equal the number of target
qubits, or if target=None and the observable's qubit count is not 1.

Examples:
Expand Down Expand Up @@ -295,7 +295,7 @@ def __init__(self, observable: Observable, target: QubitSetInput = None):
operate only on 1 qubit and it is applied to all qubits in parallel.

Raises:
ValueError: If the observable's qubit count is not equal to the number of target
ValueError: If the observable's qubit count is not equal to the number of target
qubits, or if target=None and the observable's qubit count is not 1.

Examples:
Expand Down Expand Up @@ -345,7 +345,7 @@ class Variance(ObservableResultType):
"""Variance of specified target qubit set and observable as the requested result type.

If no targets are specified, the observable must operate only on 1 qubit and it
is applied to all qubits in parallel. Otherwise, the number of targets specified
is applied to all qubits in parallel. Otherwise, the number of targets specified
must equal the number of qubits that the observable can be applied to.

For `shots>0`, this is calculated by measurements. For `shots=0`, this is supported
Expand All @@ -363,7 +363,7 @@ def __init__(self, observable: Observable, target: QubitSetInput = None):
operate only on 1 qubit and it is applied to all qubits in parallel.

Raises:
ValueError: If the observable's qubit count does not equal the number of target
ValueError: If the observable's qubit count does not equal the number of target
qubits, or if target=None and the observable's qubit count is not 1.

Examples:
Expand Down
16 changes: 0 additions & 16 deletions test/integ_tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
import pytest
from botocore.exceptions import ClientError
from braket.aws.aws_session import AwsSession
from braket.circuits import Circuit


@pytest.fixture(scope="session")
Expand Down Expand Up @@ -71,18 +70,3 @@ def s3_prefix():
@pytest.fixture(scope="module")
def s3_destination_folder(s3_bucket, s3_prefix):
return AwsSession.S3DestinationFolder(s3_bucket, s3_prefix)


@pytest.fixture(scope="session")
def bell_state_and_tolerances():
return Circuit().h(0).cnot(0, 1), {"00": (0.4, 0.6), "11": (0.4, 0.6)}


@pytest.fixture(scope="session")
def state_110_and_most_common():
return Circuit().x(0).x(1).i(2), "110"


@pytest.fixture(scope="session")
def state_001_and_most_common():
return Circuit().i(0).i(1).x(2), "001"
Loading