Skip to content

Commit

Permalink
feat: sync quafu-merge
Browse files Browse the repository at this point in the history
  • Loading branch information
Zhaoyilunnn committed Jan 11, 2024
1 parent 177b9b2 commit 702550f
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 51 deletions.
6 changes: 2 additions & 4 deletions quafu/elements/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
from .instruction import Instruction, Barrier, Measure, Reset
from .pulses import Delay, XYResonance, QuantumPulse
from .quantum_gate import QuantumGate, ControlledGate, MultiQubitGate, SingleQubitGate
from .classical_element import Cif
from .instruction import Barrier, Instruction, Measure, Reset
from .pulses import Delay, QuantumPulse, XYResonance
from .utils import extract_float, reorder_matrix
from .quantum_gate import ControlledGate, MultiQubitGate, QuantumGate, SingleQubitGate
from .unitary import UnitaryDecomposer
from .utils import extract_float, reorder_matrix
133 changes: 87 additions & 46 deletions quafu/elements/quantum_gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,44 @@

import copy
from abc import ABC, abstractmethod
from typing import Dict, Iterable, List, Optional, Union, Callable
from typing import Callable, Dict, Iterable, List, Optional, Union

import numpy as np
from numpy import ndarray

from quafu.elements.matrices.mat_utils import reorder_matrix

from .instruction import Instruction, PosType
from .oracle import OracleGate
from .parameters import ParameterType
from .utils import extract_float

__all__ = ['QuantumGate', 'FixedGate', 'ParametricGate', 'SingleQubitGate', 'MultiQubitGate', 'ControlledGate']


HERMITIAN = ['id', 'x', 'y', 'z', 'h', 'w', 'cx', 'cz', 'cy', 'cnot', 'swap', 'mcx', 'mxy', 'mcz']
ROTATION = ['rx', 'ry', 'rz', 'p', 'rxx', 'ryy', 'rzz', 'cp']
paired = {k: k+'dg' for k in ['sx', 'sy', 's', 't', 'sw']}
__all__ = [
"QuantumGate",
"FixedGate",
"ParametricGate",
"SingleQubitGate",
"MultiQubitGate",
"ControlledGate",
]


HERMITIAN = [
"id",
"x",
"y",
"z",
"h",
"w",
"cx",
"cz",
"cy",
"cnot",
"swap",
"mcx",
"mxy",
"mcz",
]
ROTATION = ["rx", "ry", "rz", "p", "rxx", "ryy", "rzz", "cp"]
paired = {k: k + "dg" for k in ["sx", "sy", "s", "t", "sw"]}
PAIRED = {**paired, **{v: k for k, v in paired.items()}}


Expand All @@ -57,26 +77,35 @@ class QuantumGate(Instruction, ABC):
update_paras: Update the parameters of this gate.
"""

gate_classes = {}

def __init__(self,
pos: PosType,
paras: Optional[Union[ParameterType, List[ParameterType]]] = None,
matrix: Optional[Union[ndarray, Callable]] = None,
):
def __init__(
self,
pos: PosType,
paras: Optional[Union[ParameterType, List[ParameterType]]] = None,
matrix: Optional[Union[ndarray, Callable]] = None,
):
super().__init__(pos, paras)
self._symbol = None
self._matrix = matrix

def __str__(self):
# only when the gate is a known(named) gate, the matrix is not shown
if self.name.lower() in self.gate_classes:
properties_names = ['pos', 'paras']
properties_names = ["pos", "paras"]
else:
properties_names = ['pos', 'paras', 'matrix']
properties_names = ["pos", "paras", "matrix"]
properties_values = [getattr(self, x) for x in properties_names]
return "%s:\n%s" % (self.__class__.__name__, '\n'.join(
[f"{x} = {repr(properties_values[i])}" for i, x in enumerate(properties_names)]))
return "%s:\n%s" % (
self.__class__.__name__,
"\n".join(
[
f"{x} = {repr(properties_values[i])}"
for i, x in enumerate(properties_names)
]
),
)

def __repr__(self):
return f"{self.__class__.__name__}"
Expand Down Expand Up @@ -120,9 +149,9 @@ def symbol(self) -> str:
# TODO: Use latex repr for Parameter
if self.paras is not None:
symbol = (
"%s(" % self.name
+ ",".join(["%.3f" % para for para in self._paras])
+ ")"
"%s(" % self.name
+ ",".join(["%.3f" % para for para in self._paras])
+ ")"
)
return symbol
else:
Expand All @@ -138,8 +167,10 @@ def matrix(self):
if self._matrix is not None:
return self._matrix
else:
raise NotImplementedError("Matrix is not implemented for %s" % self.__class__.__name__ +
", this should never happen.")
raise NotImplementedError(
"Matrix is not implemented for %s" % self.__class__.__name__
+ ", this should never happen."
)

def to_qasm(self) -> str:
"""OPENQASM 2.0"""
Expand Down Expand Up @@ -180,8 +211,12 @@ def power(self, n) -> "QuantumGate":
# TODO: decide order-2/4 gate
raise NotImplementedError
else:
from ..elements import OracleGate

if not isinstance(self, OracleGate):
raise NotImplementedError(f"Power is not implemented for {self.__class__.__name__}")
raise NotImplementedError(
f"Power is not implemented for {self.__class__.__name__}"
)
else:
gate = copy.deepcopy(self)
gate.gate_structure = [gate.power(n) for gate in self.gate_structure]
Expand All @@ -193,12 +228,16 @@ def dagger(self) -> "QuantumGate":
return copy.deepcopy(self)
if name in ROTATION: # rotation gate
return self.gate_classes[name](self.pos, -self.paras)
elif name in PAIRED: # pairwise-occurrence gate
elif name in PAIRED: # pairwise-occurrence gate
_conj_name = PAIRED[name]
return self.gate_classes[name](self.pos)
else:
from ..elements import OracleGate

if not isinstance(self, OracleGate):
raise NotImplementedError(f"Power is not implemented for {self.__class__.__name__}")
raise NotImplementedError(
f"Power is not implemented for {self.__class__.__name__}"
)
else:
gate = copy.deepcopy(self)
gate.gate_structure = [gate.dagger() for gate in self.gate_structure]
Expand All @@ -218,7 +257,7 @@ def ctrl_by(self, ctrls: Union[int, List[int]]) -> "QuantumGate":
raise NotImplementedError

name = self.name.lower()
if name in ['x', 'y', 'z']:
if name in ["x", "y", "z"]:
cname = "mc" + self.name.lower()
cop = self.gate_classes[cname](ctrls, self.pos)
return cop
Expand All @@ -234,6 +273,7 @@ def ctrl_by(self, ctrls: Union[int, List[int]]) -> "QuantumGate":
# inferred from ``pos``, while para/fixed type may be inferred by ``paras``.
# Therefore, these types may be (partly) deprecated in the future.


class SingleQubitGate(QuantumGate, ABC):
def __init__(self, pos: int, paras: Optional[ParameterType] = None):
QuantumGate.__init__(self, pos=pos, paras=paras)
Expand All @@ -243,22 +283,20 @@ def get_targ_matrix(self):

@property
def named_pos(self) -> Dict:
return {'pos': self.pos}
return {"pos": self.pos}


class MultiQubitGate(QuantumGate, ABC):
def __init__(self, pos: List, paras: Optional[ParameterType] = None):
QuantumGate.__init__(self, pos, paras)

def get_targ_matrix(self, reverse_order=False):
"""
"""
""" """
targ_matrix = self.matrix

if reverse_order and (len(self.pos) > 1):
qnum = len(self.pos)
dim = 2 ** qnum
dim = 2**qnum
order = np.array(range(len(self.pos))[::-1])
order = np.concatenate([order, order + qnum])
tensorm = targ_matrix.reshape([2] * 2 * qnum)
Expand All @@ -274,11 +312,11 @@ def __init__(self, pos: PosType, paras: Union[ParameterType, List[ParameterType]

@property
def named_paras(self) -> Dict:
return {'paras': self.paras}
return {"paras": self.paras}

@property
def named_pos(self) -> Dict:
return {'pos': self.pos}
return {"pos": self.pos}


class FixedGate(QuantumGate, ABC):
Expand All @@ -291,14 +329,16 @@ def named_paras(self) -> Dict:


class ControlledGate(MultiQubitGate):
""" Controlled gate class, where the matrix act non-trivially on target qubits"""

def __init__(self,
targ_name: str,
ctrls: PosType,
targs: PosType,
paras: Optional[Union[ParameterType, List[ParameterType]]] = None,
tar_matrix: MatrixType = None):
"""Controlled gate class, where the matrix act non-trivially on target qubits"""

def __init__(
self,
targ_name: str,
ctrls: PosType,
targs: PosType,
paras: Optional[Union[ParameterType, List[ParameterType]]] = None,
tar_matrix: MatrixType = None,
):
MultiQubitGate.__init__(self, ctrls + targs, paras)
self.ctrls = ctrls
self.targs = targs
Expand All @@ -310,16 +350,16 @@ def __build_matrix__(self):
# set matrix
# TODO: change matrix according to control-type 0/1
c_n, t_n, n = self.ct_nums
targ_dim = 2 ** t_n
dim = 2 ** n
targ_dim = 2**t_n
dim = 2**n
ctrl_dim = dim - targ_dim
self._matrix = np.eye(dim, dtype=complex)
self._matrix[ctrl_dim:, ctrl_dim:] = self.targ_matrix
self._matrix = reorder_matrix(self._matrix, self.pos)

@property
def name(self) -> str:
return 'c' + self.targ_name
return "c" + self.targ_name

@property
def symbol(self):
Expand Down Expand Up @@ -357,7 +397,7 @@ def get_targ_matrix(self, reverse_order=False):
qnum = len(self.targs)
order = np.array(range(len(self.targs))[::-1])
order = np.concatenate([order, order + qnum])
dim = 2 ** qnum
dim = 2**qnum
tensorm = targ_matrix.reshape([2] * 2 * qnum)
targ_matrix = np.transpose(tensorm, order).reshape([dim, dim])
return targ_matrix
Expand All @@ -374,6 +414,7 @@ def named_paras(self) -> Dict:
def from_target(cls, targ: QuantumGate, ctrls: PosType):
return cls(targ.name, ctrls, targ.pos, targ.paras, targ.matrix)


# TODO(ChenWei): update OracleGate so that compatible with CtrlGate
# class CircuitWrapper(QuantumGate):
# def __init__(self, name: str, circ, qbits=[]):
Expand Down
2 changes: 1 addition & 1 deletion tests/quafu/circuits/building_circuit_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from quafu.circuits import QuantumCircuit


class BuildingCircuitTest:
class TestBuildingCircuit:
def test_add(self):
q = QuantumCircuit(3)
q << (qeg.XGate(1))
Expand Down

0 comments on commit 702550f

Please sign in to comment.