def question_four():
    '''
    Question 4 (5 pts)
    To continue our analysis of the computer network, we will examine its resilience under an attack in which servers are chosen based on their connectivity.
    We will again compare the resilience of the network to the resilience of ER and UPA graphs of similar size.

    Using targeted_order (or fast_targeted_order), your task is to compute a targeted attack order for each of the three graphs (computer network, ER, UPA) from Question 1.
    Then, for each of these three graphs, compute the resilience of the graph using compute_resilience.
    Finally, plot the computed resiliences as three curves (line plots) in a single standard plot.
    As in Question 1, please include a legend in your plot that distinguishes the three plots.
    The text labels in this legend should include the values for p and m that you used in computing the ER and UPA graphs, respectively.

    Your plot will be assessed based on the answers to the following three questions:

    Does the plot follow the formatting guidelines for plots?
    Does the plot include a legend? Does this legend indicate the values for p and m used in ER and UPA, respectively?
    Do the three curves in the plot have the correct shape?
    '''

    ###
    computer_network_nodes_length = len(computer_network_dict)
    computer_network_edges = sum(len(val) for val in computer_network_dict.itervalues()) / 2

    er_prob = (computer_network_edges / float(computer_network_nodes_length)) / (float(computer_network_nodes_length) - 1) * 2

    print '\n', 'Example network total nodes: ', len(computer_network_dict)
    print 'Computer network undirected edges: ', sum(len(val) for val in computer_network_dict.itervalues()) / 2, '\n'
    print 'Probability for er_graph',  er_prob, '\n'

    er_graph = deggraph.make_ugraph_prob(len(computer_network_dict), er_prob)

    print 'ER network total nodes: ', len(er_graph)
    print 'ER network undirected edges: ', sum(len(val) for val in er_graph.itervalues()) / 2, '\n'

    m_value_upa = int(math.ceil(computer_network_edges / float(computer_network_nodes_length)))

    print 'M value for UPA graph (total nodes divided by edges): ', m_value_upa, '\n'

    upa_graph = create_UPA_graph(len(computer_network_dict), m_value_upa)

    print 'UPA network total nodes: ', len(upa_graph)
    print 'UPA network undirected edges: ', sum(len(val) for val in upa_graph.itervalues()) / 2, '\n'
    ###

    computer_network_target = app2_prov.fast_targeted_order(computer_network_dict)
    er_target = app2_prov.fast_targeted_order(er_graph)
    upa_target = app2_prov.fast_targeted_order(upa_graph)

    computer_network = project2.compute_resilience(computer_network_dict, computer_network_target)
    er_network = project2.compute_resilience(er_graph, er_target)
    upa_network = project2.compute_resilience(upa_graph, upa_target)

    # see question4.png for graph results

    plt.plot(computer_network, lw=2, label='Example computer network')
    plt.plot(er_network, lw=2, label='ER network - p = 0.00397')
    plt.plot(upa_network, lw=2, label='UPA network - m = 3')
    plt.legend(loc='upper right')
    plt.title('Different networks resilience versus targeted attack')
    plt.xlabel('Number of nodes removed')
    plt.ylabel('Largest connected component size')

    plt.show()

    pass
def question_one():
    '''
    Question 1 (5 pts)
    To begin our analysis, we will examine the resilience of the computer network under an attack in which servers are chosen at random.
    We will then compare the resilience of the network to the resilience of ER and UPA graphs of similar size.

    To begin, you should determine the probability p such that the ER graph computed using this edge probability has approximately the same number of edges as the computer network.
    (Your choice for p should be consistent with considering each edge in the undirected graph exactly once, not twice.)
    Likewise, you should compute an integer m such that the number of edges in the UPA graph is close to the number of edges in the computer network.
    Remember that all three graphs being analyzed in this Application should have the same number of nodes and approximately the same number of edges.

    Next, you should write a function random_order that takes a graph and returns a list of the nodes in the graph in some random order.
    Then, for each of the three graphs (computer network, ER, UPA), compute a random attack order using random_order and use this attack order
    in compute_resilience to compute the resilience of the graph.

    Once you have computed the resilience for all three graphs, plot the results as three curves combined in a single standard plot (not log/log).
    Use a line plot for each curve. The horizontal axis for your single plot be the the number of nodes removed (ranging from zero to the number of nodes in the graph)
    while the vertical axis should be the size of the largest connect component in the graphs resulting from the node removal.
    For this question (and others) involving multiple curves in a single plot, please include a legend in your plot that distinguishes the three curves.
    The text labels in this legend should include the values for p and m that you used in computing the ER and UPA graphs, respectively.
    Both matplotlib and simpleplot support these capabilities (matplotlib example and simpleplot example).

    Note that three graphs in this problem are large enough that using CodeSkulptor to calculate compute_resilience for these graphs will take on the order of 3-5 minutes per graph.
    When using CodeSkulptor, we suggest that you compute resilience for each graph separately and save the results (or use desktop Python for this part of the computation).
    You can then plot the result of all three calculations using simpleplot.

    Once you are satisfied with your plot, upload your plot in the box below using "Attach a file" button (the button is disabled under the 'html' edit mode;
    you must be under the 'Rich' edit mode for the button to be enabled). Your plot will be assessed based on the answers to the following three questions:

    Does the plot follow the formatting guidelines for plots?
    Does the plot include a legend? Does this legend indicate the values for p and m used in ER and UPA, respectively?
    Do the three curves in the plot have the correct shapes?
    '''
    # for ER and UPA graph need ~1239 nodes and ~3047 edges to match example network

    # for ER graph (n-1)p = average edge of node
    # so 1238p = 2.46 (3047/1239) ... and p = ~0.00199
    # this looks like it generates 3047 edges, but as it's undirected there are only really half that number.
    # so double and we get p = 0.00397

    # for UPA graph, simply choose M value which is close to average edge of node - either 2 or 3.

    # generate our two random networks and
    # print some statements to check our random networks are close to the example network
    computer_network_nodes_length = len(computer_network_dict)
    computer_network_edges = sum(len(val) for val in computer_network_dict.itervalues()) / 2

    er_prob = (computer_network_edges / float(computer_network_nodes_length)) / (float(computer_network_nodes_length) - 1) * 2

    print '\n', 'Example network total nodes: ', len(computer_network_dict)
    print 'Computer network undirected edges: ', sum(len(val) for val in computer_network_dict.itervalues()) / 2, '\n'
    print 'Probability for er_graph',  er_prob, '\n'

    er_graph = deggraph.make_ugraph_prob(len(computer_network_dict), er_prob)

    print 'ER network total nodes: ', len(er_graph)
    print 'ER network undirected edges: ', sum(len(val) for val in er_graph.itervalues()) / 2, '\n'

    m_value_upa = int(math.ceil(computer_network_edges / float(computer_network_nodes_length)))

    print 'M value for UPA graph (total nodes divided by edges): ', m_value_upa, '\n'

    upa_graph = create_UPA_graph(len(computer_network_dict), m_value_upa)

    print 'UPA network total nodes: ', len(upa_graph)
    print 'UPA network undirected edges: ', sum(len(val) for val in upa_graph.itervalues()) / 2, '\n'

    # now compute resilience of all three networks based on a random attack

    computer_network = project2.compute_resilience(computer_network_dict, random_order(computer_network_dict))
    er_network = project2.compute_resilience(er_graph, random_order(er_graph))
    upa_network = project2.compute_resilience(upa_graph, random_order(upa_graph))

    # now plot these results - see question1.png for results.

    plt.plot(computer_network, lw=2, label='Example computer network')
    plt.plot(er_network, lw=2, label='ER network - p = 0.00397')
    plt.plot(upa_network, lw=2, label='UPA network - m = 3')
    plt.legend(loc='upper right')
    plt.title('Different networks resilience versus a random attack')
    plt.xlabel('Number of nodes removed')
    plt.ylabel('Largest connected component size')

    plt.show()

    # return the two random networks to be used again in question 4
    return er_graph, upa_graph