def partial_trace(rho_AB, dim1, dim2, A_or_B): r"""计算量子态的偏迹。 Args: rho_AB (Tensor): 输入的量子态 dim1 (int): 系统A的维数 dim2 (int): 系统B的维数 A_or_B (int): 1或者2,1表示计算系统A上的偏迹,2表示计算系统B上的偏迹 Returns: Tensor: 输入的量子态的偏迹 """ if A_or_B == 2: dim1, dim2 = dim2, dim1 idty_np = np.identity(dim2).astype("complex128") idty_B = to_tensor(idty_np) zero_np = np.zeros([dim2, dim2], "complex128") res = to_tensor(zero_np) for dim_j in range(dim1): row_top = zeros([1, dim_j], dtype="float64") row_mid = ones([1, 1], dtype="float64") row_bot = zeros([1, dim1 - dim_j - 1], dtype="float64") bra_j = concat([row_top, row_mid, row_bot], axis=1) bra_j = paddle.cast(bra_j, 'complex128') if A_or_B == 1: row_tmp = kron(bra_j, idty_B) row_tmp_conj = paddle.conj(row_tmp) res = add( res, matmul( matmul(row_tmp, rho_AB), transpose(row_tmp_conj, perm=[1, 0]), ), ) if A_or_B == 2: row_tmp = kron(idty_B, bra_j) row_tmp_conj = paddle.conj(row_tmp) res = add( res, matmul( matmul(row_tmp, rho_AB), transpose(row_tmp_conj, perm=[1, 0]), ), ) return res
def test_case_with_output(self): a = np.random.randn(10, 10).astype(np.float64) b = np.random.randn(10, 10).astype(np.float64) main = fluid.Program() start = fluid.Program() with fluid.unique_name.guard(): with fluid.program_guard(main, start): a_var = fluid.data("a", [-1, -1], dtype="float64") b_var = fluid.data("b", [-1, -1], dtype="float64") out_var = fluid.layers.create_tensor("float64", "c") paddle.kron(a_var, b_var, out=out_var) place = fluid.CPUPlace() exe = fluid.Executor(place) exe.run(start) c, = exe.run(main, feed={'a': a, 'b': b}, fetch_list=[out_var]) np.testing.assert_allclose(c, np.kron(a, b))
def __measure_parameterized(self, state, which_qubits, result_desired, theta): r"""进行参数化的测量。 Args: state (Tensor): 输入的量子态 which_qubits (list): 测量作用的量子比特编号 result_desired (str): 期望得到的测量结果 theta (Tensor): 测量运算的参数 Returns: Tensor: 测量坍塌后的量子态 Tensor:测量坍塌得到的概率 str: 测量得到的结果 """ 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 = [paddle.to_tensor(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 = paddle.to_tensor( np.array([[1, 0], [0, 0]], dtype=np.complex128)) basis1 = paddle.to_tensor( np.array([[0, 0], [0, 1]], dtype=np.complex128)) rho0 = multiply(basis0, cos(theta[idx])) rho1 = multiply(basis1, sin(theta[idx])) rho = add(rho0, rho1) op_list[i] = rho elif int(ele) == 1: # rho = diag(concat([cos(theta[idx]), sin(theta[idx])])) # rho = paddle.to_tensor(rho, zeros((2, 2), dtype="float64")) basis0 = paddle.to_tensor( np.array([[1, 0], [0, 0]], dtype=np.complex128)) basis1 = paddle.to_tensor( np.array([[0, 0], [0, 1]], dtype=np.complex128)) rho0 = multiply(basis0, sin(theta[idx])) rho1 = multiply(basis1, cos(theta[idx])) rho = add(rho0, rho1) op_list[i] = rho else: print("cannot recognize the result_desired.") # rho = paddle.to_tensor(ones((2, 2), dtype="float64"), zeros((2, 2), dtype="float64")) measure_operator = paddle.to_tensor(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 = real( trace( matmul(matmul(dagger(measure_operator), measure_operator), state))) state_measured = divide(state_measured, prob) return state_measured, prob, result_desired
def test_case(self): a = np.random.randn(10, 10).astype(np.float64) b = np.random.randn(10, 10).astype(np.float64) place = fluid.CPUPlace() with dg.guard(place): a_var = dg.to_variable(a) b_var = dg.to_variable(b) c_var = paddle.kron(a_var, b_var) np.testing.assert_allclose(c_var.numpy(), np.kron(a, b))
def forward(self, problem=1): jj = paddle.to_tensor(np.array([1j], dtype=np.complex64)) # tr = paddle.trace(self.A) # _A = paddle.abs(self.A) self.A = paddle.abs(self.A) self.theta2 = self.theta0 + self.theta1 * jj if problem == 1: # matmul不支持不同dtype之间的运算 loss = paddle.sum(paddle.matmul(self.theta0, self.A)) return loss elif problem == 2: # kron在复数情况下不支持梯度反传 tmp_theta = paddle.kron(self.theta0, self.theta2) tmp_A = paddle.kron(self.A, self.B) loss = paddle.sum(paddle.matmul(tmp_theta, tmp_A)) return loss.real() elif problem == 3: # loss有时会越来越大 loss = paddle.sum(paddle.matmul(self.theta2, self.A)) # print("loss: ", loss) return loss.real() else: raise NotImplementedError
def forward(self, x): #TODO: matrix = paddle.ones([1, 1], dtype=np.float32) for t in self.thetas: cs = paddle.cos(t / 2) sn = paddle.sin(t / 2) m = paddle.concat([ paddle.concat([cs, -sn], axis=1), paddle.concat([sn, cs], axis=1), ], axis=0) matrix = paddle.kron(matrix, m) x = paddle.matmul(matrix, x) return x
def set_init_state(self, state, which_qubits): r"""对 LoccNet 的初始 LOCC 态节点进行初始化。 Args: state (Tensor): 输入的量子态的矩阵形式 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 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 test_kron_api(self, place): with dg.guard(place): x_var = dg.to_variable(self.x) y_var = dg.to_variable(self.y) out_var = paddle.kron(x_var, y_var) self.assertTrue(np.allclose(out_var.numpy(), self.ref_result))
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" 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