A QAOA circuit for the Quadratic Unconstrained Binary Optimization
    problem (i.e. an Ising model).

    Args:
        graph : a networkx graph instance with optional edge and node weights
        steps : number of QAOA steps
        beta  : driver parameters (One per step)
        gamma : cost parameters (One per step)

def qubo_circuit(
        graph: nx.Graph,
        steps: int,
        beta: Sequence,
        gamma: Sequence) -> Circuit:
    """
    A QAOA circuit for the Quadratic Unconstrained Binary Optimization
    problem (i.e. an Ising model).

    Args:
        graph : a networkx graph instance with optional edge and node weights
        steps : number of QAOA steps
        beta  : driver parameters (One per step)
        gamma : cost parameters (One per step)

    """

    qubits = list(graph.nodes())

    # Initialization
    circ = Circuit()
    for q0 in qubits:
        circ += H(q0)

    # Run for given number of QAOA steps
    for p in range(0, steps):

        # Cost
        for q0, q1 in graph.edges():
            weight = graph[q0][q1].get('weight', 1.0)
            # Note factor of pi due to parameterization of ZZ gate
            circ += ZZ(-weight * gamma[p] / np.pi, q0, q1)

        for q0 in qubits:
            node_weight = graph.nodes[q0].get('weight', None)
            if node_weight is not None:
                circ += RZ(node_weight, q0)

        # Drive
        for q0 in qubits:
            circ += RX(beta[p], q0)

    return circ