def is_graph(g):
    """Return True if g is a representation of a graph.

    Arguments:
    g -- value of any type
      Return value is True if g is a graph representation.

    See beginning of this file for our graph representation.

    >>> is_graph("Hello")
    False
    >>> is_graph([])
    True
    >>> is_graph([ [] ])
    True
    >>> is_graph([ [0] ])
    False
    >>> is_graph([ [1,2], [0,2,3], [0,1,3], [1,2] ])
    True
    >>> is_graph([ [1], [] ])
    False

    """
    # g must be list
    if type(g) is not list:
        return False
    n = len(g)

    # Neighbors must all be vertices, and given in order, no dups
    for adjl in g:
        # Each adj list must be of type list
        if type(adjl) is not list:
            return False
        # Neighbors must be ints in [0,n)
        for v in adjl:
            if type(v) is not int:
                return False
            if v < 0 or v >= n:
                return False
        # Check adj list sorted & no duplicates
        # (Do *after* above so we know nbrs can be ordered & hashed)
        if adjl != sorted(list(set(adjl))):
            return False

    # Edges must be symmetric, and no loops
    for v1 in range(n):
        if v1 in g[v1]:
            return False
        for v2 in range(v1):
            e12 = v2 in g[v1]
            e21 = v1 in g[v2]
            if e12 != e21:
                return False
    return True