class Discriminator: def __init__(self, herm, system_size): self.size = system_size self.herm = herm self.alpha = np.zeros((self.size, len(self.herm))) self.beta = np.zeros((self.size, len(self.herm))) self._init_params() self.optimizer_psi = MomentumOptimizer() self.optimizer_phi = MomentumOptimizer() def _init_params(self): # Discriminator Parameters for i in range(self.size): self.alpha[i] = -1 + 2 * np.random.random(len(self.herm)) self.beta[i] = -1 + 2 * np.random.random(len(self.herm)) def getPsi(self): ''' get matrix representation of real part of discriminator :param alpha: parameters of psi(ndarray):size = [num_qubit, 4] 0: I 1: X 2: Y 3: Z :return: ''' psi = 1 for i in range(self.size): psi_i = np.zeros_like(self.herm[0], dtype=complex) for j in range(len(self.herm)): psi_i += self.alpha[i][j] * self.herm[j] psi = np.kron(psi, psi_i) return psi def getPhi(self): ''' get matrix representation of fake part of discriminator :param beta: parameters of psi(ndarray):size = [num_qubit, 4] 0: I 1: X 2: Y 3: Z :return: ''' phi = 1 for i in range(self.size): phi_i = np.zeros_like(self.herm[0], dtype=complex) for j in range(len(self.herm)): phi_i += self.beta[i][j] * self.herm[j] phi = np.kron(phi, phi_i) return phi # Psi gradients def _grad_psi(self, type): grad_psi = list() for i in range(self.size): grad_psiI = 1 for j in range(self.size): if i == j: grad_psii = self.herm[type] else: grad_psii = np.zeros_like(self.herm[0], dtype=complex) for k in range(len(self.herm)): grad_psii += self.alpha[j][k] * self.herm[k] grad_psiI = np.kron(grad_psiI, grad_psii) grad_psi.append(grad_psiI) return grad_psi def _grad_alpha(self, gen, real_state): G = gen.getGen() psi = self.getPsi() phi = self.getPhi() fake_state = np.matmul(G, input_state) try: A = expm((-1 / lamb) * phi) except Exception: print('grad_alpha -1/lamb:\n', (-1 / lamb)) print('size of phi:\n', phi.shape) try: B = expm((1 / lamb) * psi) except Exception: print('grad_alpha 1/lamb:\n', (1 / lamb)) print('size of psi:\n', psi.shape) cs = 1 / lamb grad_psi_term = np.zeros_like(self.alpha, dtype=complex) grad_phi_term = np.zeros_like(self.alpha, dtype=complex) grad_reg_term = np.zeros_like(self.alpha, dtype=complex) for type in range(len(self.herm)): gradpsi = self._grad_psi(type) gradpsi_list = list() gradphi_list = list() gradreg_list = list() for grad_psi in gradpsi: gradpsi_list.append(np.asscalar(np.matmul(real_state.getH(), np.matmul(grad_psi, real_state)))) gradphi_list.append(0) term1 = cs * np.matmul(fake_state.getH(), np.matmul(A, fake_state)) * np.matmul(real_state.getH(),np.matmul(grad_psi,np.matmul(B,real_state))) term2 = cs * np.matmul(fake_state.getH(), np.matmul(grad_psi, np.matmul(B, real_state))) * np.matmul(real_state.getH(), np.matmul(A, fake_state)) term3 = cs * np.matmul(fake_state.getH(), np.matmul(A, real_state)) * np.matmul(real_state.getH(),np.matmul(grad_psi,np.matmul(B,fake_state))) term4 = cs * np.matmul(fake_state.getH(), np.matmul(grad_psi, np.matmul(B, fake_state))) * np.matmul(real_state.getH(), np.matmul(A, real_state)) gradreg_list.append(np.asscalar(lamb / np.e * (cst1 * term1 - cst2 * term2 - cst2 * term3 + cst3 * term4))) # calculate grad of psi term grad_psi_term[:, type] = np.asarray(gradpsi_list) # calculate grad of phi term grad_phi_term[:, type] = np.asarray(gradphi_list) # calculate grad of reg term grad_reg_term[:, type] = np.asarray(gradreg_list) grad = np.real(grad_psi_term - grad_phi_term - grad_reg_term) return grad # Phi gradients def _grad_phi(self, type): grad_phi = list() for i in range(self.size): grad_phiI = 1 for j in range(self.size): if i == j: grad_phii = self.herm[type] else: grad_phii = np.zeros_like(self.herm[0], dtype=complex) for k in range(len(self.herm)): grad_phii += self.beta[j][k] * self.herm[k] grad_phiI = np.kron(grad_phiI, grad_phii) grad_phi.append(grad_phiI) return grad_phi def _grad_beta(self, gen, real_state): G = gen.getGen() psi = self.getPsi() phi = self.getPhi() fake_state = np.matmul(G, input_state) try: A = expm((-1 / lamb) * phi) except Exception: print('grad_beta -1/lamb:\n', (-1 / lamb)) print('size of phi:\n', phi.shape) try: B = expm((1 / lamb) * psi) except Exception: print('grad_beta 1/lamb:\n', (1 / lamb)) print('size of psi:\n', psi.shape) cs = -1 / lamb grad_psi_term = np.zeros_like(self.beta, dtype=complex) grad_phi_term = np.zeros_like(self.beta, dtype=complex) grad_reg_term = np.zeros_like(self.beta, dtype=complex) for type in range(len(self.herm)): gradphi = self._grad_phi(type) gradpsi_list = list() gradphi_list = list() gradreg_list = list() for grad_phi in gradphi: gradpsi_list.append(0) gradphi_list.append(np.asscalar(np.matmul(fake_state.getH(), np.matmul(grad_phi, fake_state)))) term1 = cs * np.matmul(fake_state.getH(), np.matmul(grad_phi, np.matmul(A, fake_state))) * np.matmul(real_state.getH(), np.matmul(B, real_state)) term2 = cs * np.matmul(fake_state.getH(), np.matmul(B, real_state)) * np.matmul(real_state.getH(),np.matmul(grad_phi,np.matmul(A,fake_state))) term3 = cs * np.matmul(fake_state.getH(), np.matmul(grad_phi, np.matmul(A, real_state))) * np.matmul(real_state.getH(), np.matmul(B, fake_state)) term4 = cs * np.matmul(fake_state.getH(), np.matmul(B, fake_state)) * np.matmul(real_state.getH(),np.matmul(grad_phi,np.matmul(A,real_state))) gradreg_list.append(np.asscalar(lamb / np.e * (cst1 * term1 - cst2 * term2 - cst2 * term3 + cst3 * term4))) # calculate grad of psi term grad_psi_term[:, type] = np.asarray(gradpsi_list) # calculate grad of phi term grad_phi_term[:, type] = np.asarray(gradphi_list) # calculate grad of reg term grad_reg_term[:, type] = np.asarray(gradreg_list) grad = np.real(grad_psi_term - grad_phi_term - grad_reg_term) return grad def update_dis(self, gen, real_state): grad_alpha = self._grad_alpha(gen, real_state) # update alpha new_alpha = self.optimizer_psi.compute_grad(self.alpha, grad_alpha, 'max') # new_alpha = self.alpha + eta * self._grad_alpha(gen) grad_beta = self._grad_beta(gen, real_state) # update beta new_beta = self.optimizer_phi.compute_grad(self.beta, grad_beta, 'max') # new_beta = self.beta + eta * self._grad_beta(gen) self.alpha = new_alpha self.beta = new_beta
class Generator: def __init__(self, system_size): self.size = system_size self.qc = self.init_qcircuit() self.optimizer = MomentumOptimizer() def set_qcircuit(self, qc): self.qc = qc def init_qcircuit(self): qcircuit = Quantum_Circuit(self.size, "generator") return qcircuit def getGen(self): return np.kron(self.qc.get_mat_rep(), Identity(self.size)) def _grad_theta(self, dis, real_state): G = self.getGen() phi = dis.getPhi() psi = dis.getPsi() fake_state = np.matmul(G, input_state) try: A = expm((-1 / lamb) * phi) except Exception: print('grad_gen -1/lamb:\n', (-1 / lamb)) print('size of phi:\n', phi.shape) try: B = expm((1 / lamb) * psi) except Exception: print('grad_gen 1/lamb:\n', (1 / lamb)) print('size of psi:\n', psi.shape) grad_g_psi = list() grad_g_phi = list() grad_g_reg = list() for i in range(self.qc.depth): grad_i = np.kron(self.qc.get_grad_mat_rep(i), Identity(system_size)) # for psi term grad_g_psi.append(0) # for phi term fake_grad = np.matmul(grad_i, input_state) tmp_grad = np.matmul(fake_grad.getH(), np.matmul(phi, fake_state)) + np.matmul(fake_state.getH(),np.matmul(phi, fake_grad)) grad_g_phi.append(np.asscalar(tmp_grad)) # for reg term term1 = np.matmul(fake_grad.getH(), np.matmul(A, fake_state)) * np.matmul(real_state.getH(),np.matmul(B, real_state)) term2 = np.matmul(fake_state.getH(), np.matmul(A, fake_grad)) * np.matmul(real_state.getH(),np.matmul(B, real_state)) term3 = np.matmul(fake_grad.getH(), np.matmul(B, real_state)) * np.matmul(real_state.getH(),np.matmul(A, fake_state)) term4 = np.matmul(fake_state.getH(), np.matmul(B, real_state)) * np.matmul(real_state.getH(),np.matmul(A, fake_grad)) term5 = np.matmul(fake_grad.getH(), np.matmul(A, real_state)) * np.matmul(real_state.getH(),np.matmul(B, fake_state)) term6 = np.matmul(fake_state.getH(), np.matmul(A, real_state)) * np.matmul(real_state.getH(),np.matmul(B, fake_grad)) term7 = np.matmul(fake_grad.getH(), np.matmul(B, fake_state)) * np.matmul(real_state.getH(),np.matmul(A, real_state)) term8 = np.matmul(fake_state.getH(), np.matmul(B, fake_grad)) * np.matmul(real_state.getH(),np.matmul(A, real_state)) tmp_reg_grad = lamb / np.e * ( cst1 * (term1 + term2) - cst2 * (term3 + term4) - cst2 * (term5 + term6) + cst3 * (term7 + term8)) grad_g_reg.append(np.asscalar(tmp_reg_grad)) g_psi = np.asarray(grad_g_psi) g_phi = np.asarray(grad_g_phi) g_reg = np.asarray(grad_g_reg) grad = np.real(g_psi - g_phi - g_reg) return grad def update_gen(self, dis, real_state): theta = [] for gate in self.qc.gates: theta.append(gate.angle) grad = np.asarray(self._grad_theta(dis, real_state)) theta = np.asarray(theta) new_angle = self.optimizer.compute_grad(theta,grad,'min') for i in range(self.qc.depth): self.qc.gates[i].angle = new_angle[i]
class Generator: def __init__(self, system_size): self.size = system_size self.qc = self.init_qcircuit() self.optimizer = MomentumOptimizer() def single_layer(self, qc): for i in range(self.size): # qc.add_gate(Quantum_Gate("X", i, angle=0.5000 * np.pi)) # qc.add_gate(Quantum_Gate("Y", i, angle=0.5000 * np.pi)) qc.add_gate(Quantum_Gate("Z", i, angle=0.5000 * np.pi)) return qc def entanglement_layer(self, qc): for i in range(self.size): for j in range(i + 1, self.size): # print(i,j) qc.add_gate(Quantum_Gate("XX", i, j, angle=0.5000 * np.pi)) qc.add_gate(Quantum_Gate("YY", i, j, angle=0.5000 * np.pi)) qc.add_gate(Quantum_Gate("ZZ", i, j, angle=0.5000 * np.pi)) print(i, j) return qc def entangle_adjacent_layer(self, qc, type): for i in range(self.size - 1): qc.add_gate(Quantum_Gate(type, i, i + 1, angle=0.5000 * np.pi)) qc.add_gate(Quantum_Gate(type, 0, self.size - 1, angle=0.5000 * np.pi)) return qc def set_qcircuit(self, qc): # qc_tmp = qc # for i in range(4): # qc_tmp = self.single_layer(qc_tmp) # qc_tmp = self.entanglement_layer(qc_tmp) # qc = qc_tmp # for j in range(layer): # for i in range(self.size): # qc.add_gate(Quantum_Gate("Z", i, angle=0.5000 * np.pi)) # if i < self.size: # qc = self.entangle_adjacent_layer(qc, "XX") # qc = self.entangle_adjacent_layer(qc, "YY") # qc = self.entangle_adjacent_layer(qc, "ZZ") # qc.add_gate(Quantum_Gate("G",None,angle=0.5000 * np.pi)) entg_list = ["XX", "YY", "ZZ"] for j in range(layer): for i in range(self.size): if i < self.size - 1: for gate in entg_list: qc.add_gate( Quantum_Gate(gate, i, i + 1, angle=0.5000 * np.pi)) qc.add_gate(Quantum_Gate("Z", i, angle=0.5000 * np.pi)) for gate in entg_list: qc.add_gate( Quantum_Gate(gate, 0, self.size - 1, angle=0.5000 * np.pi)) qc.add_gate(Quantum_Gate("Z", i, angle=0.5000 * np.pi)) qc.add_gate(Quantum_Gate("G", None, angle=0.5000 * np.pi)) # for gate in entg_list: # for i in range(self.size): # if i < self.size - 1: # qc.add_gate(Quantum_Gate(gate, i, i + 1, angle=0.5000 * np.pi)) # else: # qc.add_gate(Quantum_Gate(gate, 0, self.size - 1, angle=0.5000 * np.pi)) # qc.add_gate(Quantum_Gate("Z", i, angle=0.5000 * np.pi)) theta = np.random.randn(len(qc.gates)) for i in range(len(qc.gates)): qc.gates[i].angle = theta[i] print(i + 1, qc.gates[i].name, qc.gates[i].qubit1, qc.gates[i].qubit2) return qc def init_qcircuit(self): qcircuit = Quantum_Circuit(self.size, "generator") self.set_qcircuit(qcircuit) return qcircuit def getGen(self): return np.kron(self.qc.get_mat_rep(), Identity(system_size)) def _grad_gen(self, dis): G = self.getGen() phi = dis.getPhi() psi = dis.getPsi() fake_state = np.matmul(G, zero_state) try: A = expm((-1 / lamb) * phi) except Exception: print('grad_gen -1/lamb:\n', (-1 / lamb)) print('size of phi:\n', phi.shape) try: B = expm((1 / lamb) * psi) except Exception: print('grad_gen 1/lamb:\n', (1 / lamb)) print('size of psi:\n', psi.shape) # print("g: \n", G) # print("phi: \n", phi) # print("psi: \n", psi) # phi_tmp = np.asmatrix(phi) # print('phi:\n',phi_tmp.getH()@phi_tmp) # # psi_tmp = np.asmatrix(psi) # print('psi:\n',psi_tmp.getH()@psi_tmp) # print("expHerm:",expHerm) grad_g_psi = list() grad_g_phi = list() grad_g_reg = list() for i in range(self.qc.depth): grad_i = np.kron(self.qc.get_grad_mat_rep(i), Identity(system_size)) # for psi term grad_g_psi.append(0) # for phi term fake_grad = np.matmul(grad_i, zero_state) tmp_grad = np.matmul(fake_grad.getH(), np.matmul( phi, fake_state)) + np.matmul(fake_state.getH(), np.matmul(phi, fake_grad)) grad_g_phi.append(np.asscalar(tmp_grad)) # for reg term term1 = np.matmul(fake_grad.getH(), np.matmul( A, fake_state)) * np.matmul(real_state.getH(), np.matmul(B, real_state)) term2 = np.matmul(fake_state.getH(), np.matmul( A, fake_grad)) * np.matmul(real_state.getH(), np.matmul(B, real_state)) term3 = np.matmul(fake_grad.getH(), np.matmul( B, real_state)) * np.matmul(real_state.getH(), np.matmul(A, fake_state)) term4 = np.matmul(fake_state.getH(), np.matmul( B, real_state)) * np.matmul(real_state.getH(), np.matmul(A, fake_grad)) term5 = np.matmul(fake_grad.getH(), np.matmul( A, real_state)) * np.matmul(real_state.getH(), np.matmul(B, fake_state)) term6 = np.matmul(fake_state.getH(), np.matmul( A, real_state)) * np.matmul(real_state.getH(), np.matmul(B, fake_grad)) term7 = np.matmul(fake_grad.getH(), np.matmul( B, fake_state)) * np.matmul(real_state.getH(), np.matmul(A, real_state)) term8 = np.matmul(fake_state.getH(), np.matmul( B, fake_grad)) * np.matmul(real_state.getH(), np.matmul(A, real_state)) tmp_reg_grad = lamb / np.e * (cst1 * (term1 + term2) - cst2 * (term3 + term4) - cst2 * (term5 + term6) + cst3 * (term7 + term8)) grad_g_reg.append(np.asscalar(tmp_reg_grad)) g_psi = np.asarray(grad_g_psi) g_phi = np.asarray(grad_g_phi) g_reg = np.asarray(grad_g_reg) grad = np.real(g_psi - g_phi - g_reg) # print("grad:\n",grad) # del grad_g,grad_g_phi,grad_g_psi,grad_g_reg,G,phi,psi,A,B,fake_grad,tmp_grad,g_phi,g_psi,g_reg,grad_i # gc.collect() return grad def update_gen(self, dis): theta = [] for gate in self.qc.gates: theta.append(gate.angle) grad = np.asarray(self._grad_gen(dis)) theta = np.asarray(theta) new_angle = self.optimizer.compute_grad(theta, grad, 'min') for i in range(self.qc.depth): self.qc.gates[i].angle = new_angle[i] print('gen_theta max:{} gen_theta min:{}'.format( np.max(grad), np.min(grad)))