Example #1
0
 def __init__(self, paths: PhotonicPaths, state: QubitWaveFunction = None):
     """
     :param paths: A dictionary containing all photonic paths, where each path contains dictionaries with modes
     :param qubit_state: A State in qubit representation -> A dictionary with integers (BitStrings) as keys
     """
     self._paths = paths
     self._state = state
     if state is None:
         self._state = QubitWaveFunction()
Example #2
0
def test_trace_out_xy(theta):
    a = numpy.sin(theta)
    b = numpy.cos(theta)
    state = QubitWaveFunction.from_array([a,b])

    H1 = QubitHamiltonian.from_string("1.0*X(0)*X(1)*X(100)")
    H2 = QubitHamiltonian.from_string("1.0*X(0)*X(100)")
    factor = a.conjugate()*b + b.conjugate()*a
    assert factor*H2 == H1.trace_out_qubits(qubits=[1,3,5], states=[state]*3)
    factor *= factor
    H1 = QubitHamiltonian.from_string("1.0*X(0)*X(1)*X(5)*X(100)")
    assert factor*H2 == H1.trace_out_qubits(qubits=[1,3,5], states=[state]*3)


    H1 = QubitHamiltonian.from_string("1.0*X(0)*Y(1)*X(100)")
    H2 = QubitHamiltonian.from_string("1.0*X(0)*X(100)")
    factor = -1.0j*(a.conjugate()*b - b.conjugate()*a)
    assert factor*H2 == H1.trace_out_qubits(qubits=[1,3,5], states=[state]*3)
    factor *= factor
    H1 = QubitHamiltonian.from_string("1.0*X(0)*Y(1)*Y(5)*X(100)")
    assert factor*H2 == H1.trace_out_qubits(qubits=[1,3,5], states=[state]*3)

    H1 = QubitHamiltonian.from_string("1.0*X(0)*X(1)*X(100)")
    H2 = QubitHamiltonian.from_string("1.0*X(0)*X(100)")
    factor = a.conjugate()*b + b.conjugate()*a
    assert factor*H2 == H1.trace_out_qubits(qubits=[1,3,5], states=[state]*3)
    factor *= -1.0j*(a.conjugate()*b - b.conjugate()*a)
    H1 = QubitHamiltonian.from_string("1.0*X(0)*X(1)*Y(5)*X(100)")
    assert factor*H2 == H1.trace_out_qubits(qubits=[1,3,5], states=[state]*3)
Example #3
0
def test_notation(silent=True):
    qpm = 2
    S = 2

    # State |-201>_(abc) represented with 2 qubits per mode
    # in Qubits
    # |01 00 00 00 00 | 00 00 01 00 00 | 00 00 00 01 00 >
    test1 = BitString.from_binary(binary='010000000000000100000000000100')
    paths = PhotonicPaths(path_names=['a', 'b', 'c'], S=S, qpm=qpm)

    wfn1 = QubitWaveFunction.from_int(i=test1)
    test1x = PhotonicStateVector(paths=paths, state=wfn1)
    test1y = PhotonicStateVector.from_string(
        paths=paths, string='1.0|10000>_a|00100>_b|00010>_c')
    if not silent:
        print("got      = ", test1x)
        print("expected = ", test1y)
    assert (test1x == test1y)

    # Do a 332 State:
    # Photonic notation: (one photon in each mode and I added -2 and +2 modes)
    # |1-11>_a+|000>_b+|-111>_c
    # Qudit Notation: With modes -2 ... 2
    #   | 0 0 0 1 0 >_a | 0 1 0 0 0 >_b | 0 0 0 1 0 >_c
    # + | 0 0 1 0 0 >_a | 0 0 1 0 0 >_b | 0 0 1 0 0 >_c
    # + | 0 1 0 0 0 >_a | 0 0 0 1 0 >_b | 0 0 0 1 0 >_c
    # Qubit notation: (using 2 qubits for each mode)
    #   | 00 00 00 01 00 >_a | 00 01 00 00 00 >_b | 00 00 00 01 00 >_c
    # + | 00 00 01 00 00 >_a | 00 00 01 00 00 >_b | 00 00 01 00 00 >_c
    # + | 00 01 00 00 00 >_a | 00 00 00 01 00 >_b | 00 00 00 01 00 >_c

    string = '1.0|00010>_a|01000>b|00010>_c+1.0|00100>_a|00100>_b|00100>_c+1.0|01000>_a|00010>_b|00010>_c'
    test_332x = PhotonicStateVector.from_string(paths=paths, string=string)

    q1 = BitString.from_binary('000000010000010000000000000100')
    q2 = BitString.from_binary('000001000000000100000000010000')
    q3 = BitString.from_binary('000100000000000001000000000100')
    wfn = QubitWaveFunction()
    for q in [q1, q2, q3]:
        wfn += QubitWaveFunction.from_int(i=q)
    test_332y = PhotonicStateVector(paths=paths, state=wfn)
    if not silent:
        print("got      = ", test_332y)
        print("expected = ", test_332x)
    assert (test_332x == test_332y)
def test_projectors(qubits):
    real = numpy.random.uniform(0.0, 1.0, 2**qubits)
    imag = numpy.random.uniform(0.0, 1.0, 2**qubits)
    array = real + 1.j * imag
    wfn = QubitWaveFunction.from_array(arr=array)
    P = paulis.Projector(wfn=wfn.normalize())
    assert (P.is_hermitian())
    assert (wfn.apply_qubitoperator(P) == wfn)
    PM = P.to_matrix()
    assert ((PM.dot(PM) == PM).all)
Example #5
0
    def add_basis_state(self, state: Dict[str, Dict[int, int]], coeff=1):
        if isinstance(state, str):
            state = self.string_to_basis_state(string=state)

        qubit_string = BitString.from_int(integer=0, nbits=self.n_qubits)
        for p, v in state.items():
            for m, occ in v.items():
                mode = self.get_mode(p, m)
                occ = BitString.from_int(integer=occ, nbits=mode.n_qubits)
                for i, q in enumerate(mode.qubits):
                    qubit_string[q] = occ[i]
        self._state += QubitWaveFunction.from_int(i=qubit_string, coeff=coeff)
Example #6
0
def test_simple_trace_out():
    H1 = QubitHamiltonian.from_string("1.0*Z(0)*Z(1)")
    H2 = QubitHamiltonian.from_string("1.0*Z(0)")
    assert H2 == H1.trace_out_qubits(qubits=[1], states=None)

    H1 = QubitHamiltonian.from_string("1.0*Z(0)*Z(1)X(100)")
    H2 = QubitHamiltonian.from_string("1.0*Z(1)X(100)")
    assert H2 == H1.trace_out_qubits(qubits=[0], states=None)

    H1 = QubitHamiltonian.from_string("1.0*Z(0)*Z(1)X(100)")
    H2 = QubitHamiltonian.from_string("-1.0*Z(0)X(100)")
    assert H2 == H1.trace_out_qubits(qubits=[1], states=[QubitWaveFunction.from_string("1.0*|1>")])

    H1 = QubitHamiltonian.from_string("1.0*Z(0)*Z(1)X(100)")
    H2 = QubitHamiltonian.from_string("-1.0*Z(1)X(100)")
    assert H2 == H1.trace_out_qubits(qubits=[0], states=[QubitWaveFunction.from_string("1.0*|1>")])

    H1 = QubitHamiltonian.from_string("1.0*X(0)*Z(1)*Z(5)*X(100)Y(50)")
    H2 = QubitHamiltonian.from_string("1.0*X(0)X(100)Y(50)")
    assert H2 == H1.trace_out_qubits(qubits=[1,5], states=[QubitWaveFunction.from_string("1.0*|1>")]*2)

    H1 = QubitHamiltonian.from_string("1.0*X(0)*Z(1)*X(100)Y(50)")
    H2 = QubitHamiltonian.from_string("-1.0*X(0)X(100)Y(50)")
    assert H2 == H1.trace_out_qubits(qubits=[1,5], states=[QubitWaveFunction.from_string("1.0*|1>")]*2)
Example #7
0
    def reference_state(self,
                        reference_orbitals: list = None,
                        n_qubits: int = None) -> BitString:
        """Does a really lazy workaround ... but it works
        :return: Hartree-Fock Reference as binary-number

        Parameters
        ----------
        reference_orbitals: list:
            give list of doubly occupied orbitals
            default is None which leads to automatic list of the
            first n_electron/2 orbitals

        Returns
        -------

        """

        if reference_orbitals is None:
            reference_orbitals = [i for i in range(self.n_electrons // 2)]

        spin_orbitals = sorted([2 * i for i in reference_orbitals] +
                               [2 * i + 1 for i in reference_orbitals])

        if n_qubits is None:
            n_qubits = 2 * self.n_orbitals

        string = ""

        for i in spin_orbitals:
            string += str(i) + "^ "

        fop = openfermion.FermionOperator(string, 1.0)

        op = QubitHamiltonian(qubit_hamiltonian=self.transformation(fop))
        from tequila.wavefunction.qubit_wavefunction import QubitWaveFunction
        wfn = QubitWaveFunction.from_int(0, n_qubits=n_qubits)
        wfn = wfn.apply_qubitoperator(operator=op)
        assert (len(wfn.keys()) == 1)
        keys = [k for k in wfn.keys()]
        return keys[-1]
def test_ketbra_random(n_qubits):
    ket = numpy.random.uniform(0.0, 1.0, 2**n_qubits)
    bra = QubitWaveFunction.from_int(0, n_qubits=n_qubits)
    operator = paulis.KetBra(ket=ket, bra=bra)
    result = operator * bra
    assert result == QubitWaveFunction.from_array(ket)
def test_ketbra():
    ket = QubitWaveFunction.from_string("1.0*|00> + 1.0*|11>").normalize()
    operator = paulis.KetBra(ket=ket, bra="|00>")
    result = operator * QubitWaveFunction.from_int(0, n_qubits=2)
    assert (result == ket)
Example #10
0
class PhotonicStateVector:
    """
    Take the simulator result and keep track of the photonic modes
    """
    @classmethod
    def from_string(cls, paths: PhotonicPaths, string: str):
        """
        Terms are splitted by '+' so complex values like (x+iy)|...> will not work, you need to add Real and imaginary separately
        Or improve this consructor :-)
        :param paths:
        :param string:
        :return:
        """
        string = string.lstrip('+')
        result = cls(paths)
        terms = string.split('+')
        for term in terms:

            tmp = term.split("|")
            if tmp[0] == '':
                coeff = 1.0
            else:
                coeff = complex(tmp[0])

            basis_state = cls.string_to_basis_state(string=term)
            result.add_basis_state(state=basis_state, coeff=coeff)
        return result

    @classmethod
    def string_to_basis_state(cls, string: str) -> Dict[str, Dict[int, int]]:
        """
        :param string: basis state in the form |x>_a|y>_b|z>_c ...
        :return: Dictionary in the form {path: {mode:occ}}
        """
        basis_state = dict()
        tmp = string.split("|")
        for i in range(1, len(tmp)):
            bs = tmp[i].rstrip().lstrip()
            path = bs[-1]
            occs = bs.split(">")[0]
            M = len(occs)
            S = (M - 1) // 2
            modes = dict()
            for j, m in enumerate(range(-S, S + 1)):
                modes[m] = int(occs[j])
            basis_state[path] = modes
        return basis_state

    def add_basis_state(self, state: Dict[str, Dict[int, int]], coeff=1):
        if isinstance(state, str):
            state = self.string_to_basis_state(string=state)

        qubit_string = BitString.from_int(integer=0, nbits=self.n_qubits)
        for p, v in state.items():
            for m, occ in v.items():
                mode = self.get_mode(p, m)
                occ = BitString.from_int(integer=occ, nbits=mode.n_qubits)
                for i, q in enumerate(mode.qubits):
                    qubit_string[q] = occ[i]
        self._state += QubitWaveFunction.from_int(i=qubit_string, coeff=coeff)

    def get_qubit_key(self, state):
        qubit_string = BitString.from_int(integer=0, nbits=self.n_qubits)
        for p, v in state.items():
            for m, occ in v.items():
                mode = self.get_mode(p, m)
                occ = BitString.from_int(integer=occ, nbits=mode.n_qubits)
                for i, q in enumerate(mode.qubits):
                    qubit_string[q] = occ[i]
        return qubit_string

    def get_basis_state(self, string: str):
        """
        :param string: basis state in the form |x>_a|y>_b|z>_c ...
        :return: the coefficient/count_number of that basis state in the full state
        """
        basis_state = self.string_to_basis_state(string=string)
        key = self.get_qubit_key(basis_state)
        if key in self._state.keys():
            return self._state[key]
        else:
            return 0

    @property
    def numbering(self):
        return BitNumbering.MSB

    @property
    def n_modes(self):
        if self._paths is None:
            return 0
        for k, v in self._paths.items():
            return len(v)

    @property
    def n_paths(self):
        return len(self._paths)

    @property
    def n_qubits(self):
        result = 0
        for p in self._paths.values():
            for m in p.values():
                result += m.n_qubits
        return result

    @property
    def state(self):
        return self._state

    @property
    def paths(self):
        return self._paths

    def get_mode(self, path, mode):
        """
        :param path: Name of the path
        :param mode: Name of the mode
        :return: indices of qubits which represent the corresponding mode in the corresponding path
        """
        return self._paths[path][mode]

    def __init__(self, paths: PhotonicPaths, state: QubitWaveFunction = None):
        """
        :param paths: A dictionary containing all photonic paths, where each path contains dictionaries with modes
        :param qubit_state: A State in qubit representation -> A dictionary with integers (BitStrings) as keys
        """
        self._paths = paths
        self._state = state
        if state is None:
            self._state = QubitWaveFunction()

    def normalize(self):
        self._state = self._state.normalize()
        return self

    def __repr__(self):
        threshold = 1.e-3
        result = ""
        nqubits = self.n_qubits
        for i, s in self._state.items():
            i.bits = nqubits
            if isclose(s, 0.0, atol=threshold):
                continue
            result += number_to_string(number=s)
            result += self.interpret_bitstring(i=i)
        return result

    def interpret_bitstring(self, i: BitString) -> str:
        return self._paths.interpret_bitstring(i=i)

    def __eq__(self, other):
        return self._paths == other._paths and self._state == other._state

    def __rmul__(self, other):
        return PhotonicStateVector(paths=self._paths,
                                   state=other * deepcopy(self._state))

    def __iadd__(self, other):
        assert (self.paths == other.paths)
        self._state += other.state
        return self

    def inner(self, other):
        return self._state.inner(other._state)

    def plot(self, title: str = None, label: str = None, filename: str = None):
        from matplotlib import pyplot as plt

        if title is not None:
            plt.title(title)
        plt.ylabel("counts")
        plt.xlabel("state")
        values = []
        names = []
        for k, v in self._state.items():
            values.append(v)
            names.append(self.interpret_bitstring(i=k))
        plt.bar(names, values, label=label)
        if label is not None:
            plt.legend()
        if filename is not None:
            plt.savefig(filename,
                        dpi=None,
                        facecolor='w',
                        edgecolor='w',
                        orientation='landscape',
                        papertype=None,
                        format=None,
                        transparent=False,
                        bbox_inches='tight',
                        pad_inches=0.1,
                        metadata=None)
            with open(filename + "_data", 'a+') as f:
                f.write("names \t\t values\n")
                for i, v in enumerate(values):
                    f.write(str(names[i]) + "\t\t" + str(values[i]) + "\n")
                f.write("end\n")
        else:
            plt.show()