QNLP  v1.0
__init__.py
Go to the documentation of this file.
1 name = "PyQNLPSimulator"
2 
3 #from mpi4py import rc
4 #rc.initialize = False # if = True, The Init is done when "from mpi4py import MPI" is called
5 #rc.thread_level = 'serialized'
6 
7 from mpi4py import MPI #Required to ensure initialisation of MPI environment
8 from ._PyQNLPSimulator import *
9 
10 from scipy.linalg import expm
11 import numpy as np
12 from itertools import product
13 from scipy.optimize import least_squares
14 
15 class GateOps:
16  """
17  This class is primarily for experimenting with gate operations during algorithm development.
18  This wraps the underlying gate types from the given simulator, and also gives a numpy version.
19 
20  THIS IS NOT TO BE USED FOR PERFORMANT/PRODUCTION CODE AND IS STRICTLY FOR DEV/TEST.
21  """
22  def __init__(self, simulator):
23  self.gates= {
24  "X" : simulator.getGateX(),
25  "Y" : simulator.getGateX(),
26  "Z" : simulator.getGateX(),
27  "H" : simulator.getGateX(),
28  "I" : simulator.getGateX(),
29  "Xnp" : simulator.getGateX(),
30  "Xnp" : simulator.getGateX(),
31  "Xnp" : simulator.getGateX(),
32  "Xnp" : simulator.getGateX(),
33  }
34  self.X = simulator.getGateX()
35  self.Y = simulator.getGateY()
36  self.Z = simulator.getGateZ()
37  self.H = simulator.getGateH()
38  self.I = simulator.getGateI()
39 
40  self.Xnp = np.matrix(self.X.as_numpy())
41  self.Ynp = np.matrix(self.Y.as_numpy())
42  self.Znp = np.matrix(self.Z.as_numpy())
43  self.Hnp = np.matrix(self.H.as_numpy())
44  self.Inp = np.matrix(self.I.as_numpy())
45 
46  def createU(self, vals : list):
47  return DCMatrix(vals)
48 
49  def RX(self, theta):
50  return np.matrix(expm(-0.5*1j*theta*self.Xnp))
51 
52  def RY(self, theta):
53  return np.matrix(expm(-0.5*1j*theta*self.Ynp))
54 
55  def RZ(self, theta):
56  return np.matrix(expm(-0.5*1j*theta*self.Znp))
57 
58  def RZPh(self, theta):
59  "RZ excluding global phase of exp(iTheta/2)"
60  #np.matrix(np.exp(0.5*1j*theta)*expm(-0.5*1j*theta*self.Znp)))
61  return np.matrix([[1.0,0.0], [0., np.exp(1j*theta)] ])
62 
63  def RU(self, theta, U):
64  res = None
65  if isinstance(U, list):
66  res = self.createU(U)
67  elif isinstance(U, DCMatrix):
68  res = U.as_numpy()
69  else:
70  raise TypeError("U is not an accepted type: should be list or DCMatrix")
71 
72  return np.matrix(expm(-0.5*1j*theta*res))
73 
75  def __init__(self, simulator, unitary):
76  from scipy.optimize import least_squares as lsq
77  self.ls = lsq
78  self.minFunc = None
79  self.unitary = unitary
80  self.unitarynp = None
81  self.gates = ["X", "Y", "Z", "H", "RX", "RY", "RZ", "RZPh"]
82  self.gate_ops = GateOps(simulator)
83 
84  def findOps(self, gate_order, cost_tol = 1e-3):
85  lambda x: np.array([2*x[0] + x[1] - 1])
86  num_params = 0
87  for i in gate_order:
88  if "R" in i[0]:
89  num_params += 1
90 
91  def setMinFunc(x, gates):
92  mm = self.gate_ops.createU(self.unitary).as_numpy()
93 
94  nn = 1
95  param_val = 0
96  for g in reversed(gates):
97  if "R" in g[0]:
98  nn *= getattr(self.gate_ops , g)(x[param_val])
99  param_val += 1
100  else:
101  nn *= getattr(self.gate_ops, "".join((g,"np")))
102  nn = nn.tolist()
103 
104  ml = [i for sublist in mm for i in sublist]
105  mr = [np.real(i) for i in ml]
106  mi = [np.imag(i) for i in ml]
107  m = [] + mr + mi
108  nl = [i for sublist in nn for i in sublist]
109  nr = [np.real(i) for i in nl]
110  ni = [np.imag(i) for i in nl]
111  n = [] + nr + ni
112 
113  ab = np.sum([i**2 for i in np.subtract(m,n)])
114 
115  return ab
116 
117  if num_params > 0:
118  res = least_squares(setMinFunc, [0]*num_params, args=(gate_order,), bounds=(-np.pi, np.pi))
119  if res.cost <= cost_tol:
120  return res.success, res.x
121  else:
122  return False, []
123 
124  else:
125  rr = setMinFunc([], gate_order)
126  return np.isclose(rr, 0, rtol=cost_tol), []
127 
128  def genOps(self, gates : list, depth=5):
129  """Generate the combinations of operations.
130  Same gate is never called twice in a row."""
131 
132  ops_list0 = list(product(gates, repeat=depth))
133  ops_list = list(product(gates, repeat=depth))
134  del_idx = set()
135  for idx_ops_list, ops in enumerate(ops_list):
136  for idx_ops in range(1,len(ops)):
137  if ops[idx_ops] == ops[idx_ops-1]:
138  #del ops_list[idx_ops_list]
139  del_idx.add(idx_ops_list)
140  ops_list = [val for idx,val in enumerate(ops_list) if idx not in del_idx]
141  return ops_list
def findOps(self, gate_order, cost_tol=1e-3)
Definition: __init__.py:84
def RZPh(self, theta)
Definition: __init__.py:58
def RY(self, theta)
Definition: __init__.py:52
def RU(self, theta, U)
Definition: __init__.py:63
def __init__(self, simulator)
Definition: __init__.py:22
def __init__(self, simulator, unitary)
Definition: __init__.py:75
def RZ(self, theta)
Definition: __init__.py:55
def RX(self, theta)
Definition: __init__.py:49
def genOps(self, list gates, depth=5)
Definition: __init__.py:128
def createU(self, list vals)
Definition: __init__.py:46