def make_graph_UPA(num_nodes, num_edges_per_node):
    """
    Function that creates an undirected graph with num_nodes nodes
    represented as an adjacency list using an adapted DPA algorithm given in
    assignment #1: 'Analysis of Citation Graphs' to generate the edges.
    """
    
    # Test num_nodes and num_edges_per_node to determine whether
    # the algoritnm can be used
    _num_nodes = int(num_nodes)
    _num_edges_per_node = int(num_edges_per_node)
    if _num_nodes < _num_edges_per_node:
        print "###> Error: _num_nodes must be larger than or equal to _num_edges_per_node!"
        quit()

    # Create a complete graph of size num_edges_per_node
    print "Generating the initial graph."
    _graph = degree.make_complete_graph(_num_edges_per_node)

    # Initialize variables
    _node_counter = _num_edges_per_node
    _edge_counter = int( 0.5 * _num_edges_per_node * ( _num_edges_per_node - 1 ))
    print "...............", _node_counter, "nodes generated."
    print "....................", _edge_counter, "edges generated."
    print

    # Add nodes to graph according to the UPA algorithm
    # Create UPATrial object that is used to generate the edges with
    # the newly generated nodes
    _trail = UPA.UPATrial(_num_edges_per_node)
    print "Generating additional nodes."
    for _index in range(_num_edges_per_node, _num_nodes):
        # Create additional node
        _new_nodes_edges = _trail.run_trial(_num_edges_per_node)
        # Add the new node to _graph
        _graph[_index] = _new_nodes_edges
        # Add the edges from the selected nodes to the new node
        for _node in _new_nodes_edges:
            _graph[_node].add(_index)
        _node_counter += 1
        _edge_counter += len(_new_nodes_edges)
        if _node_counter % 100 == 0:
            print "...............", _node_counter, "nodes generated."
    print "...............", _node_counter, "nodes generated."
    print "....................", _edge_counter, "edges generated."

    # Return the resulting graph
    return _graph
def make_graph_DPA(num_nodes, num_edges_per_node):
    """
    Function that creates a directed graph with num_nodes nodes
    represented as an adjacency list using the DPA algorithm given in the
    assignment.
    """
    
    # Test num_nodes and num_edges_per_node to determine whether
    # the algoritnm can be used
    _num_nodes = int(num_nodes)
    _num_edges_per_node = int(num_edges_per_node)
    if _num_nodes < _num_edges_per_node:
        print "###> Error: _num_nodes must be larger than or eagle to _num_edges_per_node!"
        quit()

    # Create a complete graph of size num_edges_per_node and compute its in degrees
    print "Generating the initial graph."
    _graph = degree.make_complete_graph(_num_edges_per_node)

    # Initialize variables
    _counter = _num_edges_per_node

    # Add nodes to graph according to the DPA algorithm
    # Create DPATrial object the is used to generate the edges with the new nodes
    _trail = DPA.DPATrial(_num_edges_per_node)
    print "Generating additional nodes."
    for _index in range(_num_edges_per_node, _num_nodes):
        # Create additional node
        _new_nodes_edges = _trail.run_trial(_num_edges_per_node)
        # Add the new node to _graph
        _graph[_index] = _new_nodes_edges
        _counter += 1
        if _counter % 1000 == 0:
            print "...............", _counter, "nodes generated."

    # Return the resulting graph
    return _graph