Skip to content
Permalink
Browse files

fixed the compatibility of qiskit and sympy, and updated to able to c…

…alculate a controlled unitary operator (#26)

* fix sympy compatibility in tests (#25)
* fix qiskit version incompatibility (#23)
* updated to adapt some files to able to calculate a controlled unitary operator.
  • Loading branch information...
openql-org committed Jul 25, 2018
1 parent 7ca67d6 commit 47c7039ce093caa5f2f4724b9bfb387cdc6ae3b7
Showing with 418 additions and 108 deletions.
  1. +6 −6 quantpy/sympy/__init__.py
  2. +50 −4 quantpy/sympy/executor/_base_quantum_executor.py
  3. +7 −5 quantpy/sympy/executor/classical_simulation_executor.py
  4. +18 −9 quantpy/sympy/executor/ibmq_executor.py
  5. +1 −1 quantpy/sympy/executor/sympy_executor.py
  6. +41 −0 quantpy/sympy/executor/tests/test__base_quantum_executor.py
  7. +19 −1 quantpy/sympy/expr_extension.py
  8. +131 −0 quantpy/sympy/gate_extension.py
  9. +2 −0 quantpy/sympy/qapply.py
  10. +0 −1 quantpy/sympy/tests/sympy/physics/quantum/test_anticommutator.py
  11. +0 −1 quantpy/sympy/tests/sympy/physics/quantum/test_boson.py
  12. +0 −2 quantpy/sympy/tests/sympy/physics/quantum/test_cartesian.py
  13. +0 −1 quantpy/sympy/tests/sympy/physics/quantum/test_cg.py
  14. +0 −2 quantpy/sympy/tests/sympy/physics/quantum/test_circuitplot.py
  15. +0 −1 quantpy/sympy/tests/sympy/physics/quantum/test_circuitutils.py
  16. +0 −1 quantpy/sympy/tests/sympy/physics/quantum/test_commutator.py
  17. +0 −1 quantpy/sympy/tests/sympy/physics/quantum/test_constants.py
  18. +0 −1 quantpy/sympy/tests/sympy/physics/quantum/test_dagger.py
  19. +0 −1 quantpy/sympy/tests/sympy/physics/quantum/test_density.py
  20. +0 −1 quantpy/sympy/tests/sympy/physics/quantum/test_fermion.py
  21. +15 −3 quantpy/sympy/tests/sympy/physics/quantum/test_gate.py
  22. +1 −2 quantpy/sympy/tests/sympy/physics/quantum/test_grover.py
  23. +0 −1 quantpy/sympy/tests/sympy/physics/quantum/test_hilbert.py
  24. +0 −1 quantpy/sympy/tests/sympy/physics/quantum/test_identitysearch.py
  25. +0 −1 quantpy/sympy/tests/sympy/physics/quantum/test_innerproduct.py
  26. +0 −2 quantpy/sympy/tests/sympy/physics/quantum/test_matrixutils.py
  27. +1 −2 quantpy/sympy/tests/sympy/physics/quantum/test_operator.py
  28. +0 −1 quantpy/sympy/tests/sympy/physics/quantum/test_operatorordering.py
  29. +0 −2 quantpy/sympy/tests/sympy/physics/quantum/test_operatorset.py
  30. +0 −1 quantpy/sympy/tests/sympy/physics/quantum/test_pauli.py
  31. +0 −2 quantpy/sympy/tests/sympy/physics/quantum/test_piab.py
  32. +12 −18 quantpy/sympy/tests/sympy/physics/quantum/test_printing.py
  33. +1 −2 quantpy/sympy/tests/sympy/physics/quantum/test_qapply.py
  34. +0 −2 quantpy/sympy/tests/sympy/physics/quantum/test_qasm.py
  35. +0 −2 quantpy/sympy/tests/sympy/physics/quantum/test_qexpr.py
  36. +1 −2 quantpy/sympy/tests/sympy/physics/quantum/test_qft.py
  37. +1 −3 quantpy/sympy/tests/sympy/physics/quantum/test_qubit.py
  38. +1 −3 quantpy/sympy/tests/sympy/physics/quantum/test_represent.py
  39. +1 −3 quantpy/sympy/tests/sympy/physics/quantum/test_sho1d.py
  40. +1 −2 quantpy/sympy/tests/sympy/physics/quantum/test_shor.py
  41. +3 −5 quantpy/sympy/tests/sympy/physics/quantum/test_spin.py
  42. +0 −2 quantpy/sympy/tests/sympy/physics/quantum/test_state.py
  43. +6 −3 quantpy/sympy/tests/sympy/physics/quantum/test_tensorproduct.py
  44. +18 −4 ...tpy/sympy/tests/{sympy/physics/quantum/test_rshift_as_append_circuit.py → test_expr_extension.py}
  45. +42 −0 quantpy/sympy/tests/test_gate_extension.py
  46. +34 −0 quantpy/sympy/tests/test_qapply.py
  47. +5 −0 sync_sympy_tests.sh
@@ -13,10 +13,10 @@
# determine which names are imported when
# "from quantpy.sympy import *" is done.

#from .qapply import __all__ as qap_all
#from .qapply import *
#__all__.extend(qap_all)
from .qapply import __all__ as qap_all
from .qapply import *
__all__.extend(qap_all)

#from . import _quantumexecutor
#from ._quantumexecutor import *
#__all__.extend(_quantumexecutor.__all__)
from .gate_extension import __all__ as gate_ext_all
from .gate_extension import *
__all__.extend(gate_ext_all)
@@ -4,7 +4,9 @@
from abc import abstractmethod

import sympy
import qiskit
from qiskit.qasm._qasmparser import QasmParser
import quantpy.sympy.gate_extension

class BaseQuantumExecutor:
"""BaseQuantumExecutor Class
@@ -21,13 +23,17 @@ def execute(self, circuit, **options):
"""
return None

def to_qasm(self, sympy_expr):
def to_qasm(self, sympy_expr, **options):
"""QuantumExecutor classes' commom method.
Transform SymPy expression to OpenQASM format descriptions.
@return qasm format string.
"""
qasm = 'OPENQASM 2.0;\ninclude "qelib1.inc";\n'
with_measure = options.get('with_measure', False)
includes = options.get('includes', ['qelib1.inc'])
qasm = 'OPENQASM 2.0;\n'
for f in includes:
qasm += 'include "{0}";\n'.format(f)
assert isinstance(sympy_expr, sympy.mul.Mul), 'Sorry. Now, supported U*U*U*Qubit format'
qubit = sympy_expr.args[-1]
assert isinstance(qubit, sympy.physics.quantum.qubit.Qubit), 'Sorry. Now, supported U*U*U*Qubit format'
@@ -56,8 +62,48 @@ def to_qasm(self, sympy_expr):
qasm += 'cx qr[{}], qr[{}];\n'.format(int(gate.args[0]), int(gate.args[1]))
qasm += 'cx qr[{}], qr[{}];\n'.format(int(gate.args[1]), int(gate.args[0]))
qasm += 'cx qr[{}], qr[{}];\n'.format(int(gate.args[0]), int(gate.args[1]))
elif isinstance(gate, sympy.physics.quantum.gate.CGate):
if isinstance(gate.args[1], sympy.physics.quantum.gate.IdentityGate):
continue
t = gate.args[1].args[0]
if isinstance(gate.args[1], sympy.physics.quantum.gate.XGate):
qasm += 'cx qr[{}], qr[{}];\n'.format(tuple(gate.args[0])[0], t)
elif isinstance(gate.args[1], sympy.physics.quantum.gate.YGate):
qasm += 'sdg qr[{}];\n'.format(t)
qasm += 'cx qr[{}], qr[{}];\n'.format(tuple(gate.args[0])[0], t)
qasm += 's qr[{}];\n'.format(t)
elif isinstance(gate.args[1], sympy.physics.quantum.gate.ZGate):
qasm += 'h qr[{}];\n'.format(t)
qasm += 'cx qr[{}], qr[{}];\n'.format(tuple(gate.args[0])[0], t)
qasm += 'h qr[{}];\n'.format(t)
elif isinstance(gate, sympy.physics.quantum.gate.HadamardGate):
qasm += 'sdg qr[{}];\n'.format(t)
qasm += 'h qr[{}];\n'.format(t)
qasm += 'tdg qr[{}];\n'.format(t)
qasm += 'cx qr[{}], qr[{}];\n'.format(tuple(gate.args[0])[0], t)
qasm += 't qr[{}];\n'.format(t)
qasm += 'h qr[{}];\n'.format(t)
qasm += 's qr[{}];\n'.format(t)
elif isinstance(gate.args[1], sympy.physics.quantum.gate.PhaseGate):
c = tuple(gate.args[0])[0]
qasm += 't qr[{}];\n'.format(t)
qasm += 'cx qr[{}], qr[{}];\n'.format(c, t)
qasm += 'tdg qr[{}];\n'.format(t)
qasm += 'cx qr[{}], qr[{}];\n'.format(c, t)
qasm += 't qr[{}];\n'.format(c)
elif isinstance(gate.args[1], sympy.physics.quantum.gate.TGate):
c = tuple(gate.args[0])[0]
qasm += 'cu1(pi/4) qr[{}], qr[{}];\n'.format(c, t)
elif isinstance(gate.args[1], quantpy.sympy.Rk):
c = tuple(gate.args[0])[0]
r = gate.args[1]
k = r.k
qasm += 'cu1(pi/{}) qr[{}], qr[{}];\n'.format(k, c, t)
else:
assert False, '{} it is not a gate operator, nor is a supported operator'.format(repr(gate))
else:
assert False, '{} it is not a gate operator, nor is a supported operator'.format(repr(gate))
for i in range(len(qubit)):
qasm += 'measure qr[{0}] -> cr[{0}];\n'.format(i)
if with_measure:
for i in range(len(qubit)):
qasm += 'measure qr[{0}] -> cr[{0}];\n'.format(i)
return qasm
@@ -2,19 +2,22 @@
"""definition of ClassicalSimulationExecutor class
"""

import qiskit
import numpy as np
from qiskit import transpiler
from qiskit.backends.local import QasmSimulatorPy
from qiskit.wrapper._circuittoolkit import circuit_from_qasm_string

import qiskit._openquantumcompiler as openquantumcompiler
from quantpy.sympy.executor._base_quantum_executor import BaseQuantumExecutor
from quantpy.sympy.executor.simulator.numpy_simulator import NumpySimulator


class ClassicalSimulationExecutor(BaseQuantumExecutor):

def __init__(self):
super().__init__()
self.simulator = None


def execute(self, circuit, **options):
"""
Execute sympy-circuit with classical simulator
@@ -25,9 +28,8 @@ def execute(self, circuit, **options):
self.simulator = NumpySimulator()
basis_gates_str = (",".join(self.simulator.basis_gates)).lower()
# the following one-line compilation ignores basis_gates, and returnes "u2" for "h".
#json = openquantumcompiler.compile(qasm,basis_gates=basis_gates_str,format="json")
circuit_dag = openquantumcompiler.compile(qasm,basis_gates=basis_gates_str)
json = openquantumcompiler.dag2json(circuit_dag,basis_gates=basis_gates_str)
quantum_circuit = circuit_from_qasm_string(qasm)
json = transpiler.compile(quantum_circuit, basis_gates=basis_gates_str, backend=QasmSimulatorPy())["circuits"][0]["compiled_circuit"]
self.simulate(json)
return str(self.simulator)

@@ -44,14 +44,23 @@ def __init__(self, **options):

def execute(self, circuit, **options):
"""
The following options are valid:
* ``with_measure``: qapply with measure flag
(default: True).
"""
qasm = self.to_qasm(circuit)
with_measure = options.get('with_measure', True)
qasm = self.to_qasm(circuit, with_measure = with_measure)
name = self.qp.load_qasm_text(qasm)
qobj = self.qp.compile(name, backend=self.backend, shots=self.shots)
cnt = self.qp.run(qobj).get_counts(name)
self.qp.destroy_circuit(name)
for reg in list(self.qp.get_quantum_register_names()):
self.qp.destroy_quantum_register(reg)
for reg in list(self.qp.get_classical_register_names()):
self.qp.destroy_classical_register(reg)
return cnt
try:
qobj = self.qp.compile(name, backend=self.backend, shots=self.shots)
cnt = self.qp.run(qobj).get_counts(name)
self.qp.destroy_circuit(name)
for reg in list(self.qp.get_quantum_register_names()):
self.qp.destroy_quantum_register(reg)
for reg in list(self.qp.get_classical_register_names()):
self.qp.destroy_classical_register(reg)
return cnt
except qiskit._resulterror.ResultError as ex:
print("error:", ex.args)
return
@@ -2,7 +2,7 @@
"""definition of SymPyExdecutor class
"""
from sympy.physics.quantum.qapply import qapply as sympy_qapply
from quantpy.sympy.executor._base_quantum_executor import BaseQuantumExecutor
from ._base_quantum_executor import BaseQuantumExecutor

class SymPyExecutor(BaseQuantumExecutor):
"""SymPyExecutor Class for transparently executing sympy's qapply.
@@ -0,0 +1,41 @@
# -*- coding:utf-8 -*-

import textwrap
from sympy.physics.quantum.gate import H, X, Y, Z, CNOT, SWAP, CPHASE, CGate, CGateS
from sympy.physics.quantum.gate import IdentityGate, UGate
from sympy.physics.quantum.qubit import Qubit, QubitBra
from quantpy.sympy.executor._base_quantum_executor import BaseQuantumExecutor

def test_new_instanse():
executor = BaseQuantumExecutor()
assert executor != None

def test_execute():
executor = BaseQuantumExecutor()
c = H(0)*Qubit('0')
assert executor.execute(c) == None

def test_to_qasm_with_no_options():
executor = BaseQuantumExecutor()
c = H(0)*Qubit('0')
qasm = executor.to_qasm(c)
assert qasm.strip() == textwrap.dedent('''
OPENQASM 2.0;
include "qelib1.inc";
qreg qr[1];
creg cr[1];
h qr[0];
''').strip()

def test_to_qasm_with_includes():
executor = BaseQuantumExecutor()
c = H(0)*Qubit('0')
qasm = executor.to_qasm(c,includes=['qelib2.inc','qelib3.inc'])
assert qasm.strip() == textwrap.dedent('''
OPENQASM 2.0;
include "qelib2.inc";
include "qelib3.inc";
qreg qr[1];
creg cr[1];
h qr[0];
''').strip()
@@ -7,8 +7,26 @@ def _expr_rshift_as_multiplication_of_reverse_order(lhs, rhs):
"""
return rhs * lhs


def sympy_expr_add_operators():
"""oprators of the Expr instanse will be overrided by Local functions.
"""
sympy_expr_add_rshift()

def sympy_expr_remove_rshift():
"""remove __rshift__ attribute of the Expr instanse
"""
if hasattr(Expr, '__rshift__'):
del Expr.__rshift__

def sympy_expr_add_rshift():
"""__rshift__ of the Expr instanse will be overrided by Local function expr_rshift_as_multiplication_of_reverse_order.
"""
Expr.__rshift__ = _expr_rshift_as_multiplication_of_reverse_order

def sympy_expr_toggle_rshift():
"""toggle __rshift__ attribute of the Expr instanse.
"""
if hasattr(Expr, '__rshift__'):
sympy_expr_remove_rshift()
else:
sympy_expr_add_rshift()
@@ -0,0 +1,131 @@
"""Gate Extension
"""

from sympy.core.compatibility import is_sequence
from sympy import cos, exp, expand, I, Matrix, pi, S, sin, sqrt, Sum, symbols
from sympy.external import import_module
from sympy.physics.quantum.qexpr import QuantumError, QExpr
from sympy.physics.quantum.gate import Gate, UGate, OneQubitGate
from sympy.physics.quantum.gate import _validate_targets_controls
from sympy.physics.quantum.qft import RkGate, Rk
# from sympy.physics.quantum.circuitplot import Mz, Mx

from sympy import Expr, Matrix, exp, I, pi, Integer, Symbol
from sympy.functions import sqrt

__all__ = [
'Mz',
'Mx',
'Rx',
'Ry',
'Rz',
'RkGate',
'Rk',
]

class Rx(UGate):
"""Rx(theta) gate.
= Exp{-i*theta*XGate/2}
"""
gate_name='Rx'
gate_name_latex=u'Rx'

#-------------------------------------------------------------------------
# Initialization
#-------------------------------------------------------------------------

@classmethod
def _eval_args(cls, args):
targets = args[0]
theta = args[1]
mat = Matrix([[cos(theta/2), -I*sin(theta/2)], [-I*sin(theta/2), cos(theta/2)]])
return UGate._eval_args([targets, mat])

class Ry(UGate):
"""Ry(theta) gate.
= Exp{-i*theta*ZGate/2}
"""
gate_name='Ry'
gate_name_latex=u'Ry'

#-------------------------------------------------------------------------
# Initialization
#-------------------------------------------------------------------------

@classmethod
def _eval_args(cls, args):
targets = args[0]
theta = args[1]
mat = Matrix([[cos(theta/2), -sin(theta/2)], [sin(theta/2), cos(theta/2)]])
return UGate._eval_args([targets, mat])

class Rz(UGate):
"""Rz(theta) gate.
= Exp{-i*theta*ZGate/2}
"""
gate_name='Rz'
gate_name_latex=u'Rz'

#-------------------------------------------------------------------------
# Initialization
#-------------------------------------------------------------------------

@classmethod
def _eval_args(cls, args):
targets = args[0]
theta = args[1]
mat = Matrix([[exp(-I*theta/2), 0], [0, exp(I*theta/2)]])
return UGate._eval_args([targets, mat])

class Mz(OneQubitGate):
"""Mock-up of a z measurement gate.
This is in circuitplot rather than gate.py because it's not a real
gate, it just draws one.
"""
measurement = True
gate_name='Mz'
gate_name_latex=u'M_z'

def __new__(cls, *args):
args = cls._eval_args(args)
inst = Expr.__new__(cls, *args)
inst.hilbert_space = cls._eval_hilbert_space(args)
return inst

@classmethod
def _eval_args(cls, args):
# Fall back to this, because Gate._eval_args assumes that args is
# all targets and can't contain duplicates.
return QExpr._eval_args(args)

@property
def gate_name_plot(self):
return self.gate_name_latex

class Mx(OneQubitGate):
"""Mock-up of an x measurement gate.
This is in circuitplot rather than gate.py because it's not a real
gate, it just draws one.
"""
measurement = True
gate_name='Mx'
gate_name_latex=u'M_x'

def __new__(cls, *args):
args = cls._eval_args(args)
inst = Expr.__new__(cls, *args)
inst.hilbert_space = cls._eval_hilbert_space(args)
return inst

@classmethod
def _eval_args(cls, args):
# Fall back to this, because Gate._eval_args assumes that args is
# all targets and can't contain duplicates.
return QExpr._eval_args(args)

@property
def gate_name_plot(self):
return self.gate_name_latex

@@ -2,6 +2,8 @@
"""Logic for applying operators to states.
"""

__all__ = ['qapply']

from quantpy.sympy.executor.sympy_executor import SymPyExecutor

def qapply(circuit, **options):
@@ -4,7 +4,6 @@
from sympy.physics.quantum.anticommutator import AntiCommutator as AComm
from sympy.physics.quantum.operator import Operator

from quantpy.sympy.qapply import qapply

a, b, c = symbols('a,b,c')
A, B, C, D = symbols('A,B,C,D', commutative=False)
Oops, something went wrong.

0 comments on commit 47c7039

Please sign in to comment.
You can’t perform that action at this time.