-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge commit: re-implement symbolic evaluation using sympy quantum me…
…chanics module
- Loading branch information
1 parent
9412a5f
commit 2dcd284
Showing
51 changed files
with
1,433 additions
and
1,104 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,3 @@ | ||
"""Qiskit symbolic module""" | ||
|
||
from .quantum_info import ( | ||
Statevector, | ||
DensityMatrix, | ||
Operator | ||
) | ||
from .quantum_info import Statevector, Operator |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,70 @@ | ||
"""Symbolic quantum circuit module""" | ||
|
||
from .gate import Gate | ||
from .controlledgate import ControlledGate | ||
from qiskit.circuit.controlledgate import ControlledGate | ||
from .library import * | ||
|
||
|
||
name2class = { | ||
'id': IGate, | ||
'x': XGate, | ||
'cx': CXGate, | ||
'y': YGate, | ||
'cy': CYGate, | ||
'z': ZGate, | ||
'cz': CZGate, | ||
'h': HGate, | ||
'ch': CHGate, | ||
'sx': SXGate, | ||
'sxdg': SXdgGate, | ||
'csx': CSXGate, | ||
'csxdg': CSXdgGate, | ||
's': SGate, | ||
'sdg': SdgGate, | ||
'cs': CSGate, | ||
'csdg': CSdgGate, | ||
't': TGate, | ||
'tdg': TdgGate, | ||
'ct': CTGate, | ||
'ctdg': CTdgGate, | ||
'swap': SwapGate, | ||
'iswap': iSwapGate, | ||
'dcx': DCXGate, | ||
'ecr': ECRGate, | ||
'u': UGate, | ||
'cu': CUGate, | ||
'u1': U1Gate, | ||
'cu1': CU1Gate, | ||
'u2': U2Gate, | ||
'cu2': CU2Gate, | ||
'u3': U3Gate, | ||
'cu3': CU3Gate, | ||
'rx': RXGate, | ||
'crx': CRXGate, | ||
'ry': RYGate, | ||
'cry': CRYGate, | ||
'rz': RZGate, | ||
'crz': CRZGate, | ||
'p': PhaseGate, | ||
'cp': CPhaseGate, | ||
'r': RGate, | ||
'cr': CRGate, | ||
'rxx': RXXGate, | ||
'ryy': RYYGate, | ||
'rzz': RZZGate, | ||
'rzx': RZXGate, | ||
'xx_minus_yy': XXMinusYYGate, | ||
'xx_plus_yy': XXPlusYYGate, | ||
} | ||
|
||
|
||
def get_class(op): | ||
"""todo""" | ||
if isinstance(op, ControlledGate): | ||
name = 'c' + op.base_gate.name | ||
else: | ||
name = op.name | ||
try: | ||
return name2class[name] | ||
except KeyError as kerr: | ||
error_message = f'Gate "{name}" is not implemented in qiskit-symb' | ||
raise NotImplementedError(error_message) from kerr |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,45 +1,16 @@ | ||
"""Symbolic controlled gate module""" | ||
|
||
import numpy | ||
import sympy | ||
from sympy.matrices import Matrix | ||
from sympy.physics.quantum import TensorProduct | ||
from sympy.physics.quantum.gate import CGate | ||
from .gate import Gate | ||
|
||
|
||
class ControlledGate(Gate): | ||
"""Symbolic controlled gate base class""" | ||
class ControlledGate(Gate, CGate): | ||
"""Symbolic controlled gate abstract class""" | ||
|
||
def __init__(self, name, num_qubits, params, base_gate, num_ctrl_qubits, ctrl_state): | ||
def __new__(cls, controls, target_gate): | ||
"""todo""" | ||
super().__init__(name=name, num_qubits=num_qubits, params=params) | ||
self.base_gate = base_gate | ||
self.num_ctrl_qubits = num_ctrl_qubits | ||
self.ctrl_state = '1' * num_ctrl_qubits if ctrl_state is None else ctrl_state | ||
return CGate.__new__(cls, *controls, target_gate) | ||
|
||
@staticmethod | ||
def get(instruction): | ||
def get_target_matrix(self, format='sympy'): | ||
"""todo""" | ||
from ..utils import get_init | ||
gate = instruction.op | ||
name = 'c' + gate.base_gate.name | ||
num_ctrl_qubits = gate.num_ctrl_qubits | ||
ctrl_state = format(gate.ctrl_state, 'b').zfill(num_ctrl_qubits) | ||
return get_init(name)(*gate.params, num_ctrl_qubits=num_ctrl_qubits, ctrl_state=ctrl_state) | ||
|
||
def __sympy__(self): | ||
"""todo""" | ||
proj = {'0': Matrix([[1, 0], [0, 0]]), | ||
'1': Matrix([[0, 0], [0, 1]])} | ||
sympy_matrix = sympy.zeros(2**self.num_qubits) | ||
for state in range(2**self.num_ctrl_qubits): | ||
bitstring = format(state, 'b').zfill(self.num_ctrl_qubits) | ||
factors = [proj[bit] for bit in bitstring] | ||
if bitstring == self.ctrl_state: | ||
matrix = self.base_gate.__sympy__() | ||
term = TensorProduct(matrix, *factors) | ||
else: | ||
identity = Matrix(numpy.eye(2**self.base_gate.num_qubits)) | ||
term = TensorProduct(identity, *factors) | ||
sympy_matrix += term | ||
return sympy_matrix | ||
return self.gate._sympy_matrix() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,56 +1,80 @@ | ||
"""Symbolic gate module""" | ||
|
||
import numpy | ||
from sympy import matrix2numpy | ||
from qiskit.circuit import ControlledGate as QiskitControlledGate | ||
from sympy import Matrix, eye, zeros, sympify | ||
from sympy.physics.quantum.matrixutils import matrix_tensor_product | ||
from sympy.physics.quantum.gate import Gate as SympyGate | ||
|
||
|
||
class Gate: | ||
"""Symbolic gate base class""" | ||
op00 = Matrix([[1, 0], [0, 0]]) # |0><0| | ||
op01 = Matrix([[0, 1], [0, 0]]) # |0><1| | ||
op10 = Matrix([[0, 0], [1, 0]]) # |1><0| | ||
op11 = Matrix([[0, 0], [0, 1]]) # |1><1| | ||
|
||
def __init__(self, name, num_qubits, params): | ||
|
||
class Gate(SympyGate): | ||
"""Symbolic gate abstract class""" | ||
|
||
def __new__(cls, params, qubits): | ||
"""todo""" | ||
symbols = Gate.get_symbols(params=params) | ||
return super().__new__(cls, *symbols, *qubits) | ||
|
||
@property | ||
def nqubits(self): | ||
"""todo""" | ||
self.name = name | ||
self.num_qubits = num_qubits | ||
self.params = params | ||
return len(self.qubits) | ||
|
||
@property | ||
def label(self): | ||
"""todo""" | ||
return super().label[-self.nqubits:] | ||
|
||
@staticmethod | ||
def get(instruction): | ||
def get_symbols(params): | ||
"""todo""" | ||
from .controlledgate import ControlledGate | ||
from ..utils import get_init | ||
gate = instruction.op | ||
if isinstance(gate, QiskitControlledGate): | ||
return ControlledGate.get(instruction) | ||
return get_init(gate.name)(*gate.params) | ||
symbols = set() | ||
for param in params: | ||
if hasattr(param, '_symbol_expr'): | ||
symbols.update(param._symbol_expr.free_symbols) | ||
symbols = sorted(symbols, key=lambda s: s.name) | ||
return symbols | ||
|
||
def _get_params_expr(self): | ||
@staticmethod | ||
def get(gate_node): | ||
"""todo""" | ||
from ..utils import get_symbolic_expr | ||
return [get_symbolic_expr(par) for par in self.params] | ||
from . import get_class | ||
_class = get_class(op=gate_node.op) | ||
params = gate_node.op.params | ||
qubits = (qarg._index for qarg in gate_node.qargs) | ||
return _class(*params, *qubits) | ||
|
||
def _get_unique_symbols(self): | ||
def _define_matrix(self, coeff_ops, nqubits): | ||
"""todo""" | ||
from ..utils import get_unique_symbols | ||
sympy_symbols = [] | ||
for par in self.params: | ||
sympy_symbols.extend(get_unique_symbols(par)) | ||
return list(dict.fromkeys(sympy_symbols)) | ||
matrix = sum((coeff * matrix_tensor_product( | ||
*(ops[0] if i == nqubits - self.targets[0] - 1 else | ||
ops[1] if i == nqubits - self.targets[1] - 1 else | ||
eye(2) for i in range(nqubits))) | ||
for coeff, ops in coeff_ops), | ||
start=zeros(2**nqubits)) | ||
return matrix | ||
|
||
def _get_tensor(self): | ||
def get_params_expr(self): | ||
"""todo""" | ||
sympy_matrix = self.__sympy__() | ||
newshape = (2, 2) * self.num_qubits | ||
return numpy.reshape(sympy_matrix, newshape) | ||
params_expr = tuple(sympify(par._symbol_expr) | ||
if hasattr(par, '_symbol_expr') else par | ||
for par in self.params) | ||
return params_expr | ||
|
||
def to_sympy(self): | ||
def get_target_matrix(self, format='sympy'): | ||
"""todo""" | ||
from ..utils import symbols2real | ||
sympy_matrix = self.__sympy__() | ||
return symbols2real(sympy_matrix) | ||
return self._sympy_matrix() | ||
|
||
def to_numpy(self, *vals): | ||
def _latex(self, printer, *args): | ||
"""todo""" | ||
sympy_symbols = self._get_unique_symbols() | ||
sympy_matrix = self.__sympy__().subs(dict(zip(sympy_symbols, vals))) | ||
return matrix2numpy(sympy_matrix, dtype=complex) | ||
controls = getattr(self, 'controls', ()) | ||
qubits_label = ','.join(str(s) for s in controls + self.targets) | ||
params_label = ','.join(str(s) for s in self.params[:3]) | ||
latex_repr = '%s_{%s}' % (self.gate_name_latex, qubits_label) | ||
if self.params: | ||
latex_repr += f'({params_label})' | ||
return latex_repr |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
11 changes: 7 additions & 4 deletions
11
src/qiskit_symb/circuit/library/parametric_gates/__init__.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,17 @@ | ||
"""Symbolic parametric gates module""" | ||
|
||
from .u import UGate, CUGate | ||
from .u import U1Gate, CU1Gate | ||
from .u import U2Gate, CU2Gate | ||
from .u import U3Gate, CU3Gate | ||
from .rx import RXGate, CRXGate | ||
from .ry import RYGate, CRYGate | ||
from .rz import RZGate, CRZGate | ||
from .p import PhaseGate, CPhaseGate | ||
from .r import RGate, CRGate | ||
from .rxx import RXXGate, CRXXGate | ||
from .ryy import RYYGate, CRYYGate | ||
from .rzz import RZZGate, CRZZGate | ||
from .rzx import RZXGate, CRZXGate | ||
from .rxx import RXXGate | ||
from .ryy import RYYGate | ||
from .rzz import RZZGate | ||
from .rzx import RZXGate | ||
from .xx_minus_yy import XXMinusYYGate | ||
from .xx_plus_yy import XXPlusYYGate |
Oops, something went wrong.