Ejemplo n.º 1
0
    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
Ejemplo n.º 2
0
    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
Ejemplo n.º 4
0
    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
Ejemplo n.º 5
0
    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
Ejemplo n.º 6
0
    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
Ejemplo n.º 7
0
    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
Ejemplo n.º 8
0
    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
Ejemplo n.º 9
0
    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