Example #1
0
 def matrix(self, **kwargs) -> tf.Tensor:
     Us = []
     for i in range(self.thetas.shape[0]):
         Us.append(qc.U(self.thetas[i]))
     if self.targets:
         return tensor([self.pre_identity, *Us, self.post_identity])
     else:
         return tensor(Us)
Example #2
0
def layer1(w1, w2, w3, x1, x2, x3, t1, t2, t3):
    state_1_in = tensor([w1, x1])
    state_2_in = tensor([w2, x2])
    state_3_in = tensor([w3, x3])
    state_in = tensor([state_1_in, state_2_in, state_3_in])
    U_layer1.thetas.assign([t1, t2, t3])
    state_out = U_layer1.matrix() @ state_in
    out_layer1 = density_matrix(state_out, [0, 4, 8])
    return out_layer1
Example #3
0
    def test_non_last_qubits_trace(self):
        # Test trace for two conseg. non-last qubits
        state1 = tensor([s0, s1])
        state2 = tensor([(s0 + s1)/np.sqrt(2), (s0 - s1)/np.sqrt(2)])
        state = tensor([state1, state2])
        dm1 = trace(density_matrix(state), [0, 1])
        self.assertTrue(almost_equal(dm1, density_matrix(state2)))

        # Test trace for two separated non-last qubits
        state_test = tensor([s0, (s0 + s1)/np.sqrt(2)])
        dm2 = trace(density_matrix(state), [1, 3])
        self.assertTrue(almost_equal(dm2, density_matrix(state_test)))
Example #4
0
def layer2(state_w, dm_in, t4):
    dm_w = density_matrix(state_w)
    dm_in = tensor([dm_w, dm_in])
    # ndtotext_print(dm_in)
    # Remember this is a density matrix, so we must apply U on both sides
    U_layer2.thetas.assign([t4])
    U_matrix = U_layer2.matrix()
    dm_out = U_matrix @ dm_in @ tf.math.conj(U_matrix)
    return trace(dm_out, [1, 2, 3])
Example #5
0
    def call(self, inputs, training=None, mask=None):
        x1, x2, x3 = inputs[..., 0, :, :], inputs[...,
                                                  1, :, :], inputs[...,
                                                                   2, :, :]
        state_1_in = tensor([self.w1, x1])
        state_2_in = tensor([self.w2, x2])
        state_3_in = tensor([self.w3, x3])
        state_in = tensor([state_1_in, state_2_in, state_3_in])
        state_out = self.U_layer1.matrix() @ state_in
        dm_out_layer1 = density_matrix(state_out, [0, 4, 8])

        dm_w = density_matrix(self.w4)
        dm_in = tensor([dm_w, dm_out_layer1])
        U_matrix = self.U_layer2.matrix()
        dm_out = U_matrix @ dm_in @ tf.math.conj(U_matrix)
        dm_output = trace(dm_out, [1, 2, 3])
        P0 = dm_output[..., 0, 0]
        return P0
Example #6
0
 def apply_qc_to_data(fea):
     opers = []
     # Encoding is Z(acos(x**2)) * Y(asin(x)) on all qubits
     encoding_oper = qc.RZ(fea[0]) @ qc.RY(fea[1])
     opers.append(tensor([
         encoding_oper,
         encoding_oper,
         encoding_oper,
         encoding_oper
     ]))
     return apply_operators2state(opers, s0000)
 def apply_qc_to_data(data):
     opers = []
     opers.append(
         tensor([
             U3([data[0], π / 2,
                 π / 2]),  # ERR NOT THE SAME AS XYZ!!!
             U3([data[1], π / 2, π / 2]),
             U3([data[0], π / 2, π / 2]),
             U3([data[1], π / 2, π / 2])
         ]))
     opers.append(u_1)
     return apply_operators2state(opers, s0000)
Example #8
0
 def apply_qc_to_data(data):
     opers = []
     opers.append(tensor([
         U3([data[0], π/2, π/2]),
         U3([data[1], π/2, π/2]),
         U3([data[2], π/2, π/2]),
         U3([data[3], π/2, π/2])
     ]))
     opers.append(u_1)
     # opers.append(u3_1)
     # opers.append(u_2)
     # opers.append(u3_2)
     return apply_operators2state(opers, s0000)
Example #9
0
 def apply_qc_to_data(data):
     opers = []
     opers.append(
         tensor([
             RX(data[0]) @ RY(π / 4) @ RZ(π / 4),
             RX(data[1]) @ RY(π / 4) @ RZ(π / 4),
             RX(data[0]) @ RY(π / 4) @ RZ(π / 4),
             RX(data[1]) @ RY(π / 4) @ RZ(π / 4)
         ]))
     opers.append(u3_1)
     opers.append(u_1)
     opers.append(u3_2)
     opers.append(u_2)
     opers.append(u3_3)
     opers.append(u_3)
     # opers.append(uXY_4)
     # opers.append(u_4)
     return apply_operators2state(opers, s0000)
Example #10
0
    data = lambda N: random_pure_states((2, 2**N, 1))
    l1 = ULayer()
    l2 = ULayer([[0, 1, 2, 3], [4, 5, 6, 7]])
    l1(data(8))
    l2(data(8))
    l1.thetas = l2.thetas
    assert tf.reduce_all(l1.matrix() == l2.matrix())

    l1 = ULayer()
    l_I1 = ILayer()
    l2 = ULayer([[0, 1, 2, 3], [4, 5, 6, 7]])
    l1(data(8))
    l_I1(data(1))
    l2(data(9))
    l1.thetas = l2.thetas
    assert tf.reduce_all(tensor([l1.matrix(), l_I1.matrix()]) == l2.matrix())

    l1 = ULayer()
    l_I1 = ILayer()
    l2 = ULayer([[1, 2, 3, 4], [5, 6, 7, 8]])
    l1(data(8))
    l_I1(data(1))
    l2(data(10))
    l1.thetas = l2.thetas
    assert tf.reduce_all(
        tensor([l_I1.matrix(), l1.matrix(),
                l_I1.matrix()]) == l2.matrix())

    l1 = ULayer()
    l_I2 = ILayer()
    l2 = ULayer([0, 1, 2, 3])
Example #11
0
from tf_qc import complex_type
from tf_qc.layers import ULayer
from tf_qc.utils import random_pure_states, normalize_state_vectors
from tf_qc.qc import s0, s1, tensor, density_matrix, trace
from txtutils import ndtotext_print
import tensorflow as tf
import math

π = math.pi

s000 = tensor([s0, s0, s0])
s001 = tensor([s0, s0, s1])
s010 = tensor([s0, s1, s0])
s011 = tensor([s0, s1, s1])
s100 = tensor([s1, s0, s0])
s101 = tensor([s1, s0, s1])
s110 = tensor([s1, s1, s0])
s111 = tensor([s1, s1, s1])

targets = [0, 1, 2, 3]
u_layer = ULayer(targets)

data = random_pure_states((10, 2**4, 1), post_zeros=0)
data_shape = data.shape

u_layer.build(data_shape)


def tree_qubit_state(amps):
    amps = tf.reshape(amps, (-1, 2**3, 1))
    return tf.cast(normalize_state_vectors(amps), complex_type)
Example #12
0
            def call(self, inputs, training=None, mask=None):
                uXY_1 = tensor([
                    RX(self.wXY_1[0]) @ RZ(self.wXY_1[1]),
                    RX(self.wXY_1[2]) @ RZ(self.wXY_1[3]),
                    RX(self.wXY_1[4]) @ RZ(self.wXY_1[5]),
                    RX(self.wXY_1[6]) @ RZ(self.wXY_1[7])
                ])
                uXY_2 = tensor([
                    RX(self.wXY_2[0]) @ RZ(self.wXY_2[1]),
                    RX(self.wXY_2[2]) @ RZ(self.wXY_2[3]),
                    RX(self.wXY_2[4]) @ RZ(self.wXY_2[5]),
                    RX(self.wXY_2[6]) @ RZ(self.wXY_2[7])
                ])
                uXY_3 = tensor([
                    RX(self.wXY_3[0]) @ RZ(self.wXY_3[1]),
                    RX(self.wXY_3[2]) @ RZ(self.wXY_3[3]),
                    RX(self.wXY_3[4]) @ RZ(self.wXY_3[5]),
                    RX(self.wXY_3[6]) @ RZ(self.wXY_3[7])
                ])
                uXY_4 = tensor([
                    RX(self.wXY_4[0]) @ RZ(self.wXY_4[1]),
                    RX(self.wXY_4[2]) @ RZ(self.wXY_4[3]),
                    RX(self.wXY_4[4]) @ RZ(self.wXY_4[5]),
                    RX(self.wXY_4[6]) @ RZ(self.wXY_4[7])
                ])
                u3_1 = tensor([
                    U3(self.wU3_1[0:3]),
                    U3(self.wU3_1[3:6]),
                    U3(self.wU3_1[6:9]),
                    U3(self.wU3_1[9:12])
                ])
                u3_2 = tensor([
                    U3(self.wU3_2[0:3]),
                    U3(self.wU3_2[3:6]),
                    U3(self.wU3_2[6:9]),
                    U3(self.wU3_2[9:12])
                ])
                u3_3 = tensor([
                    U3(self.wU3_3[0:3]),
                    U3(self.wU3_3[3:6]),
                    U3(self.wU3_3[6:9]),
                    U3(self.wU3_3[9:12])
                ])
                u_1 = qc.U(self.w_U_iswap[0])
                u_2 = qc.U(self.w_U_iswap[1])
                u_3 = qc.U(self.w_U_iswap[2])
                u_4 = qc.U(self.w_U_iswap[3])

                # iswap_C1T1 = ISWAPLayer.matrix_static(4, [0, 2], self.w_U_iswap[0])
                # iswap_C1T2 = ISWAPLayer.matrix_static(4, [0, 3], self.w_U_iswap[1])
                # iswap_C2T1 = ISWAPLayer.matrix_static(4, [1, 2], self.w_U_iswap[2])
                # iswap_C2T2 = ISWAPLayer.matrix_static(4, [1, 3], self.w_U_iswap[3])
                # u_2 = qc.U(self.wU[1])
                # u_3 = qc.U(self.wU[2])
                def apply_qc_to_data(data):
                    opers = []
                    opers.append(
                        tensor([
                            RX(data[0]) @ RY(π / 4) @ RZ(π / 4),
                            RX(data[1]) @ RY(π / 4) @ RZ(π / 4),
                            RX(data[0]) @ RY(π / 4) @ RZ(π / 4),
                            RX(data[1]) @ RY(π / 4) @ RZ(π / 4)
                        ]))
                    opers.append(u3_1)
                    opers.append(u_1)
                    opers.append(u3_2)
                    opers.append(u_2)
                    opers.append(u3_3)
                    opers.append(u_3)
                    # opers.append(uXY_4)
                    # opers.append(u_4)
                    return apply_operators2state(opers, s0000)

                outputs = tf.map_fn(apply_qc_to_data,
                                    inputs,
                                    dtype=complex_type,
                                    parallel_iterations=12)

                # Make a linearcombi. of the output probabilities
                # we measure all of them as combine them in linear combi. + bias and then apply sigmoid
                # print(outputs)
                Ps = tf.cast(measure(outputs, [0]), float_type)
                # print(Ps)
                return Ps
Example #13
0
 def naive_impl(states, n):
     tensor([states] + [s0] * n)
Example #14
0
 def test_gate_expand_2to_n(self):
     swap2 = SWAP(2, 0, 1)
     self.assertTrue(almost_equal(gate_expand_2toN(swap2, 3, targets=[0, 1]), tensor([swap2, I1])))
     self.assertTrue(almost_equal(gate_expand_2toN(swap2, 4, targets=[1, 2]), tensor([I1, swap2, I1])))
     self.assertTrue(almost_equal(gate_expand_2toN(swap2, 4, targets=[2, 3]), tensor([I1, I1, swap2])))
Example #15
0
    def call(self, inputs, training=None, mask=None):
        u_1 = ISWAPLayer.matrix_static(4, [1,2], self.w_U[0])
        u_2 = ISWAPLayer.matrix_static(4, [1,3], self.w_U[1])
        u_3 = ISWAPLayer.matrix_static(4, [1,2], self.w_U[2])
        u_4 = ISWAPLayer.matrix_static(4, [1,3], self.w_U[3])
        u_5 = ISWAPLayer.matrix_static(4, [0,3], self.w_U[4])
        u_6 = ISWAPLayer.matrix_static(4, [0,2], self.w_U[5])
        # u_1 = qc.U(self.w_U[0])
        # u_2 = qc.U(self.w_U[1])
        # u_3 = qc.U(self.w_U[2])
        # u_4 = qc.U(self.w_U[3])
        # u_5 = qc.U(self.w_U[4])
        # u_6 = qc.U(self.w_U[5])
        rxzx_1 = tensor([
            qc.RXZX(self.w_RXZX[0,0,0], self.w_RXZX[0,0,1], self.w_RXZX[0,0,2]),
            qc.RXZX(self.w_RXZX[0,1,0], self.w_RXZX[0,1,1], self.w_RXZX[0,1,2]),
            qc.RXZX(self.w_RXZX[0,2,0], self.w_RXZX[0,2,1], self.w_RXZX[0,2,2]),
            qc.RXZX(self.w_RXZX[0,3,0], self.w_RXZX[0,3,1], self.w_RXZX[0,3,2])
        ])
        rxzx_2 = tensor([
            qc.RXZX(self.w_RXZX[1, 0, 0], self.w_RXZX[1, 0, 1], self.w_RXZX[1, 0, 2]),
            qc.RXZX(self.w_RXZX[1, 1, 0], self.w_RXZX[1, 1, 1], self.w_RXZX[1, 1, 2]),
            qc.RXZX(self.w_RXZX[1, 2, 0], self.w_RXZX[1, 2, 1], self.w_RXZX[1, 2, 2]),
            qc.RXZX(self.w_RXZX[1, 3, 0], self.w_RXZX[1, 3, 1], self.w_RXZX[1, 3, 2])
        ])
        rxzx_3 = tensor([
            qc.RXZX(self.w_RXZX[2, 0, 0], self.w_RXZX[2, 0, 1], self.w_RXZX[2, 0, 2]),
            qc.RXZX(self.w_RXZX[2, 1, 0], self.w_RXZX[2, 1, 1], self.w_RXZX[2, 1, 2]),
            qc.RXZX(self.w_RXZX[2, 2, 0], self.w_RXZX[2, 2, 1], self.w_RXZX[2, 2, 2]),
            qc.RXZX(self.w_RXZX[2, 3, 0], self.w_RXZX[2, 3, 1], self.w_RXZX[2, 3, 2])
        ])
        rxzx_4 = tensor([
            qc.RXZX(self.w_RXZX[3, 0, 0], self.w_RXZX[3, 0, 1], self.w_RXZX[3, 0, 2]),
            qc.RXZX(self.w_RXZX[3, 1, 0], self.w_RXZX[3, 1, 1], self.w_RXZX[3, 1, 2]),
            qc.RXZX(self.w_RXZX[3, 2, 0], self.w_RXZX[3, 2, 1], self.w_RXZX[3, 2, 2]),
            qc.RXZX(self.w_RXZX[3, 3, 0], self.w_RXZX[3, 3, 1], self.w_RXZX[3, 3, 2])
        ])
        rxzx_5 = tensor([
            qc.RXZX(self.w_RXZX[4, 0, 0], self.w_RXZX[4, 0, 1], self.w_RXZX[4, 0, 2]),
            qc.RXZX(self.w_RXZX[4, 1, 0], self.w_RXZX[4, 1, 1], self.w_RXZX[4, 1, 2]),
            qc.RXZX(self.w_RXZX[4, 2, 0], self.w_RXZX[4, 2, 1], self.w_RXZX[4, 2, 2]),
            qc.RXZX(self.w_RXZX[4, 3, 0], self.w_RXZX[4, 3, 1], self.w_RXZX[4, 3, 2])
        ])
        rxzx_6 = tensor([
            qc.RXZX(self.w_RXZX[5, 0, 0], self.w_RXZX[5, 0, 1], self.w_RXZX[5, 0, 2]),
            qc.RXZX(self.w_RXZX[5, 1, 0], self.w_RXZX[5, 1, 1], self.w_RXZX[5, 1, 2]),
            qc.RXZX(self.w_RXZX[5, 2, 0], self.w_RXZX[5, 2, 1], self.w_RXZX[5, 2, 2]),
            qc.RXZX(self.w_RXZX[5, 3, 0], self.w_RXZX[5, 3, 1], self.w_RXZX[5, 3, 2])
        ])

        def apply_qc_to_data(fea):
            opers = []
            # Encoding is Z(acos(x**2)) * Y(asin(x)) on all qubits
            encoding_oper = qc.RZ(fea[0]) @ qc.RY(fea[1])
            opers.append(tensor([
                encoding_oper,
                encoding_oper,
                encoding_oper,
                encoding_oper
            ]))
            return apply_operators2state(opers, s0000)

        encoding = tf.map_fn(apply_qc_to_data, inputs, dtype=complex_type, parallel_iterations=12)
        W_circuit = [  # This is the parametrized circuit
            u_1, rxzx_1,
            u_2, rxzx_2,
            u_3, rxzx_3,
            u_4, rxzx_4,
            u_5, rxzx_5,
            u_6, rxzx_6
        ]
        outputs = apply_operators2state(W_circuit, encoding)

        # Measure Z on 1st qubit and add a bit of noise
        # https://en.wikipedia.org/wiki/Density_matrix#Measurement
        # The expectation value <Z> = tr(density_matrix @ Z_oper)
        # Z_oper = [[1,0], [0,-1]] so <Z> = density_matrix[0,0] - density_matrix[1,1]
        # But P0 - P1 = P0 - (1-P0) = 2*P0 - 1, so <Z> = 2*density_matrix[0,0] - 1
        # OK to take partial trace first: https://en.wikipedia.org/wiki/Partial_trace#Partial_trace_as_a_quantum_operation
        Z01 = measure(outputs, [0])
        Z_exp = 2*tf.cast(Z01[..., 0], float_type) - 1
        noise = tf.sqrt(2/self.samples) * (Z_exp**2 - 1)/4
        measurement = self.out_scale * (Z_exp + noise) + self.out_bias
        return measurement