GateWithRegisters#
qualtran.GateWithRegisters
View source on GitHub
|
cirq.Gates extension with support for composite gates acting on multiple qubit registers.
Inherits From: Bloq
Though Cirq was nominally designed for circuit construction for near-term devices the core
concept of the cirq.Gate, a programmatic representation of an operation on a state without
a complete qubit address specification, can be leveraged to describe more abstract algorithmic
primitives. To define composite gates, users derive from cirq.Gate and implement the
_decompose_ method that yields the sub-operations provided a flat list of qubits.
This API quickly becomes inconvenient when defining operations that act on multiple qubit
registers of variable sizes. Qualtran extends the cirq.Gate idea by introducing a new abstract
base class GateWithRegisters containing abstract methods registers and optional
method decompose_from_registers that provides an overlay to the Cirq flat address API.
As an example, in the following code snippet we use the GateWithRegisters to
construct a multi-target controlled swap operation:
>>> import attr
>>> import cirq
>>> import qualtran
>>>
>>> @attr.frozen
... class MultiTargetCSwap(qualtran.GateWithRegisters):
... bitsize: int
...
... @property
... def signature(self) -> qualtran.Signature:
... return qualtran.Signature.build(ctrl=1, x=self.bitsize, y=self.bitsize)
...
... def decompose_from_registers(self, context, ctrl, x, y) -> cirq.OP_TREE:
... yield [cirq.CSWAP(*ctrl, qx, qy) for qx, qy in zip(x, y)]
...
>>> op = MultiTargetCSwap(2).on_registers(
... ctrl=[cirq.q('ctrl')],
... x=cirq.NamedQubit.range(2, prefix='x'),
... y=cirq.NamedQubit.range(2, prefix='y'),
... )
>>> print(cirq.Circuit(op))
ctrl: ───MultiTargetCSwap───
│
x0: ─────x──────────────────
│
x1: ─────x──────────────────
│
y0: ─────y──────────────────
│
y1: ─────y──────────────────
Attributes
signatureThe input and output names and types for this bloq.
This property can be thought of as analogous to the function signature in ordinary programming. For example, it is analogous to function declarations in a C header (
*.h) file.This is the only mandatory method (property) you must implement to inherit from
Bloq. You can optionally implement additional methods to encode more information about this bloq.
Methods#
decompose_bloq
decompose_bloq() -> 'CompositeBloq'
Decompose this Bloq into its constituent parts contained in a CompositeBloq.
Bloq users can call this function to delve into the definition of a Bloq. The function
returns the decomposition of this Bloq represented as an explicit compute graph wrapped
in a CompositeBloq object.
Bloq authors can specify the bloq’s decomposition by overriding any of the following two methods:
build_composite_bloq: Override this method to define a bloq-style decomposition using aBloqBuilderbuilder class to construct theCompositeBloqdirectly.decompose_from_registers: Override this method to define a cirq-style decomposition by yielding cirq style operations applied on qubits.
Irrespective of the bloq author’s choice of backend to implement the decomposition, bloq users will be able to access both the bloq-style and Cirq-style interfaces. For example, users can call:
cirq.decompose_once(bloq.on_registers(**cirq_quregs)): This will yield acirq.OPTREE. Bloqs will be wrapped inBloqAsCirqGateas needed.bloq.decompose_bloq(): This will return aCompositeBloq. Cirq gates will be be wrapped inCirqGateAsBloqas needed.
Thus, GateWithRegisters class provides a convenient way of defining objects that can be used
interchangeably with both Cirq and Bloq constructs.
Returns
Raises
DecomposeNotImplementedErrorIf there is no decomposition defined; namely if both:
build_composite_bloqraises aDecomposeNotImplementedErroranddecompose_from_registersraises aDecomposeNotImplementedError.
as_cirq_op
as_cirq_op(
qubit_manager: 'cirq.QubitManager', **in_quregs
) -> Tuple[Union['cirq.Operation', None], Dict[str, 'CirqQuregT']]
Allocates/Deallocates qubits for RIGHT/LEFT only registers to construct a Cirq operation
Args
qubit_managerFor allocating/deallocating qubits for RIGHT/LEFT only registers.
in_quregsMapping from LEFT register names to corresponding cirq qubits.
Returns
wire_symbol
wire_symbol(
reg: Optional[qualtran.Register],
idx: Tuple[int, ...] = tuple()
) -> 'WireSymbol'
On a musical score visualization, use this WireSymbol to represent soq.
By default, we use a “directional text box”, which is a text box that is either rectangular for thru-registers or facing to the left or right for non-thru-registers.
If reg is specified as None, this should return a Text label for the title of
the gate. If no title is needed (as the wire_symbols are self-explanatory),
this should return Text('').
Override this method to provide a more relevant WireSymbol for the provided soquet.
This method can access bloq attributes. For example: you may want to draw either
a filled or empty circle for a control register depending on a control value bloq
attribute.
decompose_from_registers
decompose_from_registers(
*, context: 'cirq.DecompositionContext', **quregs
) -> 'cirq.OP_TREE'
on
on(
*qubits
) -> 'cirq.Operation'
A cirq.Operation of this bloq operating on the given qubits.
This method supports an alternative decomposition backend that follows a ‘Cirq-style’
association of gates with qubits to form operations. Instead of wiring up Soquets,
each gate operates on qubit addresses (cirq.Qids), which are reused by multiple
gates. This method lets you operate this bloq on qubits and returns a cirq.Operation.
The primary, bloq-native way of writing decompositions is to override
build_composite_bloq. If this is what you’re doing, do not use this method.
To provide a Cirq-style decomposition for this bloq, implement a method (typically named
decompose_from_registers for historical reasons) that yields a list of cirq.Operations
using cirq.Gate.on(...), Bloq.on(…), GateWithRegisters.on_registers(…), or
Bloq.on_registers(…).
See Also
on_registers
on_registers(
**qubit_regs
) -> 'cirq.Operation'
A cirq.Operation of this bloq operating on the given qubit registers.
This method supports an alternative decomposition backend that follows a ‘Cirq-style’
association of gates with qubit registers to form operations. See Bloq.on() for
more details.
Args
**qubit_regsA mapping of register name to the qubits comprising that register.
See Also
__pow__
__pow__(
power: int
) -> 'GateWithRegisters'
controlled
controlled(
num_controls: Union[Optional[int], 'CtrlSpec'] = None,
control_values: Optional[Union['cirq.ops.AbstractControlValues', Sequence[Union[int,
Collection[int]]]]] = None,
control_qid_shape: Optional[Tuple[int, ...]] = None,
*,
ctrl_spec: Optional['CtrlSpec'] = None
) -> 'Bloq'
Return a controlled version of self. Controls can be specified via Cirq/Bloq-style APIs.
If no arguments are specified, defaults to a single qubit control.
Supports both Cirq-style API and Bloq-style API to construct controlled Bloqs. The cirq-style
API is supported by intercepting the Cirq-style way of specifying a control specification;
via arguments num_controls, control_values and control_qid_shape, and constructing a
CtrlSpec object from it before delegating to self.get_ctrl_system.
By default, the system will use the qualtran.Controlled meta-bloq to wrap this
bloq. Bloqs authors can declare their own, custom controlled versions by overriding
Bloq.get_ctrl_system in the bloq.
Args
num_controlsCirq style API to specify control specification - Total number of control qubits.
control_valuesCirq style API to specify control specification - Which control computational basis state to apply the sub gate. A sequence of length
num_controlswhere each entry is an integer (or set of integers) corresponding to the computational basis state (or set of possible values) where that control is enabled. When all controls are enabled, the sub gate is applied. If unspecified, control values default to 1.control_qid_shapeCirq style API to specify control specification - The qid shape of the controls. A tuple of the expected dimension of each control qid. Defaults to
(2,) * num_controls. Specify this argument when using qudits.ctrl_specBloq style API to specify a control specification - An optional keyword argument
CtrlSpec, which specifies how to control the bloq. The default spec means the bloq will be active when one control qubit is in the |1> state. See the CtrlSpec documentation for more possibilities including negative controls, integer-equality control, and ndarrays of control values.
Returns
my_tensors
my_tensors(
incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT']
) -> List['qtn.Tensor']
Override this method to support native quimb simulation of this Bloq.
This method is responsible for returning tensors corresponding to the unitary, state, or effect of the bloq. Often, this method will return one tensor for a given Bloq, but some bloqs can be represented in a factorized form using more than one tensor.
By default, calls to Bloq.tensor_contract() will first decompose and flatten the bloq
before initiating the conversion to a tensor network. This has two consequences:
Overriding this method is only necessary if this bloq does not define a decomposition or if the fully-decomposed form contains a bloq that does not define its tensors.
Even if you override this method to provide custom tensors, they may not be used (by default) because we prefer the flat-decomposed version. This is usually desirable for contraction performance; but for finer-grained control see
qualtran.simulation.tensor.cbloq_to_quimb.
Quimb defines a connection between two tensors by a shared index. The returned tensors from this method must use the Qualtran-Quimb index convention:
Each tensor index is a tuple
(cxn, j)The
cxn: qualtran.Connectionentry identifies the connection between bloq instances.The second integer
jis the bit index within high-bitsize registers, which is necessary due to technical restrictions.
Args
incomingA mapping from register name to Connection (or an array thereof) to use as left indices for the tensor network. The shape of the array matches the register’s shape.
outgoingA mapping from register name to Connection (or an array thereof) to use as right indices for the tensor network.
num_qubits
num_qubits() -> int
The number of qubits this gate acts on.
View source on GitHub