Coverage for src/braket/circuits/moments.py : 100%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# Copyright 2019-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License"). You
4# may not use this file except in compliance with the License. A copy of
5# the License is located at
6#
7# http://aws.amazon.com/apache2.0/
8#
9# or in the "license" file accompanying this file. This file is
10# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11# ANY KIND, either express or implied. See the License for the specific
12# language governing permissions and limitations under the License.
14from typing import (
15 Dict,
16 ItemsView,
17 Iterable,
18 KeysView,
19 List,
20 Mapping,
21 NamedTuple,
22 OrderedDict,
23 ValuesView,
24)
26from braket.circuits.instruction import Instruction
27from braket.circuits.qubit import Qubit
28from braket.circuits.qubit_set import QubitSet
31class MomentsKey(NamedTuple):
32 """Key of the Moments mapping."""
34 time: int
35 qubits: QubitSet
38class Moments(Mapping[MomentsKey, Instruction]):
39 """
40 An ordered mapping of `MomentsKey` to `Instruction`. The core data structure that
41 contains instructions, ordering they are inserted in, and time slices when they
42 occur. `Moments` implements `Mapping` and functions the same as a read-only
43 dictionary. It is mutable only through the `add()` method.
45 This data structure is useful to determine a dependency of instructions, such as
46 printing or optimizing circuit structure, before sending it to a quantum
47 device. The original insertion order is preserved and can be retrieved via the `values()`
48 method.
50 Args:
51 instructions (Iterable[Instruction], optional): Instructions to initialize self with.
52 Default = [].
54 Examples:
55 >>> moments = Moments()
56 >>> moments.add([Instruction(Gate.H(), 0), Instruction(Gate.CNot(), [0, 1])])
57 >>> moments.add([Instruction(Gate.H(), 0), Instruction(Gate.H(), 1)])
58 >>> for i, item in enumerate(moments.items()):
59 ... print(f"Item {i}")
60 ... print(f"\\tKey: {item[0]}")
61 ... print(f"\\tValue: {item[1]}")
62 ...
63 Item 0
64 Key: MomentsKey(time=0, qubits=QubitSet([Qubit(0)]))
65 Value: Instruction('operator': H, 'target': QubitSet([Qubit(0)]))
66 Item 1
67 Key: MomentsKey(time=1, qubits=QubitSet([Qubit(0), Qubit(1)]))
68 Value: Instruction('operator': CNOT, 'target': QubitSet([Qubit(0), Qubit(1)]))
69 Item 2
70 Key: MomentsKey(time=2, qubits=QubitSet([Qubit(0)]))
71 Value: Instruction('operator': H, 'target': QubitSet([Qubit(0)]))
72 Item 3
73 Key: MomentsKey(time=2, qubits=QubitSet([Qubit(1)]))
74 Value: Instruction('operator': H, 'target': QubitSet([Qubit(1)]))
75 """
77 def __init__(self, instructions: Iterable[Instruction] = []):
78 self._moments: OrderedDict[MomentsKey, Instruction] = OrderedDict()
79 self._max_times: Dict[Qubit, int] = {}
80 self._qubits = QubitSet()
81 self._depth = 0
83 self.add(instructions)
85 @property
86 def depth(self) -> int:
87 """int: Get the depth (number of slices) of self."""
88 return self._depth
90 @property
91 def qubit_count(self) -> int:
92 """int: Get the number of qubits used across all of the instructions."""
93 return len(self._qubits)
95 @property
96 def qubits(self) -> QubitSet:
97 """
98 QubitSet: Get the qubits used across all of the instructions. The order of qubits is based
99 on the order in which the instructions were added.
101 Note:
102 Don't mutate this object, any changes may impact the behavior of this class and / or
103 consumers. If you need to mutate this, then copy it via `QubitSet(moments.qubits())`.
104 """
105 return self._qubits
107 def time_slices(self) -> Dict[int, List[Instruction]]:
108 """
109 Get instructions keyed by time.
111 Returns:
112 Dict[int, List[Instruction]]: Key is the time and value is a list of instructions that
113 occur at that moment in time. The order of instructions is in no particular order.
115 Note:
116 This is a computed result over self and can be freely mutated. This is re-computed with
117 every call, with a computational runtime O(N) where N is the number
118 of instructions in self.
119 """
121 time_slices = {}
122 for key, instruction in self._moments.items():
123 instructions = time_slices.get(key.time, [])
124 instructions.append(instruction)
125 time_slices[key.time] = instructions
127 return time_slices
129 def add(self, instructions: Iterable[Instruction]) -> None:
130 """
131 Add instructions to self.
133 Args:
134 instructions (Iterable[Instruction]): Instructions to add to self. The instruction
135 are added to the max time slice in which the instruction fits.
136 """
137 for instruction in instructions:
138 self._add(instruction)
140 def _add(self, instruction: Instruction) -> None:
141 qubit_range = instruction.target
142 time = max([self._max_time_for_qubit(qubit) for qubit in qubit_range]) + 1
144 # Mark all qubits in qubit_range with max_time
145 for qubit in qubit_range:
146 self._max_times[qubit] = max(time, self._max_time_for_qubit(qubit))
148 self._moments[MomentsKey(time, instruction.target)] = instruction
149 self._qubits.update(instruction.target)
150 self._depth = max(self._depth, time + 1)
152 def _max_time_for_qubit(self, qubit: Qubit) -> int:
153 return self._max_times.get(qubit, -1)
155 #
156 # Implement abstract methods, default to calling selfs underlying dictionary
157 #
159 def keys(self) -> KeysView[MomentsKey]:
160 """Return a view of self's keys."""
161 return self._moments.keys()
163 def items(self) -> ItemsView[MomentsKey, Instruction]:
164 """Return a view of self's (key, instruction)."""
165 return self._moments.items()
167 def values(self) -> ValuesView[Instruction]:
168 """Return a view of self's instructions."""
169 return self._moments.values()
171 def get(self, key: MomentsKey, default=None) -> Instruction:
172 """
173 Get the instruction in self by key.
175 Args:
176 key (MomentsKey): Key of the instruction to fetch.
177 default (Any, optional): Value to return if `key` is not in moment. Default = None.
179 Returns:
180 Instruction: moments[key] if key in moments, else `default` is returned.
181 """
182 return self._moments.get(key, default)
184 def __getitem__(self, key):
185 return self._moments.__getitem__(key)
187 def __iter__(self):
188 return self._moments.__iter__()
190 def __len__(self):
191 return self._moments.__len__()
193 def __contains__(self, item):
194 return self._moments.__contains__(item)
196 def __eq__(self, other):
197 if isinstance(other, Moments):
198 return (self._moments) == (other._moments)
199 return NotImplemented
201 def __ne__(self, other):
202 result = self.__eq__(other)
203 if result is not NotImplemented:
204 return not result
205 return NotImplemented
207 def __repr__(self):
208 return self._moments.__repr__()
210 def __str__(self):
211 return self._moments.__str__()