0
$\begingroup$

I am trying to implement a parameterised circuit in qiskit. Part of the circuit includes the operation

$(X \otimes X)^\alpha$

where $X$ is the standard Pauli-X gate, $\otimes$ is the tensor product, and $\alpha$ is any real number. Someone was so kind to help me implement this operation in another question: Raise tensor product to float power in qiskit and when I run it the way it was suggested, it works fine. However, when I paste it into a class, I get an error. This is my implementation:

class QuantumCircuit:
    
    def __init__(self, backend, shots=100):
        
        self._q = qiskit.QuantumRegister(3, 'q')
        self._c = qiskit.ClassicalRegister(1, 'c')
        self._circuit = qiskit.QuantumCircuit(self._q, self._c)
        
        self.inp = qiskit.circuit.ParameterVector('inp', 2)  
        self.param = qiskit.circuit.ParameterVector('param', 2)  
        
        #encoding
        self.phase_gate = Ph(self.inp[0], [0])
        self._circuit.append(self.phase_gate, [0])
        self._circuit.rx(self.inp[0], 0)
        
        self.phase_gate = Ph(self.inp[1], [0])
        self._circuit.append(self.phase_gate, [1])
        self._circuit.rx(self.inp[1], 1)

        for param in self.param:
            xx10 = PauliGate('XX').power(self.param[0])
            xx11 = PauliGate('XX').power(self.param[1])
            self._circuit.append(xx10, [0, 2])
            self._circuit.append(xx11, [1, 2])
            
            yy10 = PauliGate('YY').power(self.param[2])
            yy11 = PauliGate('YY').power(self.param[3])
            self._circuit.append(yy10, [0, 2])
            self._circuit.append(yy11, [1, 2])
            
            zz10 = PauliGate('ZZ').power(self.param[4])
            zz11 = PauliGate('ZZ').power(self.param[5])
            self._circuit.append(zz10, [0, 2])
            self._circuit.append(zz11, [1, 2])
            
        self._circuit.measure(2, 0)
        
        self.backend = backend
        self.shots = shots
        
    def run(self, inp, theta):
        qc = transpile(self._circuit, self.backend)
        
        #parameter assignment
        bind_dict = {}
        j = 0
        k = 0
        for key in qc.parameters:
            if j <= 1: #this is the number of inputs, at the moment we have two inputs
                bind_dict[key] = inp[j]
                j+=1
            else:                
                bind_dict[key] = theta[k]
                k+=1

        qc.assign_parameters(bind_dict, inplace=True)
        
        #run the circuit
        job = execute(qc, self.backend, shots=self.shots)
        result = job.result()
        c = result.get_counts()
        
        states = np.array(list(c.keys())).astype(float)
        counts = np.array(list(c.values())).astype(int)
        
        dist = counts/self.shots
        E = np.array([np.sum(states * dist)])
        
        return E

The error that I get is

Traceback (most recent call last):
  Input In [48] in <cell line: 2>
    circ = QuantumCircuit(backend, shots=10)
  Input In [47] in __init__
    xx10 = PauliGate('XX').power(self.param[0])
  File /opt/conda/lib/python3.8/site-packages/qiskit/circuit/gate.py:85 in power
    decomposition_power.append(pow(element, exponent))
TypeError: unsupported operand type(s) for ** or pow(): 'complex' and 'ParameterVectorElement'

Use %tb to get the full traceback.

For information, the lists of parameters that I used are

inp = array([0.50002703, 0.56683592])
theta = array([2.37624305, 5.00052773, 1.60817906, 1.01813369, 1.36693303,
       2.58211921])

Any ideas how to circumvent this problem?

$\endgroup$
1
  • $\begingroup$ It looks like the exponent of the PauliGate.power() has to be a value (float) and cannot be a ParameterExpression like when using a rx gate (qc.rx(param[0], [0])) Patrick $\endgroup$ May 30, 2022 at 14:41

2 Answers 2

2
$\begingroup$

You can't use Gate.power() because it does not accept qiskit.circuit.Parameter. You can, however, implement $(X \otimes X)^\alpha$ using the parameterized gate $R_{xx}(\theta)$

$$R_{xx}(\theta)=\exp(-i\frac{\theta}{2}X \otimes X)$$

We have, $R_{xx}(\pi)=iX \otimes X$.

So, $(X \otimes X)^\alpha$ is equivalent to $R_{xx}(\pi\alpha)$ up to a global phase.

Hence, instead of:

xx10 = PauliGate('XX').power(self.param[0])
self._circuit.append(xx10, [0, 2])

which causes the error, you can write:

self._circuit.rxx(np.pi * self.param[0], 0, 2)

Or, if you don't want to have a global phase difference:

self._circuit.rxx(np.pi * self.param[0], 0, 2)
self._circuit.x(0)
self._circuit.u(np.pi, np.pi * self.param[0] / 2, np.pi + np.pi * self.param[0] / 2, 0)

Similarly, you can use $R_{yy}$ and $R_{zz}$ to implement $(Y \otimes Y)^\alpha$ and $(Z \otimes Z)^\alpha$ respectively using the fact that,

$R_{yy}(\pi)=iY \otimes Y$, and $R_{zz}(\pi)=-Z \otimes Z$

$\endgroup$
1
$\begingroup$

Looks like Qiskit allows raising gates to real powers, but complains when using ParameterVector elements as exponents. Why don't you use the fact that $X = HZH$, so computing $X^{\alpha}$ is same as $HZ^{\alpha}H$. Finding $Z^{\alpha}$ is trivial because the exponent is applied to the diagonal elements of $Z^{\alpha} = \begin{pmatrix} 1& 0\\ 0 & (-1)^{\alpha} \end{pmatrix} = \begin{pmatrix} 1& 0\\ 0 & e^{i\pi\alpha} \end{pmatrix}$, which is a PhaseGate. So you can reduce $X^{\alpha}$ to $HP(\alpha\pi)H$.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.