Source code for mimiqcircuits.gatedecl

#
# Copyright © 2022-2024 University of Strasbourg. All Rights Reserved.
# Copyright © 2032-2024 QPerfect. 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.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License 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 typing import List, Tuple
import mimiqcircuits as mc


[docs] class GateDecl: """ Simple declaration of gates using the @gatedecl decorator. Examples: **First way** >>> from symengine import symbols >>> from mimiqcircuits import * Define symbols for the gate arguments >>> x, y = symbols('x y') Declare a gate using the @gatedecl decorator >>> @gatedecl("ansatz") ... def ansatz(x): ... c = Circuit() ... c.push(GateX(), 0) ... c.push(GateRX(x), 1) ... return c Create a GateDecl object using the decorator >>> ansatz(x) ansatz(x) >>> ansatz(y) ansatz(y) Decompose >>> ansatz(x).decompose() 2-qubit circuit with 2 instructions: ├── X @ q[0] └── RX(x) @ q[1] <BLANKLINE> >>> ansatz(2).decompose() 2-qubit circuit with 2 instructions: ├── X @ q[0] └── RX(2) @ q[1] <BLANKLINE> **Second Way** >>> from symengine import * >>> from mimiqcircuits import * Define symbols for the gate arguments >>> x, y = symbols('x y') From a circuit, create a GateDecl object directly >>> c = Circuit() >>> c.push(GateXXplusYY(x,y), 0,1) 2-qubit circuit with 1 instructions: └── XXplusYY(x, y) @ q[0,1] <BLANKLINE> >>> c.push(GateRX(x), 1) 2-qubit circuit with 2 instructions: ├── XXplusYY(x, y) @ q[0,1] └── RX(x) @ q[1] <BLANKLINE> >>> gate_decl = GateDecl("ansatz", ('x','y'), c) >>> gate_decl gate ansatz(x, y) = ├── XXplusYY(x, y) @ q[0,1] └── RX(x) @ q[1] <BLANKLINE> >>> GateCall(gate_decl, (2,4)) ansatz(2, 4) Decompose the GateCall into a quantum circuit >>> GateCall(gate_decl, (2,4)).decompose() 2-qubit circuit with 2 instructions: ├── XXplusYY(2, 4) @ q[0,1] └── RX(2) @ q[1] <BLANKLINE> Add to Circuit >>> g = GateCall(gate_decl, (2,4)) >>> c = Circuit() >>> c.push(g,10,22) 23-qubit circuit with 1 instructions: └── ansatz(2, 4) @ q[10,22] <BLANKLINE> """ _name = "GateDecl" def __init__( self, name: str, arguments: Tuple[str, ...], circuit: mc.Circuit ): if not all(isinstance(arg, str) for arg in arguments): raise TypeError("All GateDecl arguments must be strings.") if len(circuit) == 0: raise ValueError("GateDecl cannot be defined from empty circuits.") for inst in circuit: # check if the instruction operation is from the Gate operation if not isinstance(inst.get_operation(), mc.Gate): raise ValueError("GateDecl instructions must be gates.") if inst.num_bits() != 0 or inst.num_zvars() != 0: raise ValueError("GateDecl instructions cannot have bits or zvars.") if inst.num_qubits() == 0: raise ValueError("GateDecl instructions must have qubits.") nq = circuit.num_qubits() np = len(arguments) super().__init__() self.name = name self.arguments = arguments self.circuit = circuit @property def num_qubits(self): return self.circuit.num_qubits() @num_qubits.setter def num_qubits(self, value): raise ValueError("Cannot set num_qubits. Read only parameter.") @property def num_bits(self): return self.circuit.num_bits() @num_bits.setter def num_bits(self, value): raise ValueError("Cannot set num_bits. Read only parameter.") @property def num_zvars(self): return self.circuit.num_zvars() @num_zvars.setter def num_zvars(self, value): raise ValueError("Cannot set num_zvars. Read only parameter.") def __str__(self): result = f"gate {self.name}({', '.join(map(str, self.arguments))}) =\n" N = len(self.circuit) for i, inst in enumerate(self.circuit): if i == N - 1: result += f"└── {inst}\n" else: result += f"├── {inst}\n" return result def __repr__(self): return str(self)
[docs] class GateCall(mc.Gate): """GateCall""" _name = "GateCall" _num_bits = 0 _num_qubits = None def __init__(self, decl: GateDecl, args: Tuple[float, ...]): if len(args) != len(decl.arguments): raise ValueError("Wrong number of arguments for GateCall.") self._num_qubits = decl.num_qubits self._decl = decl self._args = args def _matrix(self): pass
[docs] def decompose(self): circ = mc.Circuit() d = dict(zip(self._decl.arguments, self._args)) for inst in self._decl.circuit: op = inst.operation.evaluate(d) qubits = [i for i in inst.get_qubits()] bits = [i for i in inst.get_bits()] zvars = [i for i in inst.get_zvars()] circ.push(op, *qubits, *bits, *zvars) return circ
def _decompose(self, circ, qubits, bits, zvars): d = dict(zip(self._decl.arguments, self._args)) if len(qubits) != self._decl.num_qubits: raise ValueError("Wrong number of qubits for GateCall.") if len(bits) != self._decl.num_bits: raise ValueError("Wrong number of bits for GateCall.") if len(zvars) != self._decl.num_zvars: raise ValueError("Wrong number of zvars for GateCall.") for inst in self._decl.circuit: op = inst.operation.evaluate(d) # Map the instruction qubits to the actual qubits in the circuit inst_qubits = [qubits[q] for q in inst.get_qubits()] # Push the operation with the mapped qubits into the circuit circ.push(op, *inst_qubits, *bits, *zvars) return circ def __str__(self): return f"{self._decl.name}({', '.join(map(str, self._args))})"
[docs] def evaluate(self, d): new_args = [ arg.subs(d) if not isinstance(arg, (int, float)) else arg for arg in self._args ] return type(self)(self._decl, tuple(new_args))
[docs] def gatedecl(name): def decorator(func): def wrapper(*args, **kwargs): circ = func(*args, **kwargs) if not isinstance(circ, mc.Circuit): raise ValueError("GateDecl must return a Circuit object.") arguments = [str(arg) for arg in args] + [ f"{key}={value}" for key, value in kwargs.items() ] decl = GateDecl(name, arguments, circ) return GateCall(decl, args) return wrapper return decorator
__all__ = ["GateCall", "GateDecl", "gatedecl"]