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
Exemple #2
0
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
Exemple #3
0
    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
Exemple #4
0
    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
Exemple #5
0
    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()
Exemple #6
0
    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
Exemple #7
0
    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
Exemple #9
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