diff --git a/quafu/circuits/quantum_circuit.py b/quafu/circuits/quantum_circuit.py index 684e3cb..075e447 100644 --- a/quafu/circuits/quantum_circuit.py +++ b/quafu/circuits/quantum_circuit.py @@ -182,15 +182,11 @@ def layered_circuit(self) -> np.ndarray: gateQlist = [[] for i in range(num)] used_qubits = [] for gate in gatelist: - if ( - isinstance(gate, SingleQubitGate) - or isinstance(gate, Delay) - or isinstance(gate, QuantumPulse) - ): - gateQlist[gate.pos].append(gate) + if len(gate.pos) == 1: + p = gate.pos[0] + gateQlist[p].append(gate) if gate.pos not in used_qubits: used_qubits.append(gate.pos) - elif ( isinstance(gate, Barrier) or isinstance(gate, MultiQubitGate) @@ -202,7 +198,7 @@ def layered_circuit(self) -> np.ndarray: for j in range(pos1 + 1, pos2 + 1): gateQlist[j].append(None) - if isinstance(gate, MultiQubitGate) or isinstance(gate, XYResonance): + if isinstance(gate, (MultiQubitGate, XYResonance)): for pos in gate.pos: if pos not in used_qubits: used_qubits.append(pos) diff --git a/quafu/elements/instruction.py b/quafu/elements/instruction.py index 7994fcb..d86f682 100644 --- a/quafu/elements/instruction.py +++ b/quafu/elements/instruction.py @@ -13,21 +13,29 @@ # limitations under the License. from abc import ABC, abstractmethod -from typing import Dict, List, Optional, Union +from typing import Dict, List, Optional, Union, Any from .parameters import ParameterType __all__ = ["Instruction", "Barrier", "Measure", "PosType", "Reset"] -PosType = Union[int, List[int]] +PosType = Union[int] # TODO: include qubits class Instruction(ABC): """Base class for ALL the possible instructions on Quafu superconducting quantum circuits. Attributes: - pos: Qubit position(s) of the instruction on the circuit. - paras: Parameters of the instruction. + pos: Qubit position(s) list of the instruction on the circuit. + paras: Parameter list of the instruction. + + Properties: + symbol: Text symbolic representation of this gate. + + Functions: + register_gate: Register a new gate class. + to_qasm: Convert this gate to QASM format. + update_paras: Update the parameters of this gate. """ @@ -35,14 +43,32 @@ class Instruction(ABC): def __init__( self, - pos: PosType, + pos: Union[PosType, List[PosType]], paras: Optional[Union[ParameterType, List[ParameterType]]] = None, *args, **kwargs, ): + self.__init_pos__(pos) + self.__init_paras__(paras) + self._symbol = None + + def __init_pos__(self, pos: Any): + """If pos is not a list of PoseType objects, make it so.""" + if isinstance(pos, PosType): + pos = [pos] + elif not isinstance(pos, List): + raise ValueError('pos must be in PoseType or a list of PoseType objects') self.pos = pos + + def __init_paras__(self, paras: Any): + """If paras is not a list of ParameterType objects, make it so.""" + if paras is None: + paras = [] + elif not isinstance(paras, List): + if not isinstance(paras, ParameterType): + raise ValueError('paras must be in ParameterType or a list of ParameterType objects') + paras = [paras] self.paras = paras - self._symbol = None @property @abstractmethod @@ -95,6 +121,7 @@ def to_qasm(self): pass +@Instruction.register('barrier') class Barrier(Instruction): """ Barrier instruction. @@ -137,6 +164,7 @@ def to_qasm(self): ) +@Instruction.register('reset') class Reset(Instruction): name = "reset" @@ -168,6 +196,7 @@ def to_qasm(self): ) +@Instruction.register('measure') class Measure(Instruction): """ Measure instruction. @@ -195,7 +224,3 @@ def to_qasm(self): ] qasm = "".join(lines) return qasm - - -Instruction.register_ins(Barrier) -Instruction.register_ins(Measure) diff --git a/quafu/elements/oracle.py b/quafu/elements/oracle.py index 070bf0e..82aad6c 100644 --- a/quafu/elements/oracle.py +++ b/quafu/elements/oracle.py @@ -88,8 +88,19 @@ def named_paras(self) -> Dict: return self._named_pos def to_qasm(self): - # TODO: this is similar to QuantumCircuit.to_qasm - raise NotImplemented + if len(self.gate_structure) > 0: + return super().to_qasm() + else: + # TODO: decompose matrix in a Just-In-Time style + raise NotImplemented + + @property + def circuit(self): + from quafu import QuantumCircuit + qc = QuantumCircuit(self.qubit_num) + for gate in self.insides: + qc.add_gate(gate) + return qc def __instantiate_gates__(self) -> None: """ diff --git a/quafu/elements/quantum_gate.py b/quafu/elements/quantum_gate.py index a2482ca..1cb541d 100644 --- a/quafu/elements/quantum_gate.py +++ b/quafu/elements/quantum_gate.py @@ -14,7 +14,7 @@ import copy -from abc import ABC, abstractmethod +from abc import ABC from typing import Callable, Dict, Iterable, List, Optional, Union import numpy as np @@ -61,12 +61,7 @@ class QuantumGate(Instruction, ABC): """Base class for standard and combined quantum gates, namely unitary operation upon quantum states. - Attributes: - pos: Position of this gate in the circuit. - paras: Parameters of this gate. - Properties: - symbol: Text symbolic representation of this gate. matrix: Matrix representation of this gate. Functions: @@ -74,13 +69,14 @@ class QuantumGate(Instruction, ABC): to_qasm: Convert this gate to QASM format. update_paras: Update the parameters of this gate. + see docstring of Instruction for other members. """ gate_classes = {} def __init__( self, - pos: PosType, + pos: Union[PosType, List[PosType]], paras: Optional[Union[ParameterType, List[ParameterType]]] = None, matrix: Optional[Union[ndarray, Callable]] = None, ): @@ -160,14 +156,17 @@ def symbol(self, symbol: str): self._symbol = symbol @property - @abstractmethod - def matrix(self): - if self._matrix is not None: + def matrix(self) -> ndarray: + """Return numpy.ndarray matrix representation, real-time updated with parameters, if any.""" + if isinstance(self._matrix, ndarray): return self._matrix + elif isinstance(self._matrix, Callable): + paras = [float(p) for p in self.paras] # TODO: check that if float() is well supported + return self._matrix(paras) else: raise NotImplementedError( "Matrix is not implemented for %s" % self.__class__.__name__ - + ", this should never happen." + + ". This should never happen, please report it on our github page." ) def to_qasm(self) -> str: @@ -370,8 +369,8 @@ class ControlledGate(MultiQubitGate): def __init__( self, targ_name: str, - ctrls: PosType, - targs: PosType, + ctrls: Union[PosType, List[PosType]], + targs: Union[PosType, List[PosType]], paras: Optional[Union[ParameterType, List[ParameterType]]] = None, tar_matrix: MatrixType = None, ): @@ -408,11 +407,6 @@ def symbol(self): def symbol(self, symbol): self._symbol = symbol - @property - def matrix(self): - # TODO: update matrix when paras of controlled-gate changed - return self._matrix - @property def ct_nums(self): targ_num = len(self.targs) @@ -423,7 +417,7 @@ def ct_nums(self): @property def targ_matrix(self): if isinstance(self._targ_matrix, Callable): - return self._targ_matrix(self.paras) + return self._targ_matrix(*self.paras) else: return self._targ_matrix