Examples

BCS Mean Field

# coding=utf-8
r"""Quantum circuit to prepare the BCS ground states for
superconductors/superfluids. Such states can be prepared by
applying pairwise Bogoliubov transformations on basis states
with opposite spins and momenta, followed by the fermionic Fourier
transformations. In this simple example, we consider a 1D 4-site Hubbard model.
The fermionic quantum state is mapped that of a qubit ladder (two coupled
chains) using the Jordan-Wigner transformation, the upper (lower) chain
represent spin-up (down) basis states.

The Bogoliubov transformation can be readily implemented by
applying quantum gates on vertical pairs of qubits, which takes the form
|BCS⟩ = \prod_k (u_k + v_k c^\dag_{k,↑} c^\dag_{−k,↓}|vac⟩ where |vac⟩ is
the vacuum state and u_k^2 = (1+ ξ_k/(ξ_k^2+Δ_k^2)^{1/2})/2 and v_k^2
= (1 - ξ_k/(ξ_k^2+Δ_k^2)^{1/2})/2.

We use the fast fermionic Fourier transformation (FFFT) to implement the basis
transformation from the momentum picture to the position picture.
This is an attempt to reduce the number of the gates that have to be
calibrated in experiments (compared to the Givens rotation approach); one
only needs to calibrate a couple of two-qubit gates using FFFT, i.e.,
the iSWAP gate and its square root √iSWAP. We use the single-qubit S gate to
convert the iSWAP gate and the √iSWAP gate to fermionic gates.

=== REFERENCE ===
F. Verstraete, J. I. Cirac, and J. I. Latorre, “Quantum circuits for strongly
correlated quantum systems,” Physical Review A 79, 032316 (2009).

Zhang Jiang, Kevin J. Sung, Kostyantyn Kechedzhi, Vadim N. Smelyanskiy,
and Sergio Boixo Phys. Rev. Applied 9, 044036 (2018).

=== EXAMPLE OUTPUT ===
Quantum circuits to prepare the BCS mean field state.
Number of sites =  4
Number of fermions =  4
Tunneling strength =  1.0
On-site interaction strength =  -4.0
Superconducting gap =  1.1261371093950703

Circuit for the Bogoliubov transformation:
(0, 0)  (0, 1)  (0, 2)  (0, 3)  (1, 0)      (1, 1)      (1, 2)     (1, 3)
│       │       │       │       │           │           │          │
W(.25)  │       │       │       │           │           │          │
│       │       │       │       │           │           │          │
iSwap───┼───────┼───────┼───────iSwap^-1.83 │           │          │
│       │       │       │       │           │           │          │
W(.625) │       │       │       │           │           │          │
│       │       │       │       │           │           │          │
│       W(.25)  │       │       │           │           │          │
│       │       │       │       │           │           │          │
│       iSwap───┼───────┼───────┼───────────iSwap^-1.67 │          │
│       │       │       │       │           │           │          │
│       W(.625) │       │       │           │           │          │
│       │       │       │       │           │           │          │
│       │       W(.25)  │       │           │           │          │
│       │       │       │       │           │           │          │
│       │       iSwap───┼───────┼───────────┼───────────iSwap^-1.0 │
│       │       │       │       │           │           │          │
│       │       W(.625) │       │           │           │          │
│       │       │       │       │           │           │          │
│       │       │       W(.25)  │           │           │          │
│       │       │       │       │           │           │          │
│       │       │       iSwap───┼───────────┼───────────┼──────────iSwap^-1.67
│       │       │       │       │           │           │          │
│       │       │       W(.625) │           │           │          │
│       │       │       │       │           │           │          │


Circuit for the inverse fermionic Fourier transformation on the spin-up states:
(0, 0) (0, 1)    (0, 2) (0, 3)
│      │         │      │
S^-1   iSwap─────iSwap  │
│      │         │      │
│      S^-1      Z      │
│      │         │      │
iSwap──iSwap^0.5 │      │
│      │         │      │
Z      │         iSwap──iSwap^0.5
│      │         │      │
│      │         S^-1   │
│      │         │      │
│      iSwap─────iSwap  │
│      │         │      │
│      S^-1      S^-1   │
│      │         │      │
iSwap──iSwap^0.5 │      │
│      │         │      │
S^-1   │         │      │
│      │         │      │
│      │         iSwap──iSwap^0.5
│      │         │      │
│      │         S^-1   │
│      │         │      │
│      iSwap─────iSwap  │
│      │         │      │
│      S^-1      S^-1   │
│      │         │      │


Circuit for the inverse fermionic Fourier transformation on the spin-down
states:
(1, 0) (1, 1)    (1, 2) (1, 3)
│      │         │      │
S^-1   iSwap─────iSwap  │
│      │         │      │
│      S^-1      Z      │
│      │         │      │
iSwap──iSwap^0.5 │      │
│      │         │      │
Z      │         iSwap──iSwap^0.5
│      │         │      │
│      │         S^-1   │
│      │         │      │
│      iSwap─────iSwap  │
│      │         │      │
│      S^-1      S      │
│      │         │      │
iSwap──iSwap^0.5 │      │
│      │         │      │
S^-1   │         │      │
│      │         │      │
│      │         iSwap──iSwap^0.5
│      │         │      │
│      │         S^-1   │
│      │         │      │
│      iSwap─────iSwap  │
│      │         │      │
│      S^-1      S^-1   │
│      │         │      │


"""

import numpy as np
import scipy.optimize
import cirq


def main():

    # Number of sites in the Fermi-Hubbard model (2*n_site spin orbitals)
    n_site = 4
    # Number of fermions
    n_fermi = 4
    # Hopping strength between neighboring sites
    t = 1.
    # On-site interaction strength. It has to be negative (attractive) for the
    # BCS theory to work.
    u = -4.
    # Calculate the superconducting gap and the angles for BCS
    delta, bog_theta = bcs_parameters(n_site, n_fermi, u, t)
    # Initializing the qubits on a ladder
    upper_qubits = [cirq.GridQubit(0, i) for i in range(n_fermi)]
    lower_qubits = [cirq.GridQubit(1, i) for i in range(n_fermi)]

    print('Quantum circuits to prepare the BCS meanfield state.')
    print('Number of sites = ', n_site)
    print('Number of fermions = ', n_fermi)
    print('Tunneling strength = ', t)
    print('On-site interaction strength = ', u)
    print('Superconducting gap = ', delta, '\n')

    bog_circuit = cirq.Circuit.from_ops(
        bogoliubov_trans(upper_qubits[i], lower_qubits[i], bog_theta[i])
        for i in range(n_site))
    bog_circuit = cirq.google.optimized_for_xmon(bog_circuit)
    print('Circuit for the Bogoliubov transformation:')
    print(bog_circuit.to_text_diagram(transpose=True), '\n')

    # The inverse fermionic Fourier transformation on the spin-up states
    print(('Circuit for the inverse fermionic Fourier transformation on the '
           'spin-up states:'))
    fourier_circuit_spin_up = cirq.Circuit.from_ops(
        fermi_fourier_trans_inverse_4(upper_qubits),
        strategy=cirq.InsertStrategy.EARLIEST)
    fourier_circuit_spin_up = cirq.google.optimized_for_xmon(
        fourier_circuit_spin_up)
    print(fourier_circuit_spin_up.to_text_diagram(transpose=True), '\n')

    # The inverse fermionic Fourier transformation on the spin-down states
    print(('Circuit for the inverse fermionic Fourier transformation on the '
           'spin-down states:'))
    fourier_circuit_spin_down = cirq.Circuit.from_ops(
        fermi_fourier_trans_inverse_conjugate_4(lower_qubits),
        strategy=cirq.InsertStrategy.EARLIEST)
    fourier_circuit_spin_down = cirq.google.optimized_for_xmon(
        fourier_circuit_spin_down)
    print(fourier_circuit_spin_down.to_text_diagram(transpose=True))


def fswap(p, q):
    """Decompose the Fermionic SWAP gate into two single-qubit gates and
    one iSWAP gate.

    Args:
        p: the id of the first qubit
        q: the id of the second qubit
    """

    yield cirq.ISWAP(q, p), cirq.Z(p) ** 1.5
    yield cirq.Z(q) ** 1.5


def bogoliubov_trans(p, q, theta):
    r"""The 2-mode Bogoliubov transformation is mapped to two-qubit operations.
     We use the identity X S^\dag X S X = Y X S^\dag Y S X = X to transform
     the Hamiltonian XY+YX to XX+YY type. The time evolution of the XX + YY
     Hamiltonian can be expressed as a power of the iSWAP gate.

    Args:
        p: the first qubit
        q: the second qubit
        theta: The rotational angle that specifies the Bogoliubov
        transformation, which is a function of the kinetic energy and
        the superconducting gap.
    """

    # The iSWAP gate corresponds to evolve under the Hamiltonian XX+YY for
    # time -pi/4.
    expo = -4 * theta / np.pi

    yield cirq.X(p)
    yield cirq.S(p)
    yield cirq.ISWAP(p, q)**expo
    yield cirq.S(p) ** 1.5
    yield cirq.X(p)


def fermi_fourier_trans_2(p, q):
    """The 2-mode fermionic Fourier transformation can be implemented
    straightforwardly by the √iSWAP gate. The √iSWAP gate can be readily
    implemented with the gmon qubits using the XX + YY Hamiltonian. The matrix
    representation of the 2-qubit fermionic Fourier transformation is:
    [1  0      0      0],
    [0  1/√2   1/√2   0],
    [0  1/√2  -1/√2   0],
    [0  0      0     -1]
    The square root of the iSWAP gate is:
    [1, 0, 0, 0],
    [0, 0.5 + 0.5j, 0.5 - 0.5j, 0],
    [0, 0.5 - 0.5j, 0.5 + 0.5j, 0],
    [0, 0, 0, 1]

    Args:
        p: the first qubit
        q: the second qubit
    """

    yield cirq.Z(p)**1.5
    yield cirq.ISWAP(q, p)**0.5
    yield cirq.Z(p)**1.5


def fermi_fourier_trans_inverse_4(qubits):
    """The reverse fermionic Fourier transformation implemented on 4 qubits
    on a line, which maps the momentum picture to the position picture.
    Using the fast Fourier transformation algorithm, the circuit can be
    decomposed into 2-mode fermionic Fourier transformation, the fermionic
    SWAP gates, and single-qubit rotations.

    Args:
        qubits: list of four qubits
    """

    yield fswap(qubits[1], qubits[2]),
    yield fermi_fourier_trans_2(qubits[0], qubits[1])
    yield fermi_fourier_trans_2(qubits[2], qubits[3])
    yield fswap(qubits[1], qubits[2])
    yield fermi_fourier_trans_2(qubits[0], qubits[1])
    yield cirq.S(qubits[2])
    yield fermi_fourier_trans_2(qubits[2], qubits[3])
    yield fswap(qubits[1], qubits[2])


def fermi_fourier_trans_inverse_conjugate_4(qubits):
    """We will need to map the momentum states in the reversed order for
    spin-down states to the position picture. This transformation can be
    simply implemented the complex conjugate of the former one. We only
    need to change the S gate to S* = S ** 3.

    Args:
        qubits: list of four qubits
    """

    yield fswap(qubits[1], qubits[2]),
    yield fermi_fourier_trans_2(qubits[0], qubits[1])
    yield fermi_fourier_trans_2(qubits[2], qubits[3])
    yield fswap(qubits[1], qubits[2])
    yield fermi_fourier_trans_2(qubits[0], qubits[1])
    yield cirq.S(qubits[2]) ** 3
    yield fermi_fourier_trans_2(qubits[2], qubits[3])
    yield fswap(qubits[1], qubits[2])


def bcs_parameters(n_site, n_fermi, u, t) :
    """Generate the parameters for the BCS ground state, i.e., the
    superconducting gap and the rotational angles in the Bogoliubov
    transformation.

     Args:
        n_site: the number of sites in the Hubbard model
        n_fermi: the number of fermions
        u: the interaction strength
        t: the tunneling strength

    Returns:
        float delta, List[float] bog_theta
    """

    # The wave numbers satisfy the periodic boundary condition.
    wave_num = np.linspace(0, 1, n_site, endpoint=False)
    # The hopping energy as a function of wave numbers
    hop_erg = -2 * t * np.cos(2 * np.pi * wave_num)
    # Finding the Fermi energy
    fermi_erg = hop_erg[n_fermi // 2]
    # Set the Fermi energy to zero
    hop_erg = hop_erg - fermi_erg

    def _bcs_gap(x):
        """Defines the self-consistent equation for the BCS wavefunction.

        Args:
            x: the superconducting gap
        """

        s = 0.
        for i in range(n_site):
            s += 1. / np.sqrt(hop_erg[i] ** 2 + x ** 2)
        return 1 + s * u / (2 * n_site)

    # Superconducting gap
    delta = scipy.optimize.bisect(_bcs_gap, 0.01, 10000. * abs(u))
    # The amplitude of the double excitation state
    bcs_v = np.sqrt(0.5 * (1 - hop_erg / np.sqrt(hop_erg ** 2 + delta ** 2)))
    # The rotational angle in the Bogoliubov transformation.
    bog_theta = np.arcsin(bcs_v)

    return delta, bog_theta


if __name__ == "__main__":
    main()

Bell Inequality

"""Creates and simulates a circuit equivalent to a Bell inequality test.

=== EXAMPLE OUTPUT ===

Circuit:
(0, 0): ───H───@───X^-0.25───────X^0.5───M───
               │                 │
(0, 1): ───────┼─────────────H───@───────M───

(1, 0): ───────X─────────────────X^0.5───M───

(1, 1): ─────────────────────H───@───────M───

Simulating 75 repetitions...

Results
a: _1__11111___111111_1__1_11_11__111________1___1_111_111_____1111_1_111__1_1
b: _1__1__11_1_1_1__1_1_1_1_11____111_111__11_____1_1__1111_1_11___111_11_1__1
x: ____11______11111__1_1111111____1_111__1111___1111_1__11_1__11_11_11_1__11_
y: 11_111_____1_1_111__11111_111_1____1____11_____11___11_1_1___1_111111_1_1_1
(a XOR b) == (x AND y):
   1111_1_111_11111111111111111_1111111__1111_111_111_11111111_11_11111111_111
Win rate: 84.0%
"""

import numpy as np

import cirq


def main():
    # Create circuit.
    circuit = make_bell_test_circuit()
    print('Circuit:')
    print(circuit)

    # Run simulations.
    print()
    repetitions = 75
    print('Simulating {} repetitions...'.format(repetitions))
    result = cirq.Simulator().run(program=circuit, repetitions=repetitions)

    # Collect results.
    a = np.array(result.measurements['a'][:, 0])
    b = np.array(result.measurements['b'][:, 0])
    x = np.array(result.measurements['x'][:, 0])
    y = np.array(result.measurements['y'][:, 0])
    outcomes = a ^ b == x & y
    win_percent = len([e for e in outcomes if e]) * 100 / repetitions

    # Print data.
    print()
    print('Results')
    print('a:', bitstring(a))
    print('b:', bitstring(b))
    print('x:', bitstring(x))
    print('y:', bitstring(y))
    print('(a XOR b) == (x AND y):\n  ', bitstring(outcomes))
    print('Win rate: {}%'.format(win_percent))


def make_bell_test_circuit():
    alice = cirq.GridQubit(0, 0)
    bob = cirq.GridQubit(1, 0)
    alice_referee = cirq.GridQubit(0, 1)
    bob_referee = cirq.GridQubit(1, 1)

    circuit = cirq.Circuit()

    # Prepare shared entangled state.
    circuit.append([
        cirq.H(alice),
        cirq.CNOT(alice, bob),
        cirq.X(alice)**-0.25,
    ])

    # Referees flip coins.
    circuit.append([
        cirq.H(alice_referee),
        cirq.H(bob_referee),
    ])

    # Players do a sqrt(X) based on their referee's coin.
    circuit.append([
        cirq.CNOT(alice_referee, alice)**0.5,
        cirq.CNOT(bob_referee, bob)**0.5,
    ])

    # Then results are recorded.
    circuit.append([
        cirq.measure(alice, key='a'),
        cirq.measure(bob, key='b'),
        cirq.measure(alice_referee, key='x'),
        cirq.measure(bob_referee, key='y'),
    ])

    return circuit


def bitstring(bits):
    return ''.join('1' if e else '_' for e in bits)


if __name__ == '__main__':
    main()

Bernstein Vazirani

"""Demonstrates the Bernstein-Vazirani algorithm.

The (non-recursive) Bernstein-Vazirani algorithm takes a black-box oracle
implementing a function f(a) = a·factors + bias (mod 2), where 'bias' is 0 or 1,
'a' and 'factors' are vectors with all elements equal to 0 or 1, and the
algorithm solves for 'factors' in a single query to the oracle.

=== REFERENCE ===

Bernstein, Ethan, and Umesh Vazirani. "Quantum complexity theory."
SIAM Journal on Computing 26.5 (1997): 1411-1473.

=== EXAMPLE OUTPUT ===

Secret function:
f(a) = a·<0, 1, 1, 1, 0, 0, 1, 0> + 1 (mod 2)
Circuit:
(0, 0): ───────H───────────────────────H───M───

(1, 0): ───────H───────@───────────────H───M───
                       │                   │
(2, 0): ───────H───────┼───@───────────H───M───
                       │   │               │
(3, 0): ───────H───────┼───┼───@───────H───M───
                       │   │   │           │
(4, 0): ───────H───────┼───┼───┼───────H───M───
                       │   │   │           │
(5, 0): ───────H───────┼───┼───┼───────H───M───
                       │   │   │           │
(6, 0): ───────H───────┼───┼───┼───@───H───M───
                       │   │   │   │       │
(7, 0): ───────H───────┼───┼───┼───┼───H───M───
                       │   │   │   │
(8, 0): ───X───H───X───X───X───X───X───────────
Sampled results:
Counter({'01110010': 3})
Most common matches secret factors:
True
"""

import random

import cirq


def main(qubit_count = 8):
    circuit_sample_count = 3

    # Choose qubits to use.
    input_qubits = [cirq.GridQubit(i, 0) for i in range(qubit_count)]
    output_qubit = cirq.GridQubit(qubit_count, 0)

    # Pick coefficients for the oracle and create a circuit to query it.
    secret_bias_bit = random.randint(0, 1)
    secret_factor_bits = [random.randint(0, 1) for _ in range(qubit_count)]
    oracle = make_oracle(input_qubits,
                         output_qubit,
                         secret_factor_bits,
                         secret_bias_bit)
    print('Secret function:\nf(a) = a·<{}> + {} (mod 2)'.format(
        ', '.join(str(e) for e in secret_factor_bits),
        secret_bias_bit))

    # Embed the oracle into a special quantum circuit querying it exactly once.
    circuit = make_bernstein_vazirani_circuit(
        input_qubits, output_qubit, oracle)
    print('Circuit:')
    print(circuit)

    # Sample from the circuit a couple times.
    simulator = cirq.Simulator()
    result = simulator.run(circuit, repetitions=circuit_sample_count)
    frequencies = result.histogram(key='result', fold_func=bitstring)
    print('Sampled results:\n{}'.format(frequencies))

    # Check if we actually found the secret value.
    most_common_bitstring = frequencies.most_common(1)[0][0]
    print('Most common matches secret factors:\n{}'.format(
        most_common_bitstring == bitstring(secret_factor_bits)))


def make_oracle(input_qubits,
                output_qubit,
                secret_factor_bits,
                secret_bias_bit):
    """Gates implementing the function f(a) = a·factors + bias (mod 2)."""

    if secret_bias_bit:
        yield cirq.X(output_qubit)

    for qubit, bit in zip(input_qubits, secret_factor_bits):
        if bit:
            yield cirq.CNOT(qubit, output_qubit)


def make_bernstein_vazirani_circuit(input_qubits, output_qubit, oracle):
    """Solves for factors in f(a) = a·factors + bias (mod 2) with one query."""

    c = cirq.Circuit()

    # Initialize qubits.
    c.append([
        cirq.X(output_qubit),
        cirq.H(output_qubit),
        cirq.H.on_each(*input_qubits),
    ])

    # Query oracle.
    c.append(oracle)

    # Measure in X basis.
    c.append([
        cirq.H.on_each(*input_qubits),
        cirq.measure(*input_qubits, key='result')
    ])

    return c


def bitstring(bits):
    return ''.join(str(int(b)) for b in bits)


if __name__ == '__main__':
    main()

Grover

"""Demonstrates Grover algorithm.

The Grover algorithm takes a black-box oracle implementing a function
{f(x) = 1 if x==x', f(x) = 0 if x!= x'} and finds x' within a randomly
ordered sequence of N items using O(sqrt(N)) operations and O(N log(N)) gates,
with the probability p >= 2/3.

At the moment, only 2-bit sequences (for which one pass through Grover operator
is enough) are considered.

=== REFERENCE ===
Coles, Eidenbenz et al. Quantum Algorithm Implementations for Beginners
https://arxiv.org/pdf/1804.03719.pdf

=== EXAMPLE OUTPUT ===
Secret bit sequence: [1, 0]
Circuit:
(0, 0): ───────H───────@───────H───X───────@───────X───H───M───
                       │                   │               │
(1, 0): ───────H───X───@───X───H───X───H───X───H───X───H───M───

(2, 0): ───X───H───────X───────────────────────────────────────
Sampled results:
Counter({'10': 10})
Most common bitstring: 10
Found a match: True

"""

import random
import cirq


def set_io_qubits(qubit_count):
    """Add the specified number of input and output qubits."""
    input_qubits = [cirq.GridQubit(i, 0) for i in range(qubit_count)]
    output_qubit = cirq.GridQubit(qubit_count, 0)
    return (input_qubits, output_qubit)


def make_oracle(input_qubits, output_qubit, x_bits):
    """Implement function {f(x) = 1 if x==x', f(x) = 0 if x!= x'}."""
    # Make oracle.
    # for (1, 1) it's just a Toffoli gate
    # otherwise negate the zero-bits.
    yield(cirq.X(q) for (q, bit) in zip(input_qubits, x_bits) if not bit)
    yield(cirq.TOFFOLI(input_qubits[0], input_qubits[1], output_qubit))
    yield(cirq.X(q) for (q, bit) in zip(input_qubits, x_bits) if not bit)


def make_grover_circuit(input_qubits, output_qubit, oracle):
    """Find the value recognized by the oracle in sqrt(N) attempts."""
    # For 2 input qubits, that means using Grover operator only once.
    c = cirq.Circuit()

    # Initialize qubits.
    c.append([
        cirq.X(output_qubit),
        cirq.H(output_qubit),
        cirq.H.on_each(*input_qubits),
    ])

    # Query oracle.
    c.append(oracle)

    # Construct Grover operator.
    c.append(cirq.H.on_each(*input_qubits))
    c.append(cirq.X.on_each(*input_qubits))
    c.append(cirq.H.on(input_qubits[1]))
    c.append(cirq.CNOT(input_qubits[0], input_qubits[1]))
    c.append(cirq.H.on(input_qubits[1]))
    c.append(cirq.X.on_each(*input_qubits))
    c.append(cirq.H.on_each(*input_qubits))

    # Measure the result.
    c.append(cirq.measure(*input_qubits, key='result'))

    return c


def bitstring(bits):
    return ''.join(str(int(b)) for b in bits)


def main():
    qubit_count = 2
    circuit_sample_count = 10

    #Set up input and output qubits.
    (input_qubits, output_qubit) = set_io_qubits(qubit_count)

    #Choose the x' and make an oracle which can recognize it.
    x_bits = [random.randint(0, 1) for _ in range(qubit_count)]
    print('Secret bit sequence: {}'.format(x_bits))

    # Make oracle (black box)
    oracle = make_oracle(input_qubits, output_qubit, x_bits)

    # Embed the oracle into a quantum circuit implementing Grover's algorithm.
    circuit = make_grover_circuit(input_qubits, output_qubit, oracle)
    print('Circuit:')
    print(circuit)

    # Sample from the circuit a couple times.
    simulator = cirq.Simulator()
    result = simulator.run(circuit, repetitions=circuit_sample_count)

    frequencies = result.histogram(key='result', fold_func=bitstring)
    print('Sampled results:\n{}'.format(frequencies))

    # Check if we actually found the secret value.
    most_common_bitstring = frequencies.most_common(1)[0][0]
    print('Most common bitstring: {}'.format(most_common_bitstring))
    print('Found a match: {}'.format(
        most_common_bitstring == bitstring(x_bits)))


if __name__ == '__main__':
    main()

Hello Qubit

"""Creates and simulates a simple circuit.

=== EXAMPLE OUTPUT ===
Circuit:
(0, 0): ───X^0.5───M('m')───
Results:
m=11000111111011001000
"""

import cirq


def main():
    # Pick a qubit.
    qubit = cirq.GridQubit(0, 0)

    # Create a circuit
    circuit = cirq.Circuit.from_ops(
        cirq.X(qubit)**0.5,  # Square root of NOT.
        cirq.measure(qubit, key='m')  # Measurement.
    )
    print("Circuit:")
    print(circuit)

    # Simulate the circuit several times.
    simulator = cirq.google.XmonSimulator()
    result = simulator.run(circuit, repetitions=20)
    print("Results:")
    print(result)


if __name__ == '__main__':
    main()

Phase Estimator

"""Creates and simulates a phase estimator circuit.

=== EXAMPLE OUTPUT ===
Estimation with 2qubits.
Actual, Estimation (Raw binary)
0.0000, 0.0000 (00)
0.1000, 0.0000 (00)
0.2000, 0.2500 (01)
0.3000, 0.2500 (01)
0.4000, 0.5000 (10)
0.5000, 0.5000 (10)
0.6000, 0.5000 (10)
0.7000, 0.7500 (11)
0.8000, 0.7500 (11)
0.9000, 0.0000 (00)
RMS Error: 0.2915

Estimation with 4qubits.
Actual, Estimation (Raw binary)
0.0000, 0.0000 (0000)
0.1000, 0.1250 (0010)
0.2000, 0.1875 (0011)
0.3000, 0.3125 (0101)
0.4000, 0.3750 (0110)
0.5000, 0.5000 (1000)
0.6000, 0.6250 (1010)
0.7000, 0.6875 (1011)
0.8000, 0.8125 (1101)
0.9000, 0.8750 (1110)
RMS Error: 0.0177

Estimation with 8qubits.
Actual, Estimation (Raw binary)
0.0000, 0.0000 (00000000)
0.1000, 0.1016 (00011010)
0.2000, 0.1992 (00110011)
0.3000, 0.3008 (01001101)
0.4000, 0.3984 (01100110)
0.5000, 0.5000 (10000000)
0.6000, 0.6016 (10011010)
0.7000, 0.6992 (10110011)
0.8000, 0.8008 (11001101)
0.9000, 0.8984 (11100110)
RMS Error: 0.0011
"""


import numpy as np
import cirq


class QftInverse(cirq.MultiQubitGate):
    """Quantum gate for the inverse Quantum Fourier Transformation
    """

    def __init__(self, num_qubits):
        super(QftInverse, self).__init__(num_qubits)


    def _decompose_(self, qubits):
        """A quantum circuit (QFT_inv) with the following structure.

        ---H--@-------@--------@----------------------------------------------
              |       |        |
        ------@^-0.5--+--------+---------H--@-------@-------------------------
                      |        |            |       |
        --------------@^-0.25--+------------@^-0.5--+---------H--@------------
                               |                    |            |
        -----------------------@^-0.125-------------@^-0.25------@^-0.5---H---

        The number of qubits can be arbitrary.
        """

        qubits = list(qubits)
        while len(qubits) > 0:
            q_head = qubits.pop(0)
            yield cirq.H(q_head)
            for i, qubit in enumerate(qubits):
                yield (cirq.CZ**(-1/2.0**(i+1)))(qubit, q_head)


def run_estimate(unknown_gate, qnum, repetitions):
    """Construct the following phase estimator circuit and execute simulations.

                                     ---------
    ---H---------------------@------|         |---M--- [m4]:lowest bit
                             |      |         |
    ---H---------------@-----+------|         |---M--- [m3]
                       |     |      | QFT_inv |
    ---H---------@-----+-----+------|         |---M--- [m2]
                 |     |     |      |         |
    ---H---@-----+-----+-----+------|         |---M--- [m1]:highest bit
           |     |     |     |       ---------
    -------U-----U^2---U^4---U^8----------------------

    The measurement results M=[m1, m2,...] are translated to the estimated
    phase with the following formula:
    phi = m1*(1/2) + m2*(1/2)^2 + m3*(1/2)^3 + ...
    """

    qubits = [None] * qnum
    for i in range(len(qubits)):
        qubits[i] = cirq.GridQubit(0, i)
    ancilla = cirq.GridQubit(0, len(qubits))

    circuit = cirq.Circuit.from_ops(
        cirq.H.on_each(*qubits),
        [cirq.ControlledGate(unknown_gate**(2**i)).on(qubits[qnum-i-1], ancilla)
         for i in range(qnum)],
        QftInverse(qnum)(*qubits),
        cirq.measure(*qubits, key='phase'))
    simulator = cirq.Simulator()
    result = simulator.run(circuit, repetitions=repetitions)
    return result


def experiment(qnum, repetitions=100):
    """Execute the phase estimator cirquit with multiple settings and
    show results.
    """

    def example_gate(phi):
        """An example unitary 1-qubit gate U with an eigen vector |0> and an
        eigen value exp(2*Pi*i*phi)
        """

        gate = cirq.SingleQubitMatrixGate(
            matrix=np.array([[np.exp(2*np.pi*1.0j*phi), 0], [0, 1]]))
        return gate

    print('Estimation with {}qubits.'.format(qnum))
    print('Actual, Estimation (Raw binary)')
    errors = []
    fold_func = lambda ms: ''.join(np.flip(ms, 0).astype(int).astype(str))
    for phi in np.arange(0, 1, 0.1):
        result = run_estimate(example_gate(phi), qnum, repetitions)
        hist = result.histogram(key='phase', fold_func=fold_func)
        estimate_bin = hist.most_common(1)[0][0]
        estimate = (sum([float(s)*0.5**(order+1)
                         for order, s in enumerate(estimate_bin)]))
        print('{:0.4f}, {:0.4f} ({})'.format(phi, estimate, estimate_bin))
        errors.append((phi-estimate)**2)
    print('RMS Error: {:0.4f}\n'.format(np.sqrt(sum(errors)/len(errors))))


def main(qnums = (2, 4, 8), repetitions=100):
    for qnum in qnums:
        experiment(qnum, repetitions=repetitions)


if __name__ == '__main__':
    main()

Place on Bristlecone

# pylint: disable=line-too-long
"""Create a circuit, optimize it, and map it onto a Bristlecone chip.

===EXAMPLE_OUTPUT===

Length 10 line on Bristlecone:
(5, 0)━━(5, 1)

        (6, 1)━━(6, 2)

                (7, 2)━━(7, 3)

                        (8, 3)━━(8, 4)

                                (9, 4)━━(9, 5)
Initial circuit:
0: ───×───────M('all')───
      │       │
1: ───×───×───M──────────
          │   │
2: ───×───×───M──────────
      │       │
3: ───×───×───M──────────
          │   │
4: ───×───×───M──────────
      │       │
5: ───×───×───M──────────
          │   │
6: ───×───×───M──────────
      │       │
7: ───×───×───M──────────
          │   │
8: ───×───×───M──────────
      │       │
9: ───×───────M──────────

Xmon circuit:
(5, 0): ───Y^-0.5───@───Y^0.5───@───────Y^-0.5───@──────────────────────────────────────────────────────────────────M('all')───
                    │           │                │                                                                  │
(5, 1): ───X^-0.5───@───X^0.5───@───────X^-0.5───@────────X^0.5───────────@───X^-0.5───@────────X^0.5───@───────────M──────────
                                                                          │            │                │           │
(6, 1): ───Y^-0.5───────@───────Y^0.5───@────────Y^-0.5───@───────Y^0.5───@───Y^-0.5───@────────Y^0.5───@───────────M──────────
                        │               │                 │                                                         │
(6, 2): ───X^-0.5───────@───────X^0.5───@────────X^-0.5───@───────X^0.5───────@────────X^-0.5───@───────X^0.5───@───M──────────
                                                                              │                 │               │   │
(7, 2): ───Y^-0.5───@───Y^0.5───@───────Y^-0.5───@────────Y^0.5───────────────@────────Y^-0.5───@───────Y^0.5───@───M──────────
                    │           │                │                                                                  │
(7, 3): ───X^-0.5───@───X^0.5───@───────X^-0.5───@────────X^0.5───────────@───X^-0.5───@────────X^0.5───@───────────M──────────
                                                                          │            │                │           │
(8, 3): ───Y^-0.5───────@───────Y^0.5───@────────Y^-0.5───@───────Y^0.5───@───Y^-0.5───@────────Y^0.5───@───────────M──────────
                        │               │                 │                                                         │
(8, 4): ───X^-0.5───────@───────X^0.5───@────────X^-0.5───@───────X^0.5───────@────────X^-0.5───@───────X^0.5───@───M──────────
                                                                              │                 │               │   │
(9, 4): ───Y^-0.5───@───Y^0.5───@───────Y^-0.5───@────────Y^0.5───────────────@────────Y^-0.5───@───────Y^0.5───@───M──────────
                    │           │                │                                                                  │
(9, 5): ───X^-0.5───@───X^0.5───@───────X^-0.5───@──────────────────────────────────────────────────────────────────M──────────
"""

import cirq


def main():
    print("Length 10 line on Bristlecone:")
    line = cirq.google.line_on_device(cirq.google.Bristlecone, length=10)
    print(line)

    print("Initial circuit:")
    n = 10
    depth = 2
    circuit = cirq.Circuit.from_ops(
        cirq.SWAP(cirq.LineQubit(j), cirq.LineQubit(j + 1))
        for i in range(depth)
        for j in range(i % 2, n - 1, 2)
    )
    circuit.append(cirq.measure(*cirq.LineQubit.range(n), key='all'))
    print(circuit)

    print()
    print("Xmon circuit:")
    translated = cirq.google.optimized_for_xmon(
        circuit=circuit,
        new_device=cirq.google.Bristlecone,
        qubit_map=lambda q: line[q.x])
    print(translated)


if __name__ == '__main__':
    main()

Quantum Fourier Transform

"""
Creates and simulates a circuit for Quantum Fourier Transform(QFT)
on a 4 qubit system.

In this example we demonstrate Fourier Transform on
(1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0) vector. To do the same, we prepare
the input state of the qubits as |0000>.
=== EXAMPLE OUTPUT ===

Circuit:
(0, 0): ─H───@^0.5───×───H────────────@^0.5─────×───H──────────@^0.5──×─H
             │       │                │         │               │     │
(0, 1): ─────@───────×───@^0.25───×───@─────────×───@^0.25───×──@─────×──
                         │        │                 │        │
(1, 0): ─────────────────┼────────┼───@^0.125───×───┼────────┼───────────
                         │        │   │         │   │        │
(1, 1): ─────────────────@────────×───@─────────×───@────────×───────────

FinalState
[0.25+0.j 0.25+0.j 0.25+0.j 0.25+0.j 0.25+0.j 0.25+0.j 0.25+0.j 0.25+0.j
 0.25+0.j 0.25+0.j 0.25+0.j 0.25+0.j 0.25+0.j 0.25+0.j 0.25+0.j 0.25+0.j]
"""

import numpy as np

import cirq

def main():
    """Demonstrates Quantum Fourier transform.
    """
    # Create circuit
    qft_circuit = generate_2x2_grid_qft_circuit()
    print('Circuit:')
    print(qft_circuit)
    # Simulate and collect final_state
    simulator = cirq.Simulator()
    result = simulator.simulate(qft_circuit)
    print()
    print('FinalState')
    print(np.around(result.final_state, 3))

def _cz_and_swap(q0, q1, rot):
    yield cirq.CZ(q0, q1)**rot
    yield cirq.SWAP(q0,q1)

# Create a quantum fourier transform circuit for 2*2 planar qubit architecture.
# Circuit is adopted from https://arxiv.org/pdf/quant-ph/0402196.pdf
def generate_2x2_grid_qft_circuit():
    # Define a 2*2 square grid of qubits.
    a,b,c,d = [cirq.GridQubit(0, 0), cirq.GridQubit(0, 1),
               cirq.GridQubit(1, 1), cirq.GridQubit(1, 0)]

    circuit = cirq.Circuit.from_ops(
        cirq.H(a),
        _cz_and_swap(a, b, 0.5),
        _cz_and_swap(b, c, 0.25),
        _cz_and_swap(c, d, 0.125),
        cirq.H(a),
        _cz_and_swap(a, b, 0.5),
        _cz_and_swap(b, c, 0.25),
        cirq.H(a),
        _cz_and_swap(a, b, 0.5),
        cirq.H(a),
        strategy=cirq.InsertStrategy.EARLIEST
    )
    return circuit

if __name__ == '__main__':
    main()