def forward(self): # 生成初始的编码器 E 和解码器 D\n", E = Encoder(self.theta) E_dagger = dagger(E) D = E_dagger D_dagger = E # 编码量子态 rho_in rho_BA = matmul(matmul(E, self.rho_in), E_dagger) # 取 partial_trace() 获得 rho_encode 与 rho_trash rho_encode = partial_trace(rho_BA, 2**N_B, 2**N_A, 1) rho_trash = partial_trace(rho_BA, 2**N_B, 2**N_A, 2) # 解码得到量子态 rho_out rho_CA = kron(self.rho_C, rho_encode) rho_out = matmul(matmul(D, rho_CA), D_dagger) # 通过 rho_trash 计算损失函数 zero_Hamiltonian = fluid.dygraph.to_variable( np.diag([1, 0]).astype('complex128')) loss = 1 - (trace(matmul(zero_Hamiltonian, rho_trash))).real return loss, self.rho_in, rho_out
def AE_decoder(theta, n, z_n, depth): assert n >= z_n n_empty = n - z_n empty_half = fluid.dygraph.to_variable(np.eye(2**n_empty).astype('complex128')) decoder_half = U_theta(theta, n, depth) result = kron(decoder_half, empty_half) return result
def __measure_parameterized(self, state, which_qubits, result_desired, theta): r"""进行参数化的测量。 Args: state (ComplexVariable): 输入的量子态 which_qubits (list): 测量作用的量子比特编号 result_desired (list): 期望得到的测量结果,如 ``"0"``、``"1"`` 或者 ``["0", "1"]`` theta (Variable): 测量运算的参数 Returns: ComplexVariable: 测量坍塌后的量子态 Variable:测量坍塌得到的概率 list: 测量得到的结果(0 或 1) """ n = self.get_qubit_number() assert len(which_qubits) == len(result_desired), \ "the length of qubits wanted to be measured and the result desired should be same" op_list = [fluid.dygraph.to_variable(np.eye(2, dtype=np.complex128)) ] * n for idx in range(0, len(which_qubits)): i = which_qubits[idx] ele = result_desired[idx] if int(ele) == 0: basis0 = fluid.dygraph.to_variable( np.array([[1, 0], [0, 0]], dtype=np.complex128)) basis1 = fluid.dygraph.to_variable( np.array([[0, 0], [0, 1]], dtype=np.complex128)) rho0 = elementwise_mul(basis0, cos(theta[idx])) rho1 = elementwise_mul(basis1, sin(theta[idx])) rho = elementwise_add(rho0, rho1) op_list[i] = rho elif int(ele) == 1: # rho = diag(concat([cos(theta[idx]), sin(theta[idx])])) # rho = ComplexVariable(rho, zeros((2, 2), dtype="float64")) basis0 = fluid.dygraph.to_variable( np.array([[1, 0], [0, 0]], dtype=np.complex128)) basis1 = fluid.dygraph.to_variable( np.array([[0, 0], [0, 1]], dtype=np.complex128)) rho0 = elementwise_mul(basis0, sin(theta[idx])) rho1 = elementwise_mul(basis1, cos(theta[idx])) rho = elementwise_add(rho0, rho1) op_list[i] = rho else: print("cannot recognize the results_desired.") # rho = ComplexVariable(ones((2, 2), dtype="float64"), zeros((2, 2), dtype="float64")) measure_operator = fluid.dygraph.to_variable(op_list[0]) if n > 1: for idx in range(1, len(op_list)): measure_operator = kron(measure_operator, op_list[idx]) state_measured = matmul(matmul(measure_operator, state), dagger(measure_operator)) prob = trace( matmul(matmul(dagger(measure_operator), measure_operator), state)).real state_measured = elementwise_div(state_measured, prob) return state_measured, prob, result_desired
def encoder(self, state_in): # 按照随机初始化的参数 theta Encoder = AE_encoder(self.theta1, n=self.n, z_n=self.n_z, depth=self.depth) # State in to input state initial_state = np.array([1]+[0]*(2**(self.n-self.n_z)-1)).astype('complex128') initial_state = fluid.dygraph.to_variable(initial_state) input_state = kron(initial_state, state_in) # 因为 Utheta是学习得到的,我们这里用行向量运算来提速而不会影响训练效果 state_z = matmul(input_state, Encoder) return state_z
def forward(self, state_in, label): """ Args: state_in: The input quantum state, shape [-1, 1, 2^n] label: label for the input state, shape [-1, 1] Returns: The loss: L = ((<Z> + 1)/2 + bias - label)^2 """ state_z = self.net.encoder(state_in) state_z = fluid.dygraph.to_variable(state_z.numpy()) # 我们需要将 Numpy array 转换成 Paddle 动态图模式中支持的 variable unused_n = self.n - self.n_z Ob = fluid.dygraph.to_variable(Observable(2*self.n-self.n_z, measure_index=unused_n)) label_pp = fluid.dygraph.to_variable(label) # 按照随机初始化的参数 theta unused_n = self.n - self.n_z Utheta = U_theta(self.theta, n=self.n_z, depth=self.depth) empty_half = fluid.dygraph.to_variable(np.eye(2**unused_n).astype('complex128')) Utheta = kron(empty_half, Utheta) Utheta = kron(Utheta, empty_half) # 因为 Utheta是学习得到的,我们这里用行向量运算来提速而不会影响训练效果 state_out = matmul(state_z, Utheta) # 维度 [-1, 1, 2 ** n] # 测量得到泡利 Z 算符的期望值 <Z> E_Z = matmul(matmul(state_out, Ob), transpose(ComplexVariable(state_out.real, -state_out.imag), perm=[0, 2, 1])) # 映射 <Z> 处理成标签的估计值 state_predict = E_Z.real[:, 0] * 0.5 + 0.5 + self.bias loss = fluid.layers.reduce_mean((state_predict - label_pp) ** 2) return loss, state_predict.numpy()
def set_init_status(self, state, which_qubits): r"""对 LoccNet 的初始 LOCC 态节点进行初始化。 Args: state (ComplexVariable): 输入的量子态的矩阵形式 which_qubits (tuple or list): 该量子态所对应的量子比特,其形式为 ``(party_id, qubit_id)`` 的 ``tuple`` ,或者由其组成的 ``list`` """ if isinstance(which_qubits, tuple): which_qubits = [which_qubits] temp_len = int(log2(sqrt(self.init_status.state.numpy().size))) self.init_status.state = kron(self.init_status.state, state) for idx, (party_id, qubit_id) in enumerate(which_qubits): if isinstance(party_id, str): self.parties_by_name[party_id][qubit_id] = (temp_len + idx) elif isinstance(party_id, int): self.parties_by_number[party_id][qubit_id] = (temp_len + idx) else: raise ValueError
def forward(self, state_in, origin_state): """ Args: state_in: The input quantum state, shape [-1, 1, 2^n] label: label for the input state, shape [-1, 1] Returns: The loss: L = ((<Z> + 1)/2 + bias - label)^2 """ # 我们需要将 Numpy array 转换成 Paddle 动态图模式中支持的 variable Ob = self.Ob # 按照随机初始化的参数 theta Encoder = AE_encoder(self.theta1, n=self.n, z_n=self.n_z, depth=self.depth) Decoder = AE_decoder(self.theta2, n=self.n, z_n=self.n_z, depth=self.depth) # State in to input state initial_state = np.array([1]+[0]*(2**(self.n-self.n_z)-1)).astype('complex128') initial_state = fluid.dygraph.to_variable(initial_state) input_state = kron(initial_state, state_in) # 因为 Utheta是学习得到的,我们这里用行向量运算来提速而不会影响训练效果 state_z = matmul(input_state, Encoder) state_out = matmul(state_z, Decoder) # 测量得到泡利 Z 算符的期望值 <Z> E_Z = [matmul(matmul(state_out, Ob[i]), transpose(ComplexVariable(state_out.real, -state_out.imag), perm=[0, 2, 1])).real for i in range(self.n)] output_state = fluid.layers.concat(E_Z, axis=-1) # Calcualate Loss loss = fluid.layers.mean((output_state-origin_state)**2) origin_len = fluid.layers.reduce_sum(origin_state**2, -1) ** 0.5 output_len = fluid.layers.reduce_sum(output_state**2, -1) ** 0.5 dot_product = fluid.layers.reduce_sum(output_state*origin_state, -1) fidelity = fluid.layers.mean(dot_product/origin_len/output_len) return loss, fidelity, output_state.numpy()
def forward(self, x): rho_in = fluid.dygraph.to_variable(x) E = Encoder(self.theta) E_dagger = dagger(E) D = E_dagger D_dagger = E rho_BA = matmul(matmul(E, rho_in), E_dagger) rho_encode = partial_trace(rho_BA, 2**N_B, 2**N_A, 1) rho_trash = partial_trace(rho_BA, 2**N_B, 2**N_A, 2) rho_CA = kron(self.rho_C, rho_encode) rho_out = matmul(matmul(D, rho_CA), D_dagger) zero_Hamiltonian = fluid.dygraph.to_variable( np.diag([1, 0]).astype('complex128')) loss = 1 - (trace(matmul(zero_Hamiltonian, rho_trash))).real return loss, rho_out, rho_encode
def reset_state(self, status, state, which_qubits): r"""用于重置你想要的量子比特上的部分量子态。 Args: status (LoccStatus or list): 输入的 LOCC 态节点,其类型应该为 ``LoccStatus`` 或者由其组成的 ``list`` state (ComplexVariable): 输入的量子态的矩阵形式 which_qubits (tuple or list): 指定需要被重置的量子比特编号,其形式为 ``(party_id, qubit_id)`` 的 ``tuple``,或者由其组成的 ``list`` Returns: LoccStatus or list: 重置部分量子比特的量子态后的 LOCC 态节点,其类型为 ``LoccStatus`` 或者由其组成的 ``list`` """ if isinstance(which_qubits, tuple): which_qubits = [which_qubits] qubits_list = list() for party_id, qubit_id in which_qubits: if isinstance(party_id, str): qubits_list.append(self.parties_by_name[party_id][qubit_id]) elif isinstance(party_id, int): qubits_list.append(self.parties_by_number[party_id][qubit_id]) else: raise ValueError m = len(qubits_list) if isinstance(status, LoccStatus): n = int(log2(sqrt(status.state.numpy().size))) elif isinstance(status, list): n = int(log2(sqrt(status[0].state.numpy().size))) else: raise ValueError("can't recognize the input status") assert max(qubits_list) <= n, "qubit index out of range" qubit2idx = list(range(0, n)) idx2qubit = list(range(0, n)) swap_history = list() cir0 = UAnsatz(n) for i, ele in enumerate(qubits_list): if qubit2idx[ ele] != i: # if qubit2idx[ele] is i, then swap([ele, i]) is identity swap_history.append((i, qubit2idx[ele])) cir0.swap([i, qubit2idx[ele]]) qubit2idx[idx2qubit[i]] = qubit2idx[ele] idx2qubit[qubit2idx[ele]] = idx2qubit[i] idx2qubit[i] = ele qubit2idx[ele] = i cir1 = UAnsatz(n) swap_cnt = len(swap_history) for idx in range(0, swap_cnt): a, b = swap_history[swap_cnt - 1 - idx] cir1.swap([b, a]) if isinstance(status, LoccStatus): _state = cir0.run_density_matrix(status.state) _state = partial_trace(_state, 2**m, 2**(n - m), 1) _state = kron(state, _state) _state = cir1.run_density_matrix(_state) new_status = LoccStatus(_state, status.prob, status.measured_result) elif isinstance(status, list): new_status = list() for each_status in status: _state = cir0.run_density_matrix(each_status.state) _state = partial_trace(_state, 2**m, 2**(n - m), 1) _state = kron(state, _state) _state = cir1.run_density_matrix(_state) new_status.append( LoccStatus(_state, each_status.prob, each_status.measured_result)) else: raise ValueError("can't recognize the input status") return new_status