示例#1
0
    def test_integrate(self):

        # Basic test
        sx = SpinOperator.from_axes()
        sz = SpinOperator.from_axes(0.5, 'z')

        H = Hamiltonian(sz.matrix)
        L = Lindbladian.from_hamiltonian(H)
        rho0 = DensityOperator.from_vectors(0.5, [1, 0, 0], 0)
        t = np.linspace(0, 1, 100)

        tau = 2.0
        avg = L.integrate_decaying(rho0, tau, sx)

        self.assertAlmostEqual(avg[0], 0.5*tau/(1+4*np.pi**2*tau**2))

        # Same but with decay
        for g in [1.0, 2.0, 5.0, 10.0]:

            L = Lindbladian.from_hamiltonian(H, [(sx, g)])
            avg = L.integrate_decaying(rho0, tau, sx)

            ap = -0.5*np.pi*g+((0.5*np.pi*g)**2-4*np.pi**2)**0.5
            am = -0.5*np.pi*g-((0.5*np.pi*g)**2-4*np.pi**2)**0.5
            A = ap*am/(am-ap)

            # Analytical solution for this case
            sol = np.real(0.5*A*tau*(1/((1-ap*tau)*ap)-1/((1-am*tau)*am)))

            self.assertAlmostEqual(avg[0], sol)
示例#2
0
    def get_starting_state(self):
        """Return the starting quantum state for the system

        Build the starting quantum state for the system as a coherently 
        polarized muon + a thermal density matrix (using only the Zeeman 
        terms) for every other spin for the current magnetic field,
        temperature, and muon polarization axis.

        Returns:
            DensityOperator -- The starting density matrix
        """

        if self._rho0 is None:
            T = self._T
            muon_axis = self._mupol

            mu_i = self.spin_system.muon_index
            rhos = []

            for i, s in enumerate(self.spin_system.spins):
                I = self.spin_system.I(i)
                if i == mu_i:
                    r = DensityOperator.from_vectors(I, muon_axis, 0)
                else:
                    # Get the Zeeman Hamiltonian for this field
                    Sz = SpinOperator.from_axes(I, 'z')
                    E = np.diag(
                        Sz.matrix) * self.spin_system.gamma(i) * self.B * 1e6
                    if T > 0:
                        Z = np.exp(-cnst.h * E / (cnst.k * T))
                    else:
                        Z = np.where(E == np.amin(E), 1.0, 0.0)
                    if np.sum(Z) > 0:
                        Z /= np.sum(Z)
                    else:
                        Z = np.ones(len(E)) / len(E)
                    r = DensityOperator(np.diag(Z))

                rhos.append(r)

            self._rho0 = rhos[0]
            for r in rhos[1:]:
                self._rho0 = self._rho0.kron(r)

        return self._rho0
示例#3
0
    def test_integrate(self):

        ssys = SpinSystem(['e'])
        ssys.add_linear_term(0, [1, 0, 0])  # Precession around x
        H = ssys.hamiltonian
        rho0 = DensityOperator.from_vectors()  # Start along z
        avg = H.integrate_decaying(rho0, 1.0, ssys.operator({0: 'z'}))

        self.assertTrue(np.isclose(avg[0], 0.5 / (1.0 + 4 * np.pi**2)))
示例#4
0
    def test_evolve(self):

        ssys = SpinSystem(['e'])
        ssys.add_linear_term(0, [1, 0, 0])  # Precession around x
        H = ssys.hamiltonian
        rho0 = DensityOperator.from_vectors()  # Start along z
        t = np.linspace(0, 1, 100)

        evol = H.evolve(rho0, t, ssys.operator({0: 'z'}))

        self.assertTrue(
            np.all(np.isclose(evol[:, 0], 0.5 * np.cos(2 * np.pi * t))))
示例#5
0
    def test_superoperator(self):

        sx = SpinOperator.from_axes()
        rho0 = DensityOperator.from_vectors()
        lsx = SuperOperator.left_multiplier(sx)
        rsx = SuperOperator.right_multiplier(sx)
        csx = SuperOperator.commutator(sx)
        acsx = SuperOperator.anticommutator(sx)
        bksx = SuperOperator.bracket(sx)

        self.assertTrue(np.all((sx * rho0).matrix == (lsx * rho0).matrix))
        self.assertTrue(np.all((rho0 * sx).matrix == (rsx * rho0).matrix))
        self.assertTrue(
            np.all((sx * rho0 - rho0 * sx).matrix == (csx * rho0).matrix))
        self.assertTrue(
            np.all((sx * rho0 + rho0 * sx).matrix == (acsx * rho0).matrix))
        self.assertTrue(
            np.all((sx * rho0 * sx.dagger()).matrix == (bksx * rho0).matrix))
示例#6
0
    def test_evolve(self):

        # Basic test
        sx = SpinOperator.from_axes()
        sp = SpinOperator.from_axes(0.5, '+')
        sm = SpinOperator.from_axes(0.5, '-')
        sz = SpinOperator.from_axes(0.5, 'z')

        H = Hamiltonian(sz.matrix)
        L = Lindbladian.from_hamiltonian(H)
        rho0 = DensityOperator.from_vectors(0.5, [1, 0, 0], 0)
        t = np.linspace(0, 1, 100)

        evol = L.evolve(rho0, t, sx)

        self.assertTrue(np.all(np.isclose(evol[:, 0], 0.5*np.cos(2*np.pi*t))))

        # Same but with decay
        for g in [1.0, 2.0, 5.0, 10.0]:

            L = Lindbladian.from_hamiltonian(H, [(sx, g)])
            evol = L.evolve(rho0, t, sx)

            ap = -0.5*np.pi*g+((0.5*np.pi*g)**2-4*np.pi**2)**0.5
            am = -0.5*np.pi*g-((0.5*np.pi*g)**2-4*np.pi**2)**0.5
            A = ap*am/(am-ap)

            # Analytical solution for this case
            solx = np.real(0.5*A*(np.exp(ap*t)/ap-np.exp(am*t)/am))

            self.assertTrue(np.all(np.isclose(evol[:, 0], solx)))

            gp = g*1.5
            gm = g*0.5
            L = Lindbladian.from_hamiltonian(H, [(sp, gp), (sm, gm)])

            evol = L.evolve(rho0, t, [sx, sz])

            solx = np.real(0.5*np.cos(2*np.pi*t)*np.exp(-2*np.pi*g*t))
            solz = 0.25*(1-np.exp(-4*np.pi*g*t))

            self.assertTrue(np.all(np.isclose(evol[:, 0], solx)))
            self.assertTrue(np.all(np.isclose(evol[:, 1], solz)))
示例#7
0
    def test_operations(self):

        sx = SpinOperator.from_axes(0.5, 'x')
        sy = SpinOperator.from_axes(0.5, 'y')
        sz = SpinOperator.from_axes(0.5, 'z')

        # Scalar operations
        self.assertTrue(np.all((2 * sx).matrix == [[0, 1], [1, 0]]))
        self.assertTrue(np.all((sx / 2).matrix == [[0, 0.25], [0.25, 0]]))

        # Operators (test commutation relations)
        self.assertTrue(
            np.all((sx * sy - sy * sx).matrix == (1.0j * sz).matrix))
        self.assertTrue(
            np.all((sy * sz - sz * sy).matrix == (1.0j * sx).matrix))
        self.assertTrue(
            np.all((sz * sx - sx * sz).matrix == (1.0j * sy).matrix))

        self.assertTrue(np.all((sx + 0.5).matrix == 0.5 * np.ones((2, 2))))
        self.assertTrue(np.all((sz - 0.5).matrix == np.diag([0, -1])))

        # Test equality
        self.assertTrue(sx == SpinOperator.from_axes(0.5, 'x'))
        self.assertFalse(
            SpinOperator(np.eye(4)) == SpinOperator(np.eye(4), (2, 2)))

        # Test Kronecker product
        sxsz = sx.kron(sz)
        self.assertEqual(sxsz.dimension, (2, 2))
        self.assertTrue(
            np.all(4 * sxsz.matrix == [[0, 0, 1, 0], [0, 0, 0, -1],
                                       [1, 0, 0, 0], [0, -1, 0, 0]]))

        # Test Hilbert-Schmidt product
        rho = DensityOperator.from_vectors(0.5, np.array([1, 1, 0]) / 2**0.5)
        sx = SpinOperator.from_axes(0.5, 'x')
        self.assertEqual(2 * np.real(rho.hilbert_schmidt(sx)), 0.5**0.5)
示例#8
0
    def test_density(self):

        rho = DensityOperator(np.eye(6) / 6.0, (2, 3))
        rhosmall = rho.partial_trace([1])

        self.assertEqual(rhosmall.dimension, (2, ))
        self.assertTrue(np.all(np.isclose(rhosmall.matrix, np.eye(2) / 2)))

        with self.assertRaises(ValueError):
            DensityOperator(np.array([[0, 1], [1, 0]]))

        with self.assertRaises(ValueError):
            DensityOperator(np.array([[1, 1], [0, 1]]))

        rho = DensityOperator.from_vectors(0.5, [1, 0, 0])

        self.assertTrue(np.all(rho.matrix == np.ones((2, 2)) * 0.5))

        rho = DensityOperator.from_vectors(0.5, [0, 1, 0], 0.5)

        self.assertTrue(
            np.all(
                np.isclose(rho.matrix, np.array([[0.5, -0.25j], [0.25j,
                                                                 0.5]]))))
示例#9
0
    def evolve(self, rho0, times, operators=[]):
        """Time evolution of a state under this Lindbladian

        Perform an evolution of a state described by a DensityOperator under
        this Lindbladian and return either a sequence of DensityOperators or
        a sequence of expectation values for given SpinOperators.

        Arguments:
            rho0 {DensityOperator} -- Initial state
            times {ndarray} -- Times to compute the evolution for, in microseconds

        Keyword Arguments:
            operators {[SpinOperator]} -- List of SpinOperators to compute the
                                          expectation values of at each step.
                                          If omitted, the states' density 
                                          matrices will be returned instead
                                           (default: {[]})

        Returns:
            [DensityOperator | ndarray] -- DensityOperators or expectation values

        Raises:
            TypeError -- Invalid operators
            ValueError -- Invalid values of times or operators
            RuntimeError -- Hamiltonian is not hermitian
        """

        if not isinstance(rho0, DensityOperator):
            raise TypeError('rho0 must be a valid DensityOperator')

        times = np.array(times)

        if len(times.shape) != 1:
            raise ValueError(
                'times must be an array of values in microseconds')

        if isinstance(operators, SpinOperator):
            operators = [operators]
        if not all([isinstance(o, SpinOperator) for o in operators]):
            raise ValueError('operators must be a SpinOperator or a list'
                             ' of SpinOperator objects')

        dim = rho0.dimension
        if self.dimension != dim * 2:
            raise ValueError('Incompatible rho0 dimension')

        if any([self.dimension != o.dimension * 2 for o in operators]):
            raise ValueError('Incompatible measure operator dimension')

        # Start by building the matrix
        L = self.matrix

        # Diagonalize it
        evals, revecs = np.linalg.eig(L)

        # Vec-ing the density matrix
        rho0 = rho0.matrix.reshape((-1, ))
        rho0 = np.linalg.solve(revecs, rho0)
        # And the operators
        operatorsT = np.array(
            [np.dot(o.matrix.T.reshape((-1, )), revecs) for o in operators])

        rho = np.exp(
            2.0 * np.pi * evals[None, :] * times[:, None]) * rho0[None, :]

        if len(operators) > 0:
            # Expectation values
            result = np.sum(operatorsT[None, :, :] * rho[:, None, :], axis=-1)
        else:
            # Density matrices
            result = [DensityOperator(np.dot(revecs, r), dim) for r in rho]

        return result
示例#10
0
    def evolve(self, rho0, times, operators=[]):
        """Time evolution of a state under this Hamiltonian

        Perform an evolution of a state described by a DensityOperator under
        this Hamiltonian and return either a sequence of DensityOperators or
        a sequence of expectation values for given SpinOperators.

        Arguments:
            rho0 {DensityOperator} -- Initial state
            times {ndarray} -- Times to compute the evolution for, in microseconds

        Keyword Arguments:
            operators {[SpinOperator]} -- List of SpinOperators to compute the
                                          expectation values of at each step.
                                          If omitted, the states' density 
                                          matrices will be returned instead
                                           (default: {[]})

        Returns:
            [DensityOperator | ndarray] -- DensityOperators or expectation values

        Raises:
            TypeError -- Invalid operators
            ValueError -- Invalid values of times or operators
            RuntimeError -- Hamiltonian is not hermitian
        """

        if not isinstance(rho0, DensityOperator):
            raise TypeError('rho0 must be a valid DensityOperator')

        times = np.array(times)

        if len(times.shape) != 1:
            raise ValueError(
                'times must be an array of values in microseconds')

        if isinstance(operators, SpinOperator):
            operators = [operators]
        if not all([isinstance(o, SpinOperator) for o in operators]):
            raise ValueError('operators must be a SpinOperator or a list'
                             ' of SpinOperator objects')

        # Start by building the matrix
        H = self.matrix

        # Sanity check - should never happen
        if not np.all(H == H.T.conj()):
            raise RuntimeError('Hamiltonian is not hermitian')

        # Diagonalize it
        evals, evecs = np.linalg.eigh(H)

        # Turn the density matrix in the right basis
        dim = rho0.dimension
        rho0 = rho0.basis_change(evecs).matrix

        # Same for operators
        operatorsT = np.array(
            [o.basis_change(evecs).matrix.T for o in operators])

        # Matrix of evolution operators
        ll = -2.0j * np.pi * (evals[:, None] - evals[None, :])
        rho = np.exp(ll[None, :, :] * times[:, None, None]) * rho0[None, :, :]

        # Now, return values
        if len(operators) > 0:
            # Actually compute expectation values
            result = np.sum(rho[:, None, :, :] * operatorsT[None, :, :, :],
                            axis=(2, 3))
        else:
            # Just return density matrices
            sceve = evecs.T.conj()
            result = [DensityOperator(r, dim).basis_change(sceve) for r in rho]

        return result