Skip to content

Commit

Permalink
sync: public changes to staging (#168)
Browse files Browse the repository at this point in the history
* infra: Pin docutils<0.18 in doc requirements (#283)

docutils 0.18 was released on October 26, 2021, and with it came some [breaking changes](readthedocs/readthedocs.org#8616) for sphinx, and in turn [readthedocs builds](https://readthedocs.org/projects/amazon-braket-sdk-python/builds/15168485/). To keep doc builds working, docutils will be constrained to versions below 0.18.

* prepare release v1.9.5.post0

* update development version to v1.9.6.dev0

* feature: Add support for jobs (#287)

Co-authored-by: Viraj Chaudhari <[email protected]>
Co-authored-by: Milan Krneta <[email protected]>
Co-authored-by: Aaron Berdy <[email protected]>
Co-authored-by: Lin <[email protected]>
Co-authored-by: Roald Bradley Severtson <[email protected]>
Co-authored-by: Christian Madsen <[email protected]>

* fix: Skip jobs integration tests (#288)

* prepare release v1.10.0

* update development version to v1.10.1.dev0

* feature: Adding integration tests for DM1 (#286)

* feature: Adding integration tests for DM1

* Moved many_layers to test_quantum_task

* formatting changes only

Co-authored-by: Cody Wang <[email protected]>

* prepare release v1.11.0

* update development version to v1.11.1.dev0

* fix: remove extraneous reference from local job container setup (#292)

* prepare release v1.11.1

* update development version to v1.11.2.dev0

* feature: optimize IAM role retrieval (#299)

* fix: Enable jobs integration tests (#289)

* feature: Added is_available property to AwsDevice (#290)

Added is_available property to AwsDevice that parses the availability window and current device status to return a boolean flag if the device is currently available.

* prepare release v1.12.0

* update development version to v1.12.1.dev0

* feature: added controlled-sqrt-not gate (#297)

* feature: added controlled-sqrt-not gate

This makes certain circuits, like CHSH, more straightforward. This commit works in line with the following branches (also committed, separately):
https://github.com/unprovable/amazon-braket-schemas-python.git@ctrl-v-gate
https://github.com/unprovable/amazon-braket-default-simulator-python.git@ctrl-v-gate

* fix: ran tox linters

* fix: reverted tox.ini

Co-authored-by: Mark C <[email protected]>
Co-authored-by: Mark C <[email protected]>
Co-authored-by: Cody Wang <[email protected]>

* prepare release v1.13.0

* update development version to v1.13.1.dev0

* feature: adding TwoQubitPauliChannel (#300)

* prepare release v1.14.0

* update development version to v1.14.1.dev0

Co-authored-by: Cody Wang <[email protected]>
Co-authored-by: ci <ci>
Co-authored-by: Kshitij Chhabra <[email protected]>
Co-authored-by: Milan Krneta <[email protected]>
Co-authored-by: Aaron Berdy <[email protected]>
Co-authored-by: Lin <[email protected]>
Co-authored-by: Roald Bradley Severtson <[email protected]>
Co-authored-by: Christian Madsen <[email protected]>
Co-authored-by: Jacob Feldman <[email protected]>
Co-authored-by: Mark Sweat <[email protected]>
Co-authored-by: Mark C <[email protected]>
Co-authored-by: Mark C <[email protected]>
Co-authored-by: Mark C <[email protected]>
Co-authored-by: mbeach-aws <[email protected]>
  • Loading branch information
14 people authored Feb 9, 2022
1 parent e1f9663 commit dabf63e
Show file tree
Hide file tree
Showing 14 changed files with 633 additions and 66 deletions.
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,28 @@
# Changelog

## v1.14.0 (2022-02-02)

### Features

* adding TwoQubitPauliChannel

## v1.13.0 (2022-01-27)

### Features

* added controlled-sqrt-not gate

## v1.12.0 (2022-01-25)

### Features

* Added is_available property to AwsDevice
* optimize IAM role retrieval

### Bug Fixes and Other Changes

* Enable jobs integration tests

## v1.11.1 (2021-12-09)

### Bug Fixes and Other Changes
Expand Down
2 changes: 1 addition & 1 deletion src/braket/_sdk/_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@
Version number (major.minor.patch[-label])
"""

__version__ = "1.11.2.dev0"
__version__ = "1.14.1.dev0"
60 changes: 59 additions & 1 deletion src/braket/aws/aws_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from __future__ import annotations

import os
from datetime import datetime
from enum import Enum
from typing import List, Optional, Union

Expand All @@ -25,7 +26,7 @@
from braket.aws.aws_quantum_task_batch import AwsQuantumTaskBatch
from braket.aws.aws_session import AwsSession
from braket.circuits import Circuit
from braket.device_schema import DeviceCapabilities, GateModelQpuParadigmProperties
from braket.device_schema import DeviceCapabilities, ExecutionDay, GateModelQpuParadigmProperties
from braket.device_schema.dwave import DwaveProviderProperties
from braket.devices.device import Device
from braket.ir.openqasm import Program as OpenQasmProgram
Expand Down Expand Up @@ -275,6 +276,63 @@ def arn(self) -> str:
"""str: Return the ARN of the device"""
return self._arn

@property
def is_available(self) -> bool:
"""bool: Return if the device is currently available"""
if self.status != "ONLINE":
return False

is_available_result = False

current_datetime_utc = datetime.utcnow()
for execution_window in self.properties.service.executionWindows:
weekday = current_datetime_utc.weekday()
current_time_utc = current_datetime_utc.time().replace(microsecond=0)

if (
execution_window.windowEndHour < execution_window.windowStartHour
and current_time_utc < execution_window.windowEndHour
):
weekday = (weekday - 1) % 7

matched_day = execution_window.executionDay == ExecutionDay.EVERYDAY
matched_day = matched_day or (
execution_window.executionDay == ExecutionDay.WEEKDAYS and weekday < 5
)
matched_day = matched_day or (
execution_window.executionDay == ExecutionDay.WEEKENDS and weekday > 4
)
ordered_days = (
ExecutionDay.MONDAY,
ExecutionDay.TUESDAY,
ExecutionDay.WEDNESDAY,
ExecutionDay.THURSDAY,
ExecutionDay.FRIDAY,
ExecutionDay.SATURDAY,
ExecutionDay.SUNDAY,
)
matched_day = matched_day or (
execution_window.executionDay in ordered_days
and ordered_days.index(execution_window.executionDay) == weekday
)

matched_time = (
execution_window.windowStartHour < execution_window.windowEndHour
and execution_window.windowStartHour
<= current_time_utc
<= execution_window.windowEndHour
) or (
execution_window.windowEndHour < execution_window.windowStartHour
and (
current_time_utc >= execution_window.windowStartHour
or current_time_utc <= execution_window.windowEndHour
)
)

is_available_result = is_available_result or (matched_day and matched_time)

return is_available_result

@property
# TODO: Add a link to the boto3 docs
def properties(self) -> DeviceCapabilities:
Expand Down
7 changes: 4 additions & 3 deletions src/braket/aws/aws_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,17 +210,18 @@ def get_default_jobs_role(self) -> str:
"""
Returns the role ARN for the default jobs role created in the Amazon Braket Console.
It will pick the first role it finds with the `RoleName` prefix
`AmazonBraketJobsExecutionRole`.
`AmazonBraketJobsExecutionRole` with a `PathPrefix` of `/service-role/`.
Returns:
(str): The ARN for the default IAM role for jobs execution created in the Amazon
Braket console.
Raises:
RuntimeError: If no roles can be found with the prefix `AmazonBraketJobsExecutionRole`.
RuntimeError: If no roles can be found with the prefix
`/service-role/AmazonBraketJobsExecutionRole`.
"""
roles_paginator = self.iam_client.get_paginator("list_roles")
for page in roles_paginator.paginate():
for page in roles_paginator.paginate(PathPrefix="/service-role/"):
for role in page.get("Roles", []):
if role["RoleName"].startswith("AmazonBraketJobsExecutionRole"):
return role["Arn"]
Expand Down
45 changes: 45 additions & 0 deletions src/braket/circuits/gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -1046,6 +1046,51 @@ def cphaseshift10(control: QubitInput, target: QubitInput, angle: float) -> Inst
Gate.register_gate(CPhaseShift10)


class CV(Gate):
"""Controlled Sqrt of NOT gate."""

def __init__(self):
super().__init__(qubit_count=None, ascii_symbols=["C", "V"])

def to_ir(self, target: QubitSet):
return ir.CV.construct(control=target[0], target=target[1])

def to_matrix(self) -> np.ndarray:
return np.array(
[
[1.0, 0.0, 0.0, 0.0],
[0.0, 1.0, 0.0, 0.0],
[0.0, 0.0, 0.5 + 0.5j, 0.5 - 0.5j], # if the control bit, then apply the V gate
[0.0, 0.0, 0.5 - 0.5j, 0.5 + 0.5j], # which is the sqrt(NOT) gate.
],
dtype=complex,
)

@staticmethod
def fixed_qubit_count() -> int:
return 2

@staticmethod
@circuit.subroutine(register=True)
def cv(control: QubitInput, target: QubitInput) -> Instruction:
"""Registers this function into the circuit class.
Args:
control (Qubit or int): Control qubit index.
target (Qubit or int): Target qubit index.
Returns:
Instruction: CV instruction.
Examples:
>>> circ = Circuit().cv(0, 1)
"""
return Instruction(CV(), target=[control, target])


Gate.register_gate(CV)


class CY(Gate):
"""Controlled Pauli-Y gate."""

Expand Down
104 changes: 98 additions & 6 deletions src/braket/circuits/noise.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.

from typing import Any, Optional, Sequence
from typing import Any, Dict, Optional, Sequence

from braket.circuits.quantum_operator import QuantumOperator
from braket.circuits.qubit_set import QubitSet
Expand Down Expand Up @@ -121,7 +121,7 @@ def __init__(
def probability(self) -> float:
"""
Returns:
probability (float): The probability that parameterizes the noise channel.
probability (float): The probability that parametrizes the noise channel.
"""
return self._probability

Expand Down Expand Up @@ -163,7 +163,7 @@ def __init__(
def probability(self) -> float:
"""
Returns:
probability (float): The probability that parameterizes the noise channel.
probability (float): The probability that parametrizes the noise channel.
"""
return self._probability

Expand Down Expand Up @@ -205,18 +205,110 @@ def __init__(
def probability(self) -> float:
"""
Returns:
probability (float): The probability that parameterizes the noise channel.
probability (float): The probability that parametrizes the noise channel.
"""
return self._probability

def __repr__(self):
return f"{self.name}('probability': {self.probability}, 'qubit_count': {self.qubit_count})"


class MultiQubitPauliNoise(Noise):
"""
Class `MultiQubitPauliNoise` represents a general multi-qubit Pauli channel,
parameterized by up to 4**N - 1 probabilities.
"""

_allowed_substrings = {"I", "X", "Y", "Z"}

def __init__(
self,
probabilities: Dict[str, float],
qubit_count: Optional[int],
ascii_symbols: Sequence[str],
):
"""[summary]
Args:
probabilities (Dict[str, float]): A dictionary with Pauli string as the keys,
and the probabilities as values, i.e. {"XX": 0.1. "IZ": 0.2}.
qubit_count (Optional[int]): The number of qubits the Pauli noise acts on.
ascii_symbols (Sequence[str]): ASCII string symbols for the noise. These are used when
printing a diagram of a circuit. The length must be the same as `qubit_count`, and
index ordering is expected to correlate with the target ordering on the instruction.
Raises:
ValueError: If the `qubit_count` is less than 1, `ascii_symbols` are `None`, or
`ascii_symbols` length != `qubit_count`. Also if `probabilities` are not `float`s,
any `probabilities` > 1, or `probabilities` < 0, or if the sum of all
probabilities is > 1,
or if "II" is specified as a Pauli string.
Also if any Pauli string contains invalid strings.
Also if the length of probabilities is greater than 4**qubit_count.
TypeError: If the type of the dictionary keys are not strings.
If the probabilities are not floats.
"""

super().__init__(qubit_count=qubit_count, ascii_symbols=ascii_symbols)
self.probabilities = probabilities

if not probabilities:
raise ValueError("Pauli dictionary must not be empty.")

identity = self.qubit_count * "I"
if identity in probabilities:
raise ValueError(
f"{identity} is not allowed as a key. Please enter only non-identity Pauli strings."
)

for pauli_string, prob in probabilities.items():
if not isinstance(pauli_string, str):
raise TypeError(f"Type of {pauli_string} was not a string.")
if len(pauli_string) != self.qubit_count:
raise ValueError(
(
"Length of each Pauli string must be equal to number of qubits. "
f"{pauli_string} had length {len(pauli_string)} instead of length {self.qubit_count}." # noqa
)
)
if not isinstance(prob, float):
raise TypeError(
(
"Probabilities must be a float type. "
f"The probability for {pauli_string} was of type {type(prob)}."
)
)
if not set(pauli_string) <= self._allowed_substrings:
raise ValueError(
(
"Strings must be Pauli strings consisting of only [I, X, Y, Z]. "
f"Received {pauli_string}."
)
)
if prob < 0.0 or prob > 1.0:
raise ValueError(
(
"Individual probabilities must be real numbers in the interval [0, 1]. "
f"Probability for {pauli_string} was {prob}."
)
)
total_prob = sum(probabilities.values())
if total_prob > 1.0 or total_prob < 0.0:
raise ValueError(
(
"Total probability must be a real number in the interval [0, 1]. "
f"Total probability was {total_prob}."
)
)

def __repr__(self):
return f"{self.name}('probabilities' : {self.probabilities}, 'qubit_count': {self.qubit_count})" # noqa


class PauliNoise(Noise):
"""
Class `PauliNoise` represents the general Pauli noise channel on N qubits
parameterized by three probabilities.
Class `PauliNoise` represents the a single-qubit Pauli noise channel
acting on one qubit. It is parameterized by three probabilities.
"""

def __init__(
Expand Down
Loading

0 comments on commit dabf63e

Please sign in to comment.