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 forward(self, input_state, H, N, N_SYS_B, D): """ Args: input_state: The initial state with default |0..> H: The target Hamiltonian Returns: The loss. """ out_state = U_theta(self.theta, input_state, N, D) # rho_AB = utils.matmul(utils.matrix_conjugate_transpose(out_state), out_state) rho_AB = matmul( transpose( fluid.framework.ComplexVariable(out_state.real, -out_state.imag), perm=[1, 0]), out_state) # compute the partial trace and three losses rho_B = partial_trace(rho_AB, 2**(N - N_SYS_B), 2**(N_SYS_B), 1) rho_B_squre = matmul(rho_B, rho_B) loss1 = (trace(matmul(rho_B, H))).real loss2 = (trace(rho_B_squre)).real * 2 loss3 = -(trace(matmul(rho_B_squre, rho_B))).real / 2 loss = loss1 + loss2 + loss3 # 损失函数 # option: if you want to check whether the imaginary part is 0, uncomment the following # print('loss_iminary_part: ', loss.numpy()[1]) return loss - 3 / 2, rho_B
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 forward(self, H, N, N_SYS_B, beta, D): # Apply quantum neural network onto the initial state rho_AB = U_theta(self.initial_state, self.theta, N, D) # Calculate the partial tarce to get the state rho_B of subsystem B rho_B = partial_trace(rho_AB, 2**(N - N_SYS_B), 2**(N_SYS_B), 1) # Calculate the three components of the loss function rho_B_squre = matmul(rho_B, rho_B) loss1 = (trace(matmul(rho_B, H))).real loss2 = (trace(rho_B_squre)).real * 2 / beta loss3 = -((trace(matmul(rho_B_squre, rho_B))).real + 3) / (2 * beta) # Get the final loss function loss = loss1 + loss2 + loss3 return loss, rho_B
def forward(self, H, N, N_SYS_B, beta, D): # 施加量子神经网络 rho_AB = U_theta(self.initial_state, self.theta, N, D) # 计算偏迹 partial trace 来获得子系统B所处的量子态 rho_B rho_B = partial_trace(rho_AB, 2**(N - N_SYS_B), 2**(N_SYS_B), 1) # 计算三个子损失函数 rho_B_squre = matmul(rho_B, rho_B) loss1 = (trace(matmul(rho_B, H))).real loss2 = (trace(rho_B_squre)).real * 2 / beta loss3 = -((trace(matmul(rho_B_squre, rho_B))).real + 3) / (2 * beta) # 最终的损失函数 loss = loss1 + loss2 + loss3 return loss, rho_B
def reset_state(self, status, state, which_qubits): r"""用于重置你想要的量子比特上的部分量子态。 Args: status (LoccStatus or list): 输入的 LOCC 态节点,其类型应该为 ``LoccStatus`` 或者由其组成的 ``list`` state (Tensor): 输入的量子态的矩阵形式 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" origin_seq = list(range(0, n)) target_seq = [idx for idx in origin_seq if idx not in qubits_list] target_seq = qubits_list + target_seq swaped = [False] * n swap_list = [] for idx in range(0, n): if not swaped[idx]: next_idx = idx swaped[next_idx] = True while not swaped[target_seq[next_idx]]: swaped[target_seq[next_idx]] = True swap_list.append((next_idx, target_seq[next_idx])) next_idx = target_seq[next_idx] cir0 = UAnsatz(n) for a, b in swap_list: cir0.swap([a, b]) cir1 = UAnsatz(n) swap_list.reverse() for a, b in swap_list: cir1.swap([a, b]) 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
def partial_state(self, status, which_qubits, is_desired=True): r"""得到你想要的部分量子比特上的量子态。 Args: status (LoccStatus or list): 输入的 LOCC 态节点,其类型应该为 ``LoccStatus`` 或者由其组成的 ``list`` which_qubits (tuple or list): 指定的量子比特编号,其形式为 ``(party_id, qubit_id)`` 的 ``tuple`` ,或者由其组成的 ``list`` is_desired (bool, optional): 默认是 ``True`` ,即返回量子比特上的部分量子态。如果为 ``False`` ,则抛弃这部分量子比特上的量子态,返回剩下的部分量子态 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" origin_seq = list(range(0, n)) target_seq = [idx for idx in origin_seq if idx not in qubits_list] target_seq = qubits_list + target_seq swaped = [False] * n swap_list = [] for idx in range(0, n): if not swaped[idx]: next_idx = idx swaped[next_idx] = True while not swaped[target_seq[next_idx]]: swaped[target_seq[next_idx]] = True swap_list.append((next_idx, target_seq[next_idx])) next_idx = target_seq[next_idx] cir = UAnsatz(n) for a, b in swap_list: cir.swap([a, b]) if isinstance(status, LoccStatus): state = cir.run_density_matrix(status.state) if is_desired: state = partial_trace(state, 2**m, 2**(n - m), 2) else: state = partial_trace(state, 2**m, 2**(n - m), 1) new_status = LoccStatus(state, status.prob, status.measured_result) elif isinstance(status, list): new_status = list() for each_status in status: state = cir.run_density_matrix(each_status.state) if is_desired: state = partial_trace(state, 2**m, 2**(n - m), 2) else: state = partial_trace(state, 2**m, 2**(n - m), 1) new_status.append( LoccStatus(state, each_status.prob, each_status.measured_result)) else: raise ValueError("can't recognize the input status") return new_status
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
def partial_state(self, status, which_qubits, is_desired=True): r"""得到你想要的部分量子比特上的量子态。 Args: status (LoccStatus or list): 输入的 LOCC 态节点,其类型应该为 ``LoccStatus`` 或者由其组成的 ``list`` which_qubits (tuple or list): 指定的量子比特编号,其形式为 ``(party_id, qubit_id)`` 的 ``tuple`` ,或者由其组成的 ``list`` is_desired (bool, optional): 默认是 ``True`` ,即返回量子比特上的部分量子态。如果为 ``False`` ,则抛弃这部分量子比特上的量子态,返回剩下的部分量子态 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)) cir = UAnsatz(n) for i, ele in enumerate(qubits_list): if qubit2idx[ele] != i: # if qubit2idx[ele] is i, then swap([ele, i]) is identity cir.swap([i, qubit2idx[ele]]) qubit2idx[idx2qubit[i]] = qubit2idx[ele] idx2qubit[qubit2idx[ele]] = idx2qubit[i] idx2qubit[i] = ele qubit2idx[ele] = i if isinstance(status, LoccStatus): state = cir.run_density_matrix(status.state) if is_desired: state = partial_trace(state, 2**m, 2**(n - m), 2) else: state = partial_trace(state, 2**m, 2**(n - m), 1) new_status = LoccStatus(state, status.prob, status.measured_result) elif isinstance(status, list): new_status = list() for each_status in status: state = cir.run_density_matrix(each_status.state) if is_desired: state = partial_trace(state, 2**m, 2**(n - m), 2) else: state = partial_trace(state, 2**m, 2**(n - m), 1) new_status.append( LoccStatus(state, each_status.prob, each_status.measured_result)) else: raise ValueError("can't recognize the input status") return new_status