softwareQinc / staq

Full-stack quantum processing toolkit
https://iopscience.iop.org/article/10.1088/2058-9565/ab9359/pdf
MIT License
154 stars 28 forks source link

OpenQASM->ProjectQ minor issues #38

Closed vsoftco closed 3 years ago

vsoftco commented 3 years ago

When transpiling from OpenQASM to ProjectQ the minimal example

OPENQASM 2.0;
include "qelib1.inc";

the code produced is

from projectq import MainEngine, ops
from cmath import pi,exp,sin,cos,tan,log as ln,sqrt
import numpy as np

def SdagGate(): return ops.Sdag
def TdagGate(): return ops.Tdag
def CNOTGate(): return ops.CNOT
def CZGate(): return ops.CZ
def CCXGate(): return ops.Toffoli

class UGate(ops.BasicGate):
    def __init__(self, theta, phi, lambd):
        ops.BasicGate.__init__(self)
        self.theta = theta
        self.phi = phi
        self.lambd = lambd

    def __str__(self):
        return str(self.__class__.__name__) + "(" + str(self.theta) + "," \
               + str(self.phi) + "," + str(self.lambd) + ")"

    def tex_str(self):
        return str(self.__class__.__name__) + "$(" + str(self.theta) + "," \
               + str(self.phi) + "," + str(self.lambd) + ")$"

    def get_inverse(self):
        tmp = 2 * pi
        return self.__class__(-self.theta + tmp, -self.lambd + tmp, -self.phi + tmp)

    def __eq__(self, other):
        if isinstance(other, self.__class__):
            return self.theta == other.theta \
                   & self.phi == other.phi \
                   & self.lambd == other.lambd
        else:
            return False

    def __ne__(self, other):
        return not self.__eq__(other)

    def __hash__(self):
        return hash(str(self))

    @property
    def matrix(self):
        return np.matrix([[exp(-1j*(self.phi+self.lambd)/2)*cos(self.theta/2),
                           -exp(-1j*(self.phi-self.lambd)/2)*sin(self.theta/2)],
                          [exp(1j*(self.phi-self.lambd)/2)*sin(self.theta/2),
                           exp(1j*(self.phi+self.lambd)/2)*cos(self.theta/2)]])

class ResetGate(ops.FastForwardingGate):
    def __str__(self):
        return "Reset"

    def __or__(self, qubit):
        ops.Measure | qubit
        if int(qubit):
            ops.X | qubit
Reset = ResetGate()

class u3(ops.BasicGate):
    def __init__(self, theta, phi, lambd):
        ops.BasicGate.__init__(self)
        self.theta = theta
        self.phi = phi
        self.lambd = lambd

    def __str__(self):
        return str(self.__class__.__name__) + "(" + str(self.theta) + "," + str(self.phi) + "," + str(self.lambd) + ")"

    def __eq__(self, other):
        if isinstance(other, self.__class__):
            return True\
                   & self.theta == other.theta\
                   & self.phi == other.phi\
                   & self.lambd == other.lambd
        else:
            return False

    def __ne__(self, other):
        return not self.__eq__(other)

    def __hash__(self):
        return hash(str(self))

    def __or__(self, qubits):
        if len(qubits) != 1:
            raise TypeError("Expected 1 qubits, given " + len(qubits))
        q = qubits[0]

        UGate(theta, phi, lambd) | q

class u2(ops.BasicGate):
    def __init__(self, phi, lambd):
        ops.BasicGate.__init__(self)
        self.phi = phi
        self.lambd = lambd

    def __str__(self):
        return str(self.__class__.__name__) + "(" + str(self.phi) + "," + str(self.lambd) + ")"

    def __eq__(self, other):
        if isinstance(other, self.__class__):
            return True\
                   & self.phi == other.phi\
                   & self.lambd == other.lambd
        else:
            return False

    def __ne__(self, other):
        return not self.__eq__(other)

    def __hash__(self):
        return hash(str(self))

    def __or__(self, qubits):
        if len(qubits) != 1:
            raise TypeError("Expected 1 qubits, given " + len(qubits))
        q = qubits[0]

        UGate(pi/2, phi, lambd) | q

class u0(ops.BasicGate):
    def __init__(self, gamma):
        ops.BasicGate.__init__(self)
        self.gamma = gamma

    def __str__(self):
        return str(self.__class__.__name__) + "(" + str(self.gamma) + ")"

    def __eq__(self, other):
        if isinstance(other, self.__class__):
            return True\
                   & self.gamma == other.gamma
        else:
            return False

    def __ne__(self, other):
        return not self.__eq__(other)

    def __hash__(self):
        return hash(str(self))

    def __or__(self, qubits):
        if len(qubits) != 1:
            raise TypeError("Expected 1 qubits, given " + len(qubits))
        q = qubits[0]

        UGate(0, 0, 0) | q

class cy(ops.BasicGate):
    def __init__(self, ):
        ops.BasicGate.__init__(self)

    def __str__(self):
        return str(self.__class__.__name__) + "(" +  + ")"

    def __eq__(self, other):
        if isinstance(other, self.__class__):
            return True
        else:
            return False

    def __ne__(self, other):
        return not self.__eq__(other)

    def __hash__(self):
        return hash(str(self))

    def __or__(self, qubits):
        if len(qubits) != 2:
            raise TypeError("Expected 2 qubits, given " + len(qubits))
        a = qubits[0]
        b = qubits[1]

        SdagGate() | (b)
        CNOTGate() | (a, b)
        ops.SGate() | (b)

class swap(ops.BasicGate):
    def __init__(self, ):
        ops.BasicGate.__init__(self)

    def __str__(self):
        return str(self.__class__.__name__) + "(" +  + ")"

    def __eq__(self, other):
        if isinstance(other, self.__class__):
            return True
        else:
            return False

    def __ne__(self, other):
        return not self.__eq__(other)

    def __hash__(self):
        return hash(str(self))

    def __or__(self, qubits):
        if len(qubits) != 2:
            raise TypeError("Expected 2 qubits, given " + len(qubits))
        a = qubits[0]
        b = qubits[1]

        CNOTGate() | (a, b)
        CNOTGate() | (b, a)
        CNOTGate() | (a, b)

class ch(ops.BasicGate):
    def __init__(self, ):
        ops.BasicGate.__init__(self)

    def __str__(self):
        return str(self.__class__.__name__) + "(" +  + ")"

    def __eq__(self, other):
        if isinstance(other, self.__class__):
            return True
        else:
            return False

    def __ne__(self, other):
        return not self.__eq__(other)

    def __hash__(self):
        return hash(str(self))

    def __or__(self, qubits):
        if len(qubits) != 2:
            raise TypeError("Expected 2 qubits, given " + len(qubits))
        a = qubits[0]
        b = qubits[1]

        ops.HGate() | (b)
        SdagGate() | (b)
        CNOTGate() | (a, b)
        ops.HGate() | (b)
        ops.TGate() | (b)
        CNOTGate() | (a, b)
        ops.TGate() | (b)
        ops.HGate() | (b)
        ops.SGate() | (b)
        ops.XGate() | (b)
        ops.SGate() | (a)

class cu3(ops.BasicGate):
    def __init__(self, theta, phi, lambd):
        ops.BasicGate.__init__(self)
        self.theta = theta
        self.phi = phi
        self.lambd = lambd

    def __str__(self):
        return str(self.__class__.__name__) + "(" + str(self.theta) + "," + str(self.phi) + "," + str(self.lambd) + ")"

    def __eq__(self, other):
        if isinstance(other, self.__class__):
            return True\
                   & self.theta == other.theta\
                   & self.phi == other.phi\
                   & self.lambd == other.lambd
        else:
            return False

    def __ne__(self, other):
        return not self.__eq__(other)

    def __hash__(self):
        return hash(str(self))

    def __or__(self, qubits):
        if len(qubits) != 2:
            raise TypeError("Expected 2 qubits, given " + len(qubits))
        c = qubits[0]
        t = qubits[1]

        ops.Rz((lambd-phi)/2) | (t)
        CNOTGate() | (c, t)
        u3(-theta/2, 0, -(phi+lambd)/2) | (t)
        CNOTGate() | (c, t)
        u3(theta/2, phi, 0) | (t)

if __name__ == "__main__":
    eng = MainEngine()

I think there are some self. missing (at least PyCharm is complaining), such as

def __or__(self, qubits):
        if len(qubits) != 1:
            raise TypeError("Expected 1 qubits, given " + len(qubits))
        q = qubits[0]

        UGate(theta, phi, lambd) | q 

In the last line we should have UGate(self.theta, self.phi, self.lambd) | q. And everywhere else we're calling the UGate/u3/u2/etc from within class methods.

@meamy can you please double-check when you get a chance? I think the same happens with the other python-like APIs (such as e.g. Circ)

meamy commented 3 years ago

Fixed!