Exemplo n.º 1
0
    def get_fidelity_with(self,
                          target_state: Union[str, q.qarray] = "ghz") -> float:
        """
        :param target_state:
            One of "ghz", "ghz_antisymmetric", "ground", and "excited".
            Can also be ghz_component_1 or ghz_component_2
        :return:
        """
        assert (
            self.evo
            is not None), "evo attribute cannot be None (call solve method)"

        final_state = self.solved_states[-1]
        if target_state == "ghz":
            return q.fidelity(final_state,
                              self.ghz_state.get_state_tensor(symmetric=True))
        elif target_state == "ghz_antisymmetric":
            return q.fidelity(final_state,
                              self.ghz_state.get_state_tensor(symmetric=False))
        elif target_state == "ghz_component_1":
            return q.fidelity(final_state, self.ghz_state._get_components()[0])
        elif target_state == "ghz_component_2":
            return q.fidelity(final_state, self.ghz_state._get_components()[1])
        elif target_state == "ground":
            return q.fidelity(final_state,
                              q.kron(*states_quimb.get_ground_states(self.N)))
        elif target_state == "excited":
            return q.fidelity(final_state,
                              q.kron(*states_quimb.get_excited_states(self.N)))
        elif isinstance(target_state, q.qarray):
            return q.fidelity(final_state, target_state)
        else:
            raise ValueError(
                f"target_state has to be one of 'ghz', 'ground', or 'excited', not {target_state}."
            )
Exemplo n.º 2
0
    def gen_term(self, sites=None):
        """Generate the interaction term acting on ``sites``.
        """
        # make sure have sites as (i, i + 1) if supplied
        if sites is not None:
            i, j = sites = tuple(sorted(sites))
            if j - i != 1:
                raise ValueError("Only nearest neighbour interactions are "
                                 "supported for an ``NNI``.")
        else:
            i = j = None

        term = self.H2s.get(sites, self.H2s[None])
        if term is None:
            raise ValueError("No term has been set for sites {}, either specif"
                             "ically or via a default term.".format(sites))

        # add single site term to left site if present
        H1 = self.H1s.get(i, self.H1s[None])

        # but only if this site has a term set
        if H1 is not None:
            I_2 = qu.eye(H1.shape[0], dtype=H1.dtype)
            term = term + qu.kron(H1, I_2)

        # if not PBC, for the last interaction, add to right site as well
        if sites and (j == self.n - 1) and (not self.cyclic):
            H1 = self.H1s.get(j, self.H1s[None])

            # but again, only if that site has a term set
            if H1 is not None:
                I_2 = qu.eye(H1.shape[0], dtype=H1.dtype)
                term = term + qu.kron(I_2, H1)

        return term
Exemplo n.º 3
0
def two_qubit_eigsectors(strA='XY', strB='YX'):
    '''

    Params: strA, strB [strings]
        Action of stabilizers on face-qubit subspace.

    Return: `eigsectors` [ndarray(shape=(2,2), dtype=object)]
        Each element of eigsector contains the unique vector
        in the face-qubit subspace that diagonalizes strA, strB
        with respective eigenvalues +/-1.

        eigsectors[0,0]: +1, +1
        eigsectors[0,1]: +1, -1
        eigsectors[1,0]: -1, +1
        eigsectors[1,1]: -1, -1

    '''
    sign_dic = {0: 1.0,  1: -1.0}
    X, Y, Z, I = (qu.pauli(mu) for mu in ['x','y','z','i'])
    opmap = {'X': X, 'Y':Y, 'Z':Z, 'I':I}

    face_dims = [2]*2 #dimensions of face-qubit subspace

    # ###
    # strA = 'XY'
    # strB = 'YX'
    # ###

    SA = qu.kron(*[opmap[Q] for Q in strA])
    SB = qu.kron(*[opmap[Q] for Q in strB])
    # SA, SB = X&Y, Y&X

    eigsectors = np.ndarray(shape=face_dims, dtype=object)


    eva, Ua = qu.eigh(SA)
    for indA, signA in sign_dic.items():
        
        #pick evectors in (signA) sector
        Ua_sgn = Ua[:, np.isclose(eva, signA)] #4x2
        
        #Stabilizer B on (signA) eigspace of SA
        Qb = Ua_sgn.H @ SB @ Ua_sgn
        
        evb, Ub = qu.eigh(Qb)

        for indB, signB in sign_dic.items():

            #pick evector in signB sector
            Ub_sgn = Ub[:,np.isclose(evb, signB)] #2x1
            
            face_state =  Ua_sgn @ Ub_sgn #4x1

            assert np.allclose(SA@face_state, signA*face_state)
            assert np.allclose(SB@face_state, signB*face_state)

            eigsectors[indA,indB] = face_state

    return eigsectors
Exemplo n.º 4
0
 def _get_components(self) -> Tuple[q.qarray, q.qarray]:
     ghz_1 = q.kron(*[
         q.ket([0, 1], sparse=True) if _ %
         2 == 0 else q.ket([1, 0], sparse=True) for _ in range(self.N)
     ])
     ghz_2 = q.kron(*[
         q.ket([0, 1], sparse=True) if _ %
         2 == 1 else q.ket([1, 0], sparse=True) for _ in range(self.N)
     ])
     return ghz_1, ghz_2
Exemplo n.º 5
0
 def _get_components(self) -> Tuple[q.qarray, q.qarray]:
     ghz_1 = q.kron(*[
         q.ket([0, 1], sparse=True) if self.single_component[i] else q.
         ket([1, 0], sparse=True) for i in range(self.N)
     ])
     ghz_2 = q.kron(*[
         q.ket([0, 1], sparse=True) if not self.single_component[i] else q.
         ket([1, 0], sparse=True) for i in range(self.N)
     ])
     return ghz_1, ghz_2
Exemplo n.º 6
0
    def __init__(self,
                 N: int,
                 V: float,
                 geometry: BaseGeometry,
                 Omega: np.ndarray,
                 Delta: np.ndarray,
                 t_list: np.ndarray,
                 ghz_state: BaseGHZState,
                 solve_points_per_timestep: int = 1):
        super().__init__(N, V, geometry)

        self.Omega = Omega
        self.Delta = Delta
        self.t_list = t_list

        assert len(t_list) - 1 == len(Omega) == len(Delta), \
            "Omega and Delta need to be of equal length, and of length one less than t_list"

        self.psi_0 = q.kron(*states_quimb.get_ground_states(N))
        self.ghz_state = ghz_state

        self.solve_points_per_timestep = solve_points_per_timestep

        self.evo: Optional[q.Evolution] = None
        self.solved_states: List[q.qarray] = []
        self.solved_t_list = []
Exemplo n.º 7
0
 def test_pauli_reconstruct(self):
     p1 = qu.rand_rho(4)
     names_cffs = qu.pauli_decomp(p1, mode='c')
     pr = sum(
         qu.kron(*(qu.pauli(s) for s in name)) * names_cffs["".join(name)]
         for name in itertools.product('IXYZ', repeat=2))
     assert_allclose(pr, p1)
Exemplo n.º 8
0
 def test_kron_basic(self, parallel):
     a = qu.rand_ket(2)
     b = qu.rand_ket(4)
     c = qu.rand_ket(4)
     d = qu.rand_ket(5)
     t = qu.kron(a, b, c, d, parallel=parallel)
     assert_allclose(t, a & b & c & d)
Exemplo n.º 9
0
 def test_partial_trace_dop_product_state(self):
     dims = [3, 2, 4, 2, 3]
     ps = [qu.rand_rho(dim) for dim in dims]
     pt = qu.kron(*ps)
     for i, dim in enumerate(dims):
         p = qu.partial_trace(pt, dims, i)
         assert_allclose(p, ps[i])
Exemplo n.º 10
0
    def get_energies(self):
        omega_zero_all_energies = []
        omega_non_zero_all_energies = []

        state_tensors = [q.kron(*state) for state in self.states]
        for detuning in tqdm(self.Delta):
            H = self.get_hamiltonian(detuning)
            energies = []

            for i, state in enumerate(self.states):
                energy = q.expec(H, state_tensors[i]).real
                energies.append(energy)
            omega_zero_all_energies.append(energies)
            if self.Omega != 0:
                eigenvalues = q.eigvalsh(H.toarray()).real
                omega_non_zero_all_energies.append(eigenvalues)
        self.Omega_zero_energies = np.array(omega_zero_all_energies)
        self.Omega_non_zero_energies = np.array(omega_non_zero_all_energies)
Exemplo n.º 11
0
    def __init__(self,
                 N: int,
                 V: float,
                 geometry: BaseGeometry,
                 t_list: np.ndarray,
                 ghz_state: BaseGHZState,
                 Omega_range: Tuple[float, float],
                 Delta_range: Tuple[float, float],
                 verbose: bool = False):
        self.verbose = verbose

        self.ti_evolving_qubit_system_kwargs = {
            'N': N,
            'V': V,
            'geometry': geometry,
            'ghz_state': ghz_state,
            't_list': np.linspace(0, t_list[1], 10)
        }
        self.psi_0 = q.kron(*states_quimb.get_ground_states(N))
        self.t_list = t_list

        self.required_steps = len(t_list) - 1
        # Actions for all ts except the end.

        self.recorded_steps = {
            'Omega': [],
            'Delta': [],
        }
        self.step_number = 0
        self.latest_evolving_qubit_system: Optional[
            TimeIndependentEvolvingQubitSystem] = None
        self.total_solve_time = 0

        self.action_normalisation = Omega_range, Delta_range
        self.action_space = gym.spaces.Box(low=np.array([0, 0],
                                                        dtype=np.float32),
                                           high=np.array([1, 1],
                                                         dtype=np.float32))
        # Using action_normalisation as PPO policy generates actions of order 1

        self.observation_space = gym.spaces.Discrete(self.required_steps)

        self._maximum_fidelity_achieved = 0.505
Exemplo n.º 12
0
    def make_stab_gate_map(self, coo_stab_map, store='gate'):
        '''TODO: NOW MAPS coos to (where, gate) tuples.

        Return
        -------
        `gate_map`: dict[tuple : (tuple, qarray)] 
            Maps coordinates (x,y) in the *face* array (empty 
            faces!) to pairs (where, gate) that specify the 
            stabilizer gate and the sites to be acted on.

        Param:
        ------
        coo_stab_map: dict[tuple : dict]
            Maps coordinates (x,y) in the FACE array of the lattice
            to `loop_stab` dictionaries of the form
            {'inds' : (indices),   'opstring' : (string)}
        
        store: 'gate' or 'tuple', optional
            Whether to store a 'dense' 2**8 x 2**8 array or a tuple
            of 8 (ordered) 2 x 2 arrays
        '''
        gate_map = dict()

        for coo, loop_stab in coo_stab_map.items():
            qubits = tuple(loop_stab['inds'])  #tuple e.g. (1,2,4,5,6)
            opstring = loop_stab['opstring']  #str e.g. 'ZZZZX'

            if store == 'gate':
                # store (where, kron(gate1,gate2,...))
                gate = qu.kron(*(qu.pauli(Q) for Q in opstring))
                gate *= self.multiplier
                gate_map[coo] = (qubits, gate)

            elif store == 'tuple':
                # store (where, (gate1, gate2, ...))
                signs = [self.multiplier] + [1.0] * (len(opstring) - 1)
                gates = tuple(signs[k] * qu.pauli(Q)
                              for k, Q in enumerate(opstring))
                gate_map[coo] = (qubits, gates)

        return gate_map
Exemplo n.º 13
0
    def __init__(self,
                 N: int,
                 V: float,
                 geometry: BaseGeometry,
                 Omega: float,
                 Delta: float,
                 t_list: np.ndarray,
                 ghz_state: BaseGHZState,
                 psi_0: q.qarray = None):
        super().__init__(N, V, geometry)

        self.Omega = Omega
        self.Delta = Delta
        self.t_list = t_list

        self.psi_0 = q.kron(*states_quimb.get_ground_states(
            N, sparse=True)) if psi_0 is None else psi_0
        self.ghz_state = ghz_state

        self.evo: Optional[q.Evolution] = None
        self.solved_states: List[q.qarray] = []
Exemplo n.º 14
0
 def _get_components(self) -> Tuple[q.qarray, q.qarray]:
     return q.kron(*get_ground_states(self.N, sparse=True)), q.kron(
         *get_excited_states(self.N, sparse=True))
Exemplo n.º 15
0
def three_qubit_U_matrix(qlattice, qstabs=None):
    '''
    TODO: 
    *define SX_vert (vertices acted on by Z-stabilizer)
    '''
    sectors = {1.0: 0,  -1.0: 1}
    X, Y, Z, I = (qu.pauli(mu) for mu in ['x','y','z','i'])
    opmap = {'X': X, 'Y':Y, 'Z':Z, 'I':I}

    face_dims = [2]*3 #dimensions of face-qubit subspace


    if qstabs==None:

        qstab_A = loopStabOperator( vert_inds=[1,2,5,4],
                                    face_op_str='XYI',
                                    face_inds=[12,13,14])  

        qstab_B = loopStabOperator( vert_inds=[3,4,7,6],
                                    face_op_str='YXY',
                                    face_inds=[12,13,14])  
        
        qstab_C = loopStabOperator( vert_inds=[7,8,11,10],
                                    face_op_str='IYX',
                                    face_inds=[12,13,14])                                                                 
    

    SA = qu.kron(*[opmap[Q] for Q in qstab_A.face_op_str])
    SB = qu.kron(*[opmap[Q] for Q in qstab_B.face_op_str])
    SC = qu.kron(*[opmap[Q] for Q in qstab_C.face_op_str])
    # SA, SB, SC = X&Y&I, Y&X&Y, I&Y&X 

    eigfaces = np.ndarray(shape=face_dims, dtype=object)


    for signA, indA in sectors.items():

        eva, Ua = qu.eigh(SA)
        Ua_sector = Ua[:,eva==signA] #8x4

        Qb = Ua_sector.H @ SB @ Ua_sector
        # Qc = Ua_sector.H @ SC @ Ua_sector
        
        evb, Ub = qu.eigh(Qb)

        for signB, indB in sectors.items():

            Ub_sector = Ub[:, np.isclose(evb,signB)] #4x2

            #SC on b-eigenspace
            Qc = Ub_sector.H @ Ua_sector.H @ SC @ Ua_sector @ Ub_sector #2x2
            
            evc, Uc = qu.eigh(Qc)

            for signC, indC in sectors.items():
                
                #should be in a 1-dimensional subspace now
                vec = Uc[:,np.isclose(evc,signC)]

                #vector in 8-dim face qubit space
                face_vec = Ua_sector @ Ub_sector @ vec

                assert np.allclose(SA@face_vec, signA*face_vec)
                assert np.allclose(SB@face_vec, signB*face_vec)
                assert np.allclose(SC@face_vec, signC*face_vec)
                
                eigfaces[indA,indB,indC] = face_vec


    Nfermi, Nqubit = qlattice._Nfermi, qlattice._Nsites
    code_dims = [2]*Nfermi #vertices 
    qub_dims = [2]*Nqubit #vertices&faces


    #######
    qindices_A = qstab_A.vert_inds
    qindices_B = qstab_B.vert_inds
    qindices_C = qstab_C.vert_inds
    #######

    #parts of stabilizers acting only on vertex qubits
    SA_vert = qu.ikron(ops=[Z,Z,Z,Z], inds=qindices_A,
                    dims=code_dims)

    SB_vert = qu.ikron(ops=[Z,Z,Z,Z], inds=qindices_B,
                        dims=code_dims)
    
    SC_vert = qu.ikron(ops=[Z,Z,Z,Z], inds=qindices_C,
                        dims=code_dims)
                    
    Uplus = np.ndarray(shape=(2**Nqubit, 2**Nfermi))

    print('here')
    for k in range(2**Nfermi):
        print(k%10)
        #state of vertex qubits, all local z-eigenstates
        vertex_state = qu.basis_vec(i=k, dim=2**Nfermi)

        secA = sectors[qu.expec(SA_vert, vertex_state)]
        secB = sectors[qu.expec(SB_vert, vertex_state)]
        secC = sectors[qu.expec(SC_vert, vertex_state)]

        face_state = eigfaces[secA, secB, secC] 

        full_state = vertex_state & face_state

        #"stable" eigenstate written in qubit basis
        Uplus[:,k] = full_state.flatten()

        #full_state should be +1 eigenstate of all stabilizers
        assert np.allclose((SA_vert&SA) @ full_state, full_state)
        assert np.allclose((SB_vert&SB) @ full_state, full_state)
        assert np.allclose((SC_vert&SC) @ full_state, full_state)

    return qu.qu(Uplus)
Exemplo n.º 16
0
 def string_to_gate(cls, string_op):
     X, Y, Z, I = (qu.pauli(mu) for mu in ['x','y','z','i'])
     opmap = {'X': X, 'Y':Y, 'Z':Z, 'I':I}
     return qu.kron(*[opmap[Q] for Q in string_op])
Exemplo n.º 17
0
 def test_kron_ownership(self, sparse, ri, rf):
     dims = [7, 2, 4, 3]
     ops = [qu.rand_matrix(d, sparse=sparse) for d in dims]
     X1 = qu.kron(*ops)[ri:rf, :]
     X2 = qu.kron(*ops, ownership=(ri, rf))
     assert_allclose(X1.A, X2.A)
Exemplo n.º 18
0
def get_product_basis_states_index(state: List[q.qarray]) -> int:
    return q.kron(*state).argmax()