def density(G, t=None):
    r"""Return the density of a graph at timestamp t.
        The density for undirected graphs is

        .. math::
           d = \frac{2m}{n(n-1)},

        and for directed graphs is

        .. math::
           d = \frac{m}{n(n-1)},

        where `n` is the number of nodes and `m`  is the number of edges in `G`.

        Parameters
        ----------

        G : Graph opject
            DyNetx graph object


        t : snapshot id (default=None)
            If None the density will be computed on the flattened graph.


        Notes
        -----

        The density is 0 for a graph without edges and 1 for a complete graph.

        Self loops are counted in the total number of edges so graphs with self
        loops can have density higher than 1.
    """
    n = number_of_nodes(G, t)
    m = number_of_interactions(G, t)
    if m == 0 or m is None or n <= 1:
        return 0

    d = m / (n * (n - 1))
    if not G.is_directed():
        d *= 2
    return d