def get_filter_scores(self, Efingerprint, test_type):
        """ Compute the filter scores tau.

        Run through each possible contingency and compute the filter score
        tau for that contingency. Create a filter_score_dict with the results.

        Inputs:
        Efingerprint (np.matrix) - The voltage change fingerprint.
        test_type ("Full", "Single_Lines") - The type of contingencies for 
           which to test.

        Output:
        filter_score_dict (Dictionary) - A dictionary with contingencies as keys
           and tau scores as values. "No contingency" is not included in this 
           dictionary.
        """
        filter_score_dict = dict()
        filter_scores_computed = 0
        for sub in self.substations:
            for splitting_nodes in sub.node_iterator(test_type):
                split_einds = np.array(
                    [sub.nodes[sn].eind for sn in splitting_nodes])
                key = (sub.index, tuple(splitting_nodes))

                subspace = self.get_subspace(split_einds)
                x = precision_lstsq(subspace, Efingerprint, ITERATIONS=1)
                Efing_sub = subspace.dot(x)
                tau_score = np.linalg.norm(Efingerprint - Efing_sub)
                filter_score_dict[key] = tau_score
                filter_scores_computed += 1
        return filter_score_dict
    def get_filter_scores(self, Efingerprint, test_type):
        """ Compute the filter scores tau.

        Run through each possible contingency and compute the filter score
        tau for that contingency. Create a filter_score_dict with the results.

        Inputs:
        Efingerprint (np.matrix) - The voltage change fingerprint.
        test_type ("Full", "Single_Lines") - The type of contingencies for 
           which to test.

        Output:
        filter_score_dict (Dictionary) - A dictionary with contingencies as keys
           and tau scores as values. "No contingency" is not included in this 
           dictionary.
        """
        filter_score_dict = dict()
        filter_scores_computed = 0
        for sub in self.substations:
            for splitting_nodes in sub.node_iterator(test_type):
                split_einds = np.array([sub.nodes[sn].eind for 
                                        sn in splitting_nodes])
                key = (sub.index, tuple(splitting_nodes))
                    
                subspace = self.get_subspace(split_einds)
                x = precision_lstsq(subspace, Efingerprint, ITERATIONS = 1)                
                Efing_sub = subspace.dot(x)
                tau_score = np.linalg.norm(Efingerprint - Efing_sub)
                filter_score_dict[key] = tau_score
                filter_scores_computed += 1
        return filter_score_dict
    def get_scores(self,
                   Efingerprint,
                   filter_score_dict,
                   ts_to_keep=1,
                   use_filter=True):
        """ Compute the actual scores t.

        Inputs:
        Efingerprint (np.matrix) - The voltage change fingerprint.
        filter_score_dict (Dictionary) - A dictionary with contingencies as keys
           and tau scores as values. "No contingency" is not included in this 
           dictionary.
        ts_to_keep (int) - As we iterate over possible contingencies, we only
           compute its t score if its filter (tau) score is below the 
           ts_to_keep'th lowest t_ij computed so far. A higher number increases
           computational cost but lowers the chances of filtering out the 
           correct answer. The paper only discusses the default value of 1.
        use_filter (True, False) - Whether or not to filter based on filter 
           (tau) scores. Default is True.
        """
        sort_filtersc = sorted(filter_score_dict.items(), key=lambda x: x[1])
        min_ts = np.array([np.Inf] * ts_to_keep)

        score_dict = dict()
        score_dict[-1] = np.linalg.norm(
            Efingerprint)  # Represents "no topology
        # change."
        for i in xrange(len(sort_filtersc)):
            key, tau = sort_filtersc[i]
            splitbus, splitting_nodes = key
            if (filter_score_dict[key] - np.max(min_ts) > 0) and use_filter:
                continue
            split_einds = np.array([
                self.substations[splitbus].nodes[sn].eind
                for sn in splitting_nodes
            ])
            U = self.get_system_matrix_extension(split_einds)
            FT = U[-len(self.lamed):, :].T
            UAinvU = U.T * self.Afac(U.todense())
            try:
                gamma = np.linalg.solve(UAinvU, FT * self.lamed)
            except np.linalg.LinAlgError:
                gamma = precision_lstsq(UAinvU, FT * self.lamed, ITERATIONS=1)
            Efing_approx = -self.EAinv * (U * gamma)
            t_score = np.linalg.norm(Efingerprint - Efing_approx)
            score_dict[key] = t_score
            if t_score < np.max(min_ts):
                min_ts[np.argmax(min_ts)] = t_score
        return score_dict
    def get_scores(self, Efingerprint, filter_score_dict, ts_to_keep = 1, 
                   use_filter = True):
        """ Compute the actual scores t.

        Inputs:
        Efingerprint (np.matrix) - The voltage change fingerprint.
        filter_score_dict (Dictionary) - A dictionary with contingencies as keys
           and tau scores as values. "No contingency" is not included in this 
           dictionary.
        ts_to_keep (int) - As we iterate over possible contingencies, we only
           compute its t score if its filter (tau) score is below the 
           ts_to_keep'th lowest t_ij computed so far. A higher number increases
           computational cost but lowers the chances of filtering out the 
           correct answer. The paper only discusses the default value of 1.
        use_filter (True, False) - Whether or not to filter based on filter 
           (tau) scores. Default is True.
        """
        sort_filtersc = sorted(filter_score_dict.items(), key = lambda x : x[1])
        min_ts = np.array([np.Inf]*ts_to_keep)
        
        score_dict = dict()
        score_dict[-1] = np.linalg.norm(Efingerprint) # Represents "no topology
                                                      # change."
        for i in xrange(len(sort_filtersc)):
            key, tau = sort_filtersc[i]
            splitbus, splitting_nodes = key
            if (filter_score_dict[key] - np.max(min_ts) > 0) and use_filter:
                continue
            split_einds = np.array([self.substations[splitbus].nodes[sn].eind 
                                    for sn in splitting_nodes])
            U = self.get_system_matrix_extension(split_einds)
            FT = U[-len(self.lamed):,:].T
            UAinvU = U.T * self.Afac(U.todense())
            try:
                gamma = np.linalg.solve(UAinvU, FT * self.lamed)
            except np.linalg.LinAlgError:
                gamma = precision_lstsq(UAinvU, FT * self.lamed, ITERATIONS = 1)
            Efing_approx = -self.EAinv * (U * gamma)
            t_score = np.linalg.norm(Efingerprint - Efing_approx)
            score_dict[key] = t_score
            if t_score < np.max(min_ts):
                min_ts[np.argmax(min_ts)] = t_score
        return score_dict