Пример #1
0
def test_get_merged_different_hamiltonian():
    hamiltonian = QubitOperator("Z2", 2)
    gate = te.TimeEvolution(2, hamiltonian)
    hamiltonian2 = QubitOperator("Y2", 2)
    gate2 = te.TimeEvolution(2, hamiltonian2)
    with pytest.raises(NotMergeable):
        gate.get_merged(gate2)
    def _get_Hamiltonian(self, filename):
        'Parse a projectq Hamiltonian operator from file into projectq operator'

        # get raw data
        with open(filename, "r", encoding='utf-8-sig') as file:
            lines = file.readlines()

        # convert to projectq operator
        H = QubitOperator()
        for line in lines:
            line = line.split()
            term = ''
            for i in range(len(line)):
                if i in [0, 1]:
                    pass
                elif line[i] == str(0):
                    pass
                elif line[i] == str(1):
                    term += 'X' + str(i - 2) + ' '
                elif line[i] == str(2):
                    term += 'Y' + str(i - 2) + ' '
                elif line[i] == str(3):
                    term += 'Z' + str(i - 2) + ' '
                else:
                    raise Exception("Error: Incorrect hamiltonian file format")

            if self.verbose: print(term)
            H += float(line[1]) * QubitOperator(term)

        return H
Пример #3
0
def load_operator(file_name=None, data_directory=None):
    """Load FermionOperator or QubitOperator from file.

    Args:
        file_name: The name of the saved file.
        data_directory: Optional data directory to change from default data
                        directory specified in config file.

    Returns:
        operator: The stored FermionOperator or QubitOperator

    Raises:
        TypeError: Operator of invalid type.
    """
    file_path = get_file_path(file_name, data_directory)

    with open(file_path, 'rb') as f:
        data = marshal.load(f)
        operator_type = data[0]
        operator_terms = data[1]

    if operator_type == 'FermionOperator':
        operator = FermionOperator()
        for term in operator_terms:
            operator += FermionOperator(term, operator_terms[term])
    elif operator_type == 'QubitOperator':
        operator = QubitOperator()
        for term in operator_terms:
            operator += QubitOperator(term, operator_terms[term])
    else:
        raise TypeError('Operator of invalid type.')

    return operator
Пример #4
0
def maxcut_cost_ham(graph):
    ham = QubitOperator('', 0.0)
    for i, j in graph.edges():
        operator_i = 'Z' + str(i)
        operator_j = 'Z' + str(j)
        ham += QubitOperator(operator_i + ' ' + operator_j,
                             0.5) + QubitOperator('', -0.5)
    return ham
Пример #5
0
def test_get_merged_not_close_enough():
    hamiltonian = QubitOperator("Z2", 2)
    hamiltonian += QubitOperator("X3", 1)
    gate = te.TimeEvolution(2, hamiltonian)
    hamiltonian2 = QubitOperator("Z2", 4)
    hamiltonian2 += QubitOperator("X3", 2 + 1e-8)
    gate2 = te.TimeEvolution(5, hamiltonian2)
    with pytest.raises(NotMergeable):
        gate.get_merged(gate2)
 def test_is_identity(self):
     self.assertTrue(is_identity(FermionOperator(())))
     self.assertTrue(is_identity(2. * FermionOperator(())))
     self.assertTrue(is_identity(QubitOperator(())))
     self.assertTrue(is_identity(QubitOperator((), 2.)))
     self.assertFalse(is_identity(FermionOperator('1^')))
     self.assertFalse(is_identity(QubitOperator('X1')))
     self.assertFalse(is_identity(FermionOperator()))
     self.assertFalse(is_identity(QubitOperator()))
Пример #7
0
def jordan_wigner_dual_basis_hamiltonian(grid, geometry=None, spinless=False,
                                         include_constant=False):
    """Return the dual basis Hamiltonian as QubitOperator.

    Args:
        grid (Grid): The discretization to use.
        geometry: A list of tuples giving the coordinates of each atom.
            example is [('H', (0, 0, 0)), ('H', (0, 0, 0.7414))].
            Distances in atomic units. Use atomic symbols to specify atoms.
        spinless (bool): Whether to use the spinless model or not.
        include_constant (bool): Whether to include the Madelung constant.

    Returns:
        hamiltonian (QubitOperator)
    """
    jellium_op = jordan_wigner_dual_basis_jellium(
        grid, spinless, include_constant)

    if geometry is None:
        return jellium_op

    for item in geometry:
        if len(item[1]) != grid.dimensions:
            raise ValueError("Invalid geometry coordinate.")
        if item[0] not in periodic_hash_table:
            raise ValueError("Invalid nuclear element.")

    n_orbitals = grid.num_points()
    volume = grid.volume_scale()
    if spinless:
        n_qubits = n_orbitals
    else:
        n_qubits = 2 * n_orbitals
    prefactor = -2 * numpy.pi / volume
    external_potential = QubitOperator()

    for k_indices in grid.all_points_indices():
        momenta = momentum_vector(k_indices, grid)
        momenta_squared = momenta.dot(momenta)
        if momenta_squared < EQ_TOLERANCE:
            continue

        for p in range(n_qubits):
            index_p = grid_indices(p, grid, spinless)
            coordinate_p = position_vector(index_p, grid)

            for nuclear_term in geometry:
                coordinate_j = numpy.array(nuclear_term[1], float)

                exp_index = 1.0j * momenta.dot(coordinate_j - coordinate_p)
                coefficient = (prefactor / momenta_squared *
                               periodic_hash_table[nuclear_term[0]] *
                               numpy.exp(exp_index))
                external_potential += (QubitOperator((), coefficient) -
                                       QubitOperator(((p, 'Z'),), coefficient))

    return jellium_op + external_potential
Пример #8
0
def test_get_merged_one_term():
    hamiltonian = QubitOperator("Z2", 2)
    gate = te.TimeEvolution(2, hamiltonian)
    hamiltonian2 = QubitOperator("Z2", 4)
    gate2 = te.TimeEvolution(5, hamiltonian2)
    merged = gate.get_merged(gate2)
    # This is not a requirement, the hamiltonian could also be the other
    # if we change implementation
    assert merged.hamiltonian.isclose(hamiltonian)
    assert merged.time == pytest.approx(12)
Пример #9
0
    def test_sparse_matrix_combo(self):
        qop = (QubitOperator(((0, 'Y'), (1, 'X')), -0.1j) + QubitOperator(
            ((0, 'X'), (1, 'Z')), 3. + 2.j))
        sparse_operator = get_sparse_operator(qop)

        self.assertEqual(
            list(sparse_operator.data),
            [3 + 2j, 0.1, 0.1, -3 - 2j, 3 + 2j, -0.1, -0.1, -3 - 2j])
        self.assertEqual(list(sparse_operator.indices),
                         [2, 3, 2, 3, 0, 1, 0, 1])
Пример #10
0
    def test_z(self):
        pauli_z = QubitOperator(((2, 'Z'), ))
        transmed_z = reverse_jordan_wigner(pauli_z)

        expected = (FermionOperator(()) + FermionOperator(
            ((2, 1), (2, 0)), -2.))
        self.assertTrue(transmed_z.isclose(expected))

        retransmed_z = jordan_wigner(transmed_z)
        self.assertTrue(pauli_z.isclose(retransmed_z))
Пример #11
0
 def test_error_operator_xyz(self):
     terms = [QubitOperator('X1'), QubitOperator('Y1'), QubitOperator('Z1')]
     expected = numpy.array([[-2./3, 1./3 + 1.j/6, 0., 0.],
                             [1./3 - 1.j/6, 2./3, 0., 0.],
                             [0., 0., -2./3, 1./3 + 1.j/6],
                             [0., 0., 1./3 - 1.j/6, 2./3]])
     sparse_op = get_sparse_operator(error_operator(terms))
     matrix = sparse_op.todense()
     self.assertTrue(numpy.allclose(matrix, expected),
                     ("Got " + str(matrix)))
Пример #12
0
def single_hamiltonian(clause: list):
    # separate variables number and its negation signs
    var0, var1, var2 = np.abs(clause) - 1

    # explanation for -1:
    # qubit numeration starts with 0, but clause literals
    # starts with 1 in order to not loose negation of 0 literal
    # so here 1 is subtracted to not keep 0-s qubit unused

    sign0, sign1, sign2 = [int(i) for i in np.sign(clause)]

    # create expanded Hamiltonian from the form 0.125*(1+z_i)(1+z_j)(1+z_k)
    ham0 = QubitOperator(' ')
    ham1 = QubitOperator(f'Z{var0}', sign0)
    ham2 = QubitOperator(f'Z{var1}', sign1)
    ham3 = QubitOperator(f'Z{var2}', sign2)
    ham4 = QubitOperator(f'Z{var0} Z{var1}', sign0 * sign1)
    ham5 = QubitOperator(f'Z{var0} Z{var2}', sign0 * sign2)
    ham6 = QubitOperator(f'Z{var1} Z{var2}', sign1 * sign2)
    ham7 = QubitOperator(f'Z{var0} Z{var1} Z{var2}', sign0 * sign1 * sign2)

    hams = [ham0, ham1, ham2, ham3, ham4, ham5, ham6, ham7]

    ham = QubitOperator()

    for h in hams:
        ham += 1 / 8 * h

    return ham
Пример #13
0
def test_simulator_expectation_exception(sim):
    eng = MainEngine(sim, [])
    qureg = eng.allocate_qureg(3)
    op = QubitOperator('Z2')
    sim.get_expectation_value(op, qureg)
    op2 = QubitOperator('Z3')
    with pytest.raises(Exception):
        sim.get_expectation_value(op2, qureg)
    op3 = QubitOperator('Z1') + QubitOperator('X1 Y3')
    with pytest.raises(Exception):
        sim.get_expectation_value(op3, qureg)
Пример #14
0
def test_simulator_applyqubitoperator_exception(sim):
    eng = MainEngine(sim, [])
    qureg = eng.allocate_qureg(3)
    op = QubitOperator('Z2')
    sim.apply_qubit_operator(op, qureg)
    op2 = QubitOperator('Z3')
    with pytest.raises(Exception):
        sim.apply_qubit_operator(op2, qureg)
    op3 = QubitOperator('Z1') + QubitOperator('X1 Y3')
    with pytest.raises(Exception):
        sim.apply_qubit_operator(op3, qureg)
Пример #15
0
    def test_sparse_matrix_linearity(self):
        identity = QubitOperator(())
        zzzz = QubitOperator(tuple((i, 'Z') for i in range(4)), 1.0)

        sparse1 = get_sparse_operator(identity + zzzz)
        sparse2 = get_sparse_operator(identity, 4) + get_sparse_operator(zzzz)

        self.assertEqual(list(sparse1.data), [2] * 8)
        self.assertEqual(list(sparse1.indices), [0, 3, 5, 6, 9, 10, 12, 15])
        self.assertEqual(list(sparse2.data), [2] * 8)
        self.assertEqual(list(sparse2.indices), [0, 3, 5, 6, 9, 10, 12, 15])
Пример #16
0
    def test_transm_lower0(self):
        lowering = jordan_wigner(FermionOperator(((0, 0), )))

        correct_operators_x = ((0, 'X'), )
        correct_operators_y = ((0, 'Y'), )
        qtermx = QubitOperator(correct_operators_x, 0.5)
        qtermy = QubitOperator(correct_operators_y, 0.5j)

        self.assertEqual(lowering.terms[correct_operators_x], 0.5)
        self.assertEqual(lowering.terms[correct_operators_y], 0.5j)
        self.assertTrue(lowering.isclose(qtermx + qtermy))
Пример #17
0
    def test_transm_raise1(self):
        raising = jordan_wigner(FermionOperator(((1, 1), )))

        correct_operators_x = ((0, 'Z'), (1, 'X'))
        correct_operators_y = ((0, 'Z'), (1, 'Y'))
        qtermx = QubitOperator(correct_operators_x, 0.5)
        qtermy = QubitOperator(correct_operators_y, -0.5j)

        self.assertEqual(raising.terms[correct_operators_x], 0.5)
        self.assertEqual(raising.terms[correct_operators_y], -0.5j)
        self.assertTrue(raising.isclose(qtermx + qtermy))
Пример #18
0
def test_or_gate_not_mutated():
    saving_backend = DummyEngine(save_commands=True)
    eng = MainEngine(backend=saving_backend, engine_list=[])
    qureg = eng.allocate_qureg(4)
    hamiltonian = QubitOperator("X0 Z3", 2)
    hamiltonian += QubitOperator("Y1", 0.5)
    correct_h = copy.deepcopy(hamiltonian)
    gate = te.TimeEvolution(2.1, hamiltonian)
    gate | qureg
    eng.flush()
    assert gate.hamiltonian.isclose(correct_h)
    assert gate.time == pytest.approx(2.1)
Пример #19
0
def test_qubitop2singlequbit():
    num_qubits = 4
    random_initial_state = [
        0.2 + 0.1 * x * cmath.exp(0.1j + 0.2j * x)
        for x in range(2**(num_qubits + 1))
    ]
    rule_set = DecompositionRuleSet(modules=[qubitop2onequbit])
    test_eng = MainEngine(
        backend=Simulator(),
        engine_list=[AutoReplacer(rule_set),
                     InstructionFilter(_decomp_gates)],
    )
    test_qureg = test_eng.allocate_qureg(num_qubits)
    test_ctrl_qb = test_eng.allocate_qubit()
    test_eng.flush()
    test_eng.backend.set_wavefunction(random_initial_state,
                                      test_qureg + test_ctrl_qb)
    correct_eng = MainEngine()
    correct_qureg = correct_eng.allocate_qureg(num_qubits)
    correct_ctrl_qb = correct_eng.allocate_qubit()
    correct_eng.flush()
    correct_eng.backend.set_wavefunction(random_initial_state,
                                         correct_qureg + correct_ctrl_qb)

    qubit_op_0 = QubitOperator("X0 Y1 Z3", -1.0j)
    qubit_op_1 = QubitOperator("Z0 Y1 X3", cmath.exp(0.6j))

    qubit_op_0 | test_qureg
    with Control(test_eng, test_ctrl_qb):
        qubit_op_1 | test_qureg
    test_eng.flush()

    correct_eng.backend.apply_qubit_operator(qubit_op_0, correct_qureg)
    with Control(correct_eng, correct_ctrl_qb):
        Ph(0.6) | correct_qureg[0]
        Z | correct_qureg[0]
        Y | correct_qureg[1]
        X | correct_qureg[3]
    correct_eng.flush()

    for fstate in range(2**(num_qubits + 1)):
        binary_state = format(fstate, '0' + str(num_qubits + 1) + 'b')
        test = test_eng.backend.get_amplitude(binary_state,
                                              test_qureg + test_ctrl_qb)
        correct = correct_eng.backend.get_amplitude(
            binary_state, correct_qureg + correct_ctrl_qb)
        assert correct == pytest.approx(test, rel=1e-10, abs=1e-10)

    All(Measure) | correct_qureg + correct_ctrl_qb
    All(Measure) | test_qureg + test_ctrl_qb
    correct_eng.flush()
    test_eng.flush()
Пример #20
0
    def test_yy(self):
        yy = QubitOperator(((2, 'Y'), (3, 'Y')), 2.)
        transmed_yy = reverse_jordan_wigner(yy)
        retransmed_yy = jordan_wigner(transmed_yy)

        expected1 = -(FermionOperator(((2, 1), ), 2.) + FermionOperator(
            ((2, 0), ), 2.))
        expected2 = (FermionOperator(((3, 1), )) - FermionOperator(((3, 0), )))
        expected = expected1 * expected2

        self.assertTrue(yy.isclose(retransmed_yy))
        self.assertTrue(
            normal_ordered(transmed_yy).isclose(normal_ordered(expected)))
Пример #21
0
def H_ansatz(N, B):
    '''
    implement the mixer Hamiltonian given in the probelm
    parameters
        N: (int) number of allocated qubits
        B: (float) coupling coefficients
    return
        H:(QubitOperator) target hamiltonian
    '''
    H = 0 * QubitOperator("")
    for i in range(N):
        H += B * QubitOperator("X" + str(i))
    return (-1) * H
Пример #22
0
    def test_xy(self):
        xy = QubitOperator(((4, 'X'), (5, 'Y')), -2.j)
        transmed_xy = reverse_jordan_wigner(xy)
        retransmed_xy = jordan_wigner(transmed_xy)

        expected1 = -2j * (FermionOperator(((4, 1), ), 1j) - FermionOperator(
            ((4, 0), ), 1j))
        expected2 = (FermionOperator(((5, 1), )) - FermionOperator(((5, 0), )))
        expected = expected1 * expected2

        self.assertTrue(xy.isclose(retransmed_xy))
        self.assertTrue(
            normal_ordered(transmed_xy).isclose(normal_ordered(expected)))
def test_recognize():
    saving_backend = DummyEngine(save_commands=True)
    eng = MainEngine(backend=saving_backend, engine_list=[])
    ctrl_qureg = eng.allocate_qureg(2)
    qureg = eng.allocate_qureg(2)
    with Control(eng, ctrl_qureg):
        QubitOperator("X0 Y1") | qureg
    with Control(eng, ctrl_qureg[0]):
        QubitOperator("X0 Y1") | qureg
    eng.flush()
    cmd0 = saving_backend.received_commands[4]
    cmd1 = saving_backend.received_commands[5]
    assert not qubitop2onequbit._recognize_qubitop(cmd0)
    assert qubitop2onequbit._recognize_qubitop(cmd1)
Пример #24
0
    def test_yx(self):
        yx = QubitOperator(((0, 'Y'), (1, 'X')), -0.5)
        transmed_yx = reverse_jordan_wigner(yx)
        retransmed_yx = jordan_wigner(transmed_yx)

        expected1 = 1j * (FermionOperator(((0, 1), )) + FermionOperator(
            ((0, 0), )))
        expected2 = -0.5 * (FermionOperator(((1, 1), )) + FermionOperator(
            ((1, 0), )))
        expected = expected1 * expected2

        self.assertTrue(yx.isclose(retransmed_yx))
        self.assertTrue(
            normal_ordered(transmed_yx).isclose(normal_ordered(expected)))
Пример #25
0
    def test_xx(self):
        xx = QubitOperator(((3, 'X'), (4, 'X')), 2.)
        transmed_xx = reverse_jordan_wigner(xx)
        retransmed_xx = jordan_wigner(transmed_xx)

        expected1 = (FermionOperator(((3, 1), ), 2.) - FermionOperator(
            ((3, 0), ), 2.))
        expected2 = (FermionOperator(((4, 1), ), 1.) + FermionOperator(
            ((4, 0), ), 1.))
        expected = expected1 * expected2

        self.assertTrue(xx.isclose(retransmed_xx))
        self.assertTrue(
            normal_ordered(transmed_xx).isclose(normal_ordered(expected)))
Пример #26
0
def _recognize_time_evolution_commuting_terms(cmd):
    """Recognize all TimeEvolution gates with >1 terms but which all commute."""
    hamiltonian = cmd.gate.hamiltonian
    if len(hamiltonian.terms) == 1:
        return False
    id_op = QubitOperator((), 0.0)
    for term in hamiltonian.terms:
        test_op = QubitOperator(term, hamiltonian.terms[term])
        for other in hamiltonian.terms:
            other_op = QubitOperator(other, hamiltonian.terms[other])
            commutator = test_op * other_op - other_op * test_op
            if not commutator.isclose(id_op, rel_tol=1e-9, abs_tol=1e-9):
                return False
    return True
def test_decompose_commuting_terms():
    saving_backend = DummyEngine(save_commands=True)

    def my_filter(self, cmd):
        if len(cmd.qubits[0]) <= 2 or isinstance(cmd.gate,
                                                 ClassicalInstructionGate):
            return True
        return False

    rules = DecompositionRuleSet([te.rule_commuting_terms])
    replacer = AutoReplacer(rules)
    filter_eng = InstructionFilter(my_filter)
    eng = MainEngine(backend=saving_backend,
                     engine_list=[replacer, filter_eng])
    qureg = eng.allocate_qureg(5)
    with Control(eng, qureg[3]):
        op1 = QubitOperator("X1 Y2", 0.7)
        op2 = QubitOperator("Y2 X4", -0.8)
        op3 = QubitOperator((), 0.6)
        TimeEvolution(1.5, op1 + op2 + op3) | qureg

    cmd1 = saving_backend.received_commands[5]
    cmd2 = saving_backend.received_commands[6]
    cmd3 = saving_backend.received_commands[7]

    found = [False, False, False]
    scaled_op1 = QubitOperator("X0 Y1", 0.7)
    scaled_op2 = QubitOperator("Y0 X1", -0.8)
    for cmd in [cmd1, cmd2, cmd3]:
        if (cmd.gate == Ph(-1.5 * 0.6) and cmd.qubits[0][0].id == qureg[1].id
                and cmd.control_qubits[0].id
                == qureg[3].id  # 1st qubit of [1,2,4]
            ):
            found[0] = True
        elif (isinstance(cmd.gate, TimeEvolution)
              and cmd.gate.hamiltonian.isclose(scaled_op1)
              and cmd.gate.time == pytest.approx(1.5)
              and cmd.qubits[0][0].id == qureg[1].id
              and cmd.qubits[0][1].id == qureg[2].id
              and cmd.control_qubits[0].id == qureg[3].id):
            found[1] = True
        elif (isinstance(cmd.gate, TimeEvolution)
              and cmd.gate.hamiltonian.isclose(scaled_op2)
              and cmd.gate.time == pytest.approx(1.5)
              and cmd.qubits[0][0].id == qureg[2].id
              and cmd.qubits[0][1].id == qureg[4].id
              and cmd.control_qubits[0].id == qureg[3].id):
            found[2] = True
    assert all(found)
Пример #28
0
def test_or_not_enough_qubits():
    saving_backend = DummyEngine(save_commands=True)
    eng = MainEngine(backend=saving_backend, engine_list=[])
    qureg = eng.allocate_qureg(2)
    hamiltonian = QubitOperator("Z0 X3", 2)
    with pytest.raises(ValueError):
        te.TimeEvolution(2.1, hamiltonian) | qureg
Пример #29
0
def test_or_two_qubits_error():
    saving_backend = DummyEngine(save_commands=True)
    eng = MainEngine(backend=saving_backend, engine_list=[])
    qureg = eng.allocate_qureg(2)
    hamiltonian = QubitOperator("Z0", 2)
    with pytest.raises(TypeError):
        te.TimeEvolution(2.1, hamiltonian) | (qureg[0], qureg[1])
Пример #30
0
def error_operator(terms, series_order=2):
    """Determine the difference between the exact generator of unitary
    evolution and the approximate generator given by Trotter-Suzuki
    to the given order.

    Args:
        terms: a list of QubitTerms in the Hamiltonian to be simulated.
        series_order: the order at which to compute the BCH expansion.
            Only the second order formula is currently implemented
            (corresponding to Equation 9 of the paper).

    Returns:
        The difference between the true and effective generators of time
            evolution for a single Trotter step.

    Notes: follows Equation 9 of Poulin et al.'s work in "The Trotter Step
        Size Required for Accurate Quantum Simulation of Quantum Chemistry".
    """
    if series_order != 2:
        raise NotImplementedError
    error_operator = QubitOperator()
    for beta in range(len(terms)):
        for alpha in range(beta + 1):
            for alpha_prime in range(beta):
                if not trivially_double_commutes(terms[alpha], terms[beta],
                                                 terms[alpha_prime]):
                    double_com = commutator(terms[alpha],
                                            commutator(terms[beta],
                                                       terms[alpha_prime]))
                    error_operator += double_com
                    if alpha == beta:
                        error_operator -= double_com / 2.0

    return error_operator / 12.0