130 lines
4.3 KiB
Python
130 lines
4.3 KiB
Python
import numpy as np
|
|
from benchmarks.libraries import abstract
|
|
|
|
class ProjectQ(abstract.ParserBackend):
|
|
|
|
def __init__(self, max_qubits="0", local_optimizer="0"):
|
|
"""Initialize data members.
|
|
|
|
Args:
|
|
max_qubits (str): if "0", gate fusion is disabled, otherwise it's enabled.
|
|
Note that it's not possible to set the maximum fused gate size.
|
|
local_optimizer (str): if "0", local optimization of circuits is disabled,
|
|
otherwise it's enabled.
|
|
"""
|
|
import projectq
|
|
self.name = "projectq"
|
|
self.projectq = projectq
|
|
self.__version__ = None
|
|
self.gate_fusion = int(max_qubits) > 0
|
|
self.local_optimizer = bool(int(local_optimizer))
|
|
|
|
def RX(self, theta):
|
|
return self.projectq.ops.Rx(theta)
|
|
|
|
def RY(self, theta):
|
|
return self.projectq.ops.Ry(theta)
|
|
|
|
def RZ(self, theta):
|
|
return self.projectq.ops.Rz(theta)
|
|
|
|
def U1(self, theta):
|
|
return self.projectq.ops.R(theta)
|
|
|
|
def U2(self, phi, lam):
|
|
pplus, pminus = np.exp(0.5j * (phi + lam)), np.exp(0.5j * (phi - lam))
|
|
matrix = np.array([[np.conj(pplus), -np.conj(pminus)],
|
|
[pminus, pplus]])
|
|
matrix /= np.sqrt(2)
|
|
return self.projectq.ops.MatrixGate(matrix)
|
|
|
|
def U3(self, theta, phi, lam):
|
|
cost, sint = np.cos(theta / 2.0), np.sin(theta / 2.0)
|
|
pplus, pminus = np.exp(0.5j * (phi + lam)), np.exp(0.5j * (phi - lam))
|
|
matrix = np.array([[np.conj(pplus) * cost, -np.conj(pminus) * sint],
|
|
[pminus * sint, pplus * cost]])
|
|
return self.projectq.ops.MatrixGate(matrix)
|
|
|
|
|
|
def SWAP(self):
|
|
return self.projectq.ops.Swap
|
|
|
|
def CRX(self, theta):
|
|
return self.projectq.ops.C(self.RX(theta))
|
|
|
|
def CRY(self, theta):
|
|
return self.projectq.ops.C(self.RY(theta))
|
|
|
|
def CRZ(self, theta):
|
|
return self.projectq.ops.CRz(theta)
|
|
|
|
def CU1(self, theta):
|
|
U1 = self.projectq.ops.R(theta)
|
|
return self.projectq.ops.C(U1, n_qubits=1)
|
|
|
|
def CU3(self, theta):
|
|
raise NotImplementedError
|
|
|
|
def RZZ(self, theta):
|
|
return self.projectq.ops.Rzz(theta)
|
|
|
|
def __getattr__(self, x):
|
|
return getattr(self.projectq.ops, x)
|
|
|
|
def __item__(self, x):
|
|
return getattr(self.projectq.ops, x)
|
|
|
|
def from_qasm(self, qasm):
|
|
nqubits, gatelist = self.parse(qasm)
|
|
backend = self.projectq.backends.Simulator(gate_fusion=self.gate_fusion)
|
|
if self.local_optimizer:
|
|
self.eng = self.projectq.MainEngine(
|
|
backend=backend, engine_list=[self.projectq.cengines.LocalOptimizer()]
|
|
)
|
|
else:
|
|
self.eng = self.projectq.MainEngine(backend=backend)
|
|
qureg = self.eng.allocate_qureg(nqubits)
|
|
for gatename, qubits, params in gatelist:
|
|
gate = getattr(self, gatename)
|
|
if params is not None:
|
|
parameters = list(params)
|
|
if len(qubits) > 1:
|
|
gate(*parameters) | tuple(qureg[i] for i in qubits)
|
|
else:
|
|
gate(*parameters) | qureg[qubits[0]]
|
|
elif len(qubits) > 1:
|
|
if gatename == "SWAP":
|
|
gate() | tuple(qureg[i] for i in qubits)
|
|
else:
|
|
gate | tuple(qureg[i] for i in qubits)
|
|
else:
|
|
gate | qureg[qubits[0]]
|
|
|
|
return qureg
|
|
|
|
def __call__(self, qureg):
|
|
self.eng.flush()
|
|
self.qubit_id, wave = self.eng.backend.cheat()
|
|
# measure everything to avoid error when running
|
|
self.projectq.ops.All(self.projectq.ops.Measure) | qureg
|
|
return np.array(wave)
|
|
|
|
def transpose_state(self, x):
|
|
shape = tuple(x.shape)
|
|
nqubits = int(np.log2(shape[0]))
|
|
x = np.reshape(x, nqubits * (2,))
|
|
x = np.transpose(x, range(nqubits - 1, -1, -1))
|
|
x = np.transpose(x, tuple(self.qubit_id[key] for key in self.qubit_id))
|
|
x = np.reshape(x, shape)
|
|
return x
|
|
|
|
def set_precision(self, precision):
|
|
if precision != "double":
|
|
raise NotImplementedError(f"Cannot set {precision} precision for {self.name} backend.")
|
|
|
|
def get_precision(self):
|
|
return "double"
|
|
|
|
def get_device(self):
|
|
return None
|