<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def extract_connected_components(graph, connectivity_type, node_to_id):
 """ Extract the largest connected component from a graph. Inputs: - graph: An adjacency matrix in scipy sparse matrix format. - connectivity_type: A string that can be either: "strong" or "weak". - node_to_id: A map from graph node id to Twitter id, in python dictionary format. Outputs: - largest_connected_component: An adjacency matrix in scipy sparse matrix format. - new_node_to_id: A map from graph node id to Twitter id, in python dictionary format. - old_node_list: List of nodes from the possibly disconnected original graph. Raises: - RuntimeError: If there the input graph is empty. """

    # Get a networkx graph.
    nx_graph = nx.from_scipy_sparse_matrix(graph, create_using=nx.DiGraph())

    # Calculate all connected components in graph.
    if connectivity_type == "weak":
        largest_connected_component_list = nxalgcom.weakly_connected_component_subgraphs(nx_graph)
    elif connectivity_type == "strong":
        largest_connected_component_list = nxalgcom.strongly_connected_component_subgraphs(nx_graph)
    else:
        print("Invalid connectivity type input.")
        raise RuntimeError

    # Handle empty graph.
    try:
        largest_connected_component = max(largest_connected_component_list, key=len)
    except ValueError:
        print("Error: Empty graph.")
        raise RuntimeError

    old_node_list = largest_connected_component.nodes()
    node_to_node = dict(zip(np.arange(len(old_node_list)), old_node_list))
    largest_connected_component = nx.to_scipy_sparse_matrix(largest_connected_component, dtype=np.float64, format="csr")

    # Make node_to_id.
    new_node_to_id = {k: node_to_id[v] for k, v in node_to_node.items()}

    return largest_connected_component, new_node_to_id, old_node_list