diff --git a/main_package/classes/abstract_importer.py b/main_package/classes/abstract_importer.py index 7ab61d5..707f0bd 100644 --- a/main_package/classes/abstract_importer.py +++ b/main_package/classes/abstract_importer.py @@ -3,34 +3,21 @@ from abc import ABC, abstractmethod class AbstractImporter(ABC): """ - Interfaccia che espone i metodi necessari all'importing delle trajectories e della struttura della CTBN + Interface that exposes all the necessary methods to import the trajectories and the net structure. - :files_path: il path in cui sono presenti i/il file da importare + :file_path: the file path """ - def __init__(self, files_path): - self.files_path = files_path + def __init__(self, file_path: str): + self.file_path = file_path super().__init__() @abstractmethod def import_trajectories(self, raw_data): - """ - Costruisce le traj partendo dal dataset raw_data - Parameters: - raw_data: il dataset da cui estrarre le traj - Returns: - void - """ pass @abstractmethod def import_structure(self, raw_data): - """ - Costruisce la struttura della rete partendo dal dataset raw_data - Parameters: - raw_data: il dataset da cui estrarre la struttura - Returns: - void - """ pass + diff --git a/main_package/classes/abstract_sample_path.py b/main_package/classes/abstract_sample_path.py new file mode 100644 index 0000000..3d71ca1 --- /dev/null +++ b/main_package/classes/abstract_sample_path.py @@ -0,0 +1,37 @@ +from abc import ABC, abstractmethod +import abstract_importer as ai + + +class AbstractSamplePath(ABC): + + def __init__(self, importer: ai.AbstractImporter): + self.importer = importer + self._trajectories = None + self._structure = None + super().__init__() + + @abstractmethod + def build_trajectories(self): + """ + Builds the Trajectory object that will contain all the trajectories. + Assigns the Trajectoriy object to the instance attribute _trajectories + Clears all the unused dataframes in Importer Object + + Parameters: + void + Returns: + void + """ + pass + + @abstractmethod + def build_structure(self): + """ + Builds the Structure object that aggregates all the infos about the net. + Assigns the Structure object to the instance attribuite _structure + Parameters: + void + Returns: + void + """ + pass diff --git a/main_package/classes/cache.py b/main_package/classes/cache.py index 13d7f6c..f9a1f7a 100644 --- a/main_package/classes/cache.py +++ b/main_package/classes/cache.py @@ -1,24 +1,61 @@ import typing import set_of_cims as sofc + class Cache: + """ + This class has the role of a cache for SetOfCIMS of a test node that have been already computed during the ctpc algorithm. + + :list_of_sets_of_parents: a list of Sets of the parents to which the cim in cache at SAME index is related + :actual_cache: a list of setOfCims objects + """ def __init__(self): - self.list_of_sets_of_indxs = [] + self.list_of_sets_of_parents = [] self.actual_cache = [] - def find(self, parents_comb: typing.Set): - try: - result = self.actual_cache[self.list_of_sets_of_indxs.index(parents_comb)] - print("CACHE HIT!!!!") - return result - except ValueError: - return None + def find(self, parents_comb: typing.Set): #typing.Union[typing.Set, str] + """ + Tries to find in cache given the symbolic parents combination parents_comb the SetOfCims related to that parents_comb. + Parameters: + parents_comb: the parents related to that SetOfCims + Returns: + A SetOfCims object if the parents_comb index is found in list_of_sets_of_parents. + None otherwise. + + """ + try: + #print("Cache State:", self.list_of_sets_of_indxs) + #print("Look For:", parents_comb) + result = self.actual_cache[self.list_of_sets_of_parents.index(parents_comb)] + print("CACHE HIT!!!!", parents_comb) + return result + except ValueError: + return None - def put(self, parents_comb: typing.Set, socim: sofc.SetOfCims): - self.list_of_sets_of_indxs.append(parents_comb) + def put(self, parents_comb: typing.Union[typing.Set, str], socim: sofc.SetOfCims): + """ + Place in cache the SetOfCims object, and the related sybolyc index parents_comb in list_of_sets_of_parents + + Parameters: + parents_comb: the symbolic set index + socim: the related SetOfCims object + + Returns: + void + """ + #print("Putting in cache:", parents_comb) + self.list_of_sets_of_parents.append(parents_comb) self.actual_cache.append(socim) def clear(self): - del self.list_of_sets_of_indxs[:] + """ + Clear the contents of both caches. + + Parameters: + void + Returns: + void + """ + del self.list_of_sets_of_parents[:] del self.actual_cache[:] \ No newline at end of file diff --git a/main_package/classes/conditional_intensity_matrix.py b/main_package/classes/conditional_intensity_matrix.py index 035c48b..927c257 100644 --- a/main_package/classes/conditional_intensity_matrix.py +++ b/main_package/classes/conditional_intensity_matrix.py @@ -2,18 +2,30 @@ import numpy as np class ConditionalIntensityMatrix: - - def __init__(self, state_residence_times, state_transition_matrix): + """ + Abstracts the Conditional Intesity matrix of a node as aggregation of the state residence times vector + and state transition matrix and the actual CIM matrix. + + :_state_residence_times: state residence times vector + :_state_transition_matrix: the transitions count matrix + :_cim: the actual cim of the node + """ + def __init__(self, state_residence_times: np.array, state_transition_matrix: np.array): self._state_residence_times = state_residence_times self._state_transition_matrix = state_transition_matrix - #self.cim = np.zeros(shape=(dimension, dimension), dtype=float) - self._cim = self.state_transition_matrix.astype(np.float) + self._cim = self.state_transition_matrix.astype(np.float64) def compute_cim_coefficients(self): + """ + Compute the coefficients of the matrix _cim by using the following equality q_xx' = M[x, x'] / T[x] + + Parameters: + void + Returns: + void + """ np.fill_diagonal(self._cim, self._cim.diagonal() * -1) - #print(self._cim) self._cim = ((self._cim.T + 1) / (self._state_residence_times + 1)).T - #np.fill_diagonal(self.state_transition_matrix, 0) @property def state_residence_times(self): diff --git a/main_package/classes/json_importer.py b/main_package/classes/json_importer.py index f774492..f684811 100644 --- a/main_package/classes/json_importer.py +++ b/main_package/classes/json_importer.py @@ -4,26 +4,31 @@ import pandas as pd import json import typing from abstract_importer import AbstractImporter -from line_profiler import LineProfiler class JsonImporter(AbstractImporter): """ - Implementa l'interfaccia AbstractImporter e aggiunge i metodi necessari a costruire le trajectories e la struttura della rete - del dataset in formato json con la seguente struttura: + Implements the Interface AbstractImporter and adds all the necessary methods to process and prepare the data in json ext. + with the following structure: [] 0 |_ dyn.cims |_ dyn.str |_ samples |_ variabels - - :df_samples_list: lista di dataframe, ogni dataframe contiene una traj - :df_structure: dataframe contenente la struttura della rete - :df_variables: dataframe contenente le infromazioni sulle variabili della rete - + :file_path: the path of the file that contains tha data to be imported + :samples_label: the reference key for the samples in the trajectories + :structure_label: the reference key for the structure of the network data + :variables_label: the reference key for the cardinalites of the nodes data + :time_key: the key used to identify the timestamps in each trajectory + :variables_key: the key used to identify the names of the variables in the net + :df_samples_list: a Dataframe list in which every df contains a trajectory + :df_structure: Dataframe containing the structure of the network (edges) + :df_variables: Dataframe containing the nodes cardinalities + :df_concatenated_samples: the concatenation and processing of all the trajectories present in the list df_samples list + :sorter: the columns header(excluding the time column) of the Dataframe concatenated_samples """ - def __init__(self, files_path: str, samples_label: str, structure_label: str, variables_label: str, time_key: str, + def __init__(self, file_path: str, samples_label: str, structure_label: str, variables_label: str, time_key: str, variables_key: str): self.samples_label = samples_label self.structure_label = structure_label @@ -35,80 +40,135 @@ class JsonImporter(AbstractImporter): self._df_variables = pd.DataFrame() self._concatenated_samples = None self.sorter = None - super(JsonImporter, self).__init__(files_path) + super(JsonImporter, self).__init__(file_path) def import_data(self): + """ + Imports and prepares all data present needed for susequent computation. + Parameters: + void + Returns: + void + """ raw_data = self.read_json_file() + #self.import_variables(raw_data) self.import_trajectories(raw_data) self.compute_row_delta_in_all_samples_frames(self.time_key) self.clear_data_frame_list() self.import_structure(raw_data) self.import_variables(raw_data, self.sorter) - def import_trajectories(self, raw_data: pd.DataFrame): + def import_trajectories(self, raw_data: typing.List): + """ + Imports the trajectories in the list of dicts raw_data. + Parameters: + :raw_data: List of Dicts + Returns: + void + """ self.normalize_trajectories(raw_data, 0, self.samples_label) - def import_structure(self, raw_data: pd.DataFrame): + def import_structure(self, raw_data: typing.List): + """ + Imports in a dataframe the data in the list raw_data at the key structure_label + + Parameters: + raw_data: the data + Returns: + void + """ self._df_structure = self.one_level_normalizing(raw_data, 0, self.structure_label) - def import_variables(self, raw_data: pd.DataFrame, sorter: typing.List): + def import_variables(self, raw_data: typing.List, sorter: typing.List): + """ + Imports the data in raw_data at the key variables_label. + Sorts the row of the dataframe df_variables using the list sorter. + + Parameters: + raw_data: the data + sorter: the list used to sort the dataframe self.df_variables + Returns: + void + """ self._df_variables = self.one_level_normalizing(raw_data, 0, self.variables_label) + #self.sorter = self._df_variables[self.variables_key].to_list() + #self.sorter.sort() + #print("Sorter:", self.sorter) self._df_variables[self.variables_key] = self._df_variables[self.variables_key].astype("category") self._df_variables[self.variables_key] = self._df_variables[self.variables_key].cat.set_categories(sorter) self._df_variables = self._df_variables.sort_values([self.variables_key]) + self._df_variables.reset_index(inplace=True) + print("Var Frame", self._df_variables) def read_json_file(self) -> typing.List: """ - Legge il primo file .json nel path self.filepath + Reads the first json file in the path self.filePath Parameters: void Returns: - :data: il contenuto del file json + data: the contents of the json file """ - try: - read_files = glob.glob(os.path.join(self.files_path, "*.json")) - if not read_files: - raise ValueError('No .json file found in the entered path!') - with open(read_files[0]) as f: - data = json.load(f) - return data - except ValueError as err: - print(err.args) - - def one_level_normalizing(self, raw_data: pd.DataFrame, indx: int, key: str) -> pd.DataFrame: + #try: + #read_files = glob.glob(os.path.join(self.files_path, "*.json")) + #if not read_files: + #raise ValueError('No .json file found in the entered path!') + with open(self.file_path) as f: + data = json.load(f) + return data + #except ValueError as err: + #print(err.args) + + def one_level_normalizing(self, raw_data: typing.List, indx: int, key: str) -> pd.DataFrame: """ - Estrae i dati innestati di un livello, presenti nel dataset raw_data, - presenti nel json array all'indice indx nel json object key + Extracts the one-level nested data in the list raw_data at the index indx at the key key Parameters: - :raw_data: il dataset json completo - :indx: l'indice del json array da cui estrarre i dati - :key: il json object da cui estrarre i dati + raw_data: List of Dicts + indx: The index of the array from which the data have to be extracted + key: the key for the Dicts from which exctract data Returns: - Il dataframe contenente i dati normalizzati + a normalized dataframe """ return pd.DataFrame(raw_data[indx][key]) - def normalize_trajectories(self, raw_data: pd.DataFrame, indx: int, trajectories_key: str): + def normalize_trajectories(self, raw_data: typing.List, indx: int, trajectories_key: str): """ - Estrae le traiettorie presenti in rawdata nel json array all'indice indx, nel json object trajectories_key. - Aggiunge le traj estratte nella lista di dataframe self.df_samples_list + Extracts the traj in raw_data at the index index at the key trajectories key. + Adds the extracted traj in the dataframe list self._df_samples_list. + Initializes the list self.sorter. Parameters: - void + raw_data: the data + indx: the index of the array from which extract data + trajectories_key: the key of the trajectories objects Returns: void """ - for sample_indx, sample in enumerate(raw_data[indx][trajectories_key]): - self.df_samples_list.append(pd.DataFrame(sample)) - self.sorter = list(self.df_samples_list[0].columns.values)[1:] + dataframe = pd.DataFrame + smps = raw_data[indx][trajectories_key] + self.df_samples_list = [dataframe(sample) for sample in smps] + columns_header = list(self.df_samples_list[0].columns.values) + columns_header.remove(self.time_key) + self.sorter = columns_header def compute_row_delta_sigle_samples_frame(self, sample_frame: pd.DataFrame, time_header_label: str, columns_header: typing.List, shifted_cols_header: typing.List) \ -> pd.DataFrame: + """ + Computes the difference between each value present in th time column. + Copies and shift by one position up all the values present in the remaining columns. + Parameters: + sample_frame: the traj to be processed + time_header_label: the label for the times + columns_header: the original header of sample_frame + shifted_cols_header: a copy of columns_header with changed names of the contents + Returns: + sample_frame: the processed dataframe + + """ sample_frame[time_header_label] = sample_frame[time_header_label].diff().shift(-1) shifted_cols = sample_frame[columns_header].shift(-1).fillna(0).astype('int32') #print(shifted_cols) @@ -118,31 +178,49 @@ class JsonImporter(AbstractImporter): return sample_frame def compute_row_delta_in_all_samples_frames(self, time_header_label: str): - #columns_header = list(self.df_samples_list[0].columns.values) - #self.sorter = columns_header[1:] + """ + Calls the method compute_row_delta_sigle_samples_frame on every dataframe present in the list self.df_samples_list. + Concatenates the result in the dataframe concatanated_samples + + Parameters: + time_header_label: the label of the time column + Returns: + void + """ + """columns_header = list(self.df_samples_list[0].columns.values) + columns_header.remove('Time') + self.sorter = columns_header""" shifted_cols_header = [s + "S" for s in self.sorter] - for indx, sample in enumerate(self.df_samples_list): + compute_row_delta = self.compute_row_delta_sigle_samples_frame + """for indx, sample in enumerate(self.df_samples_list): self.df_samples_list[indx] = self.compute_row_delta_sigle_samples_frame(sample, - time_header_label, self.sorter, shifted_cols_header) + time_header_label, self.sorter, shifted_cols_header)""" + self.df_samples_list = [compute_row_delta(sample, time_header_label, self.sorter, shifted_cols_header) + for sample in self.df_samples_list] self._concatenated_samples = pd.concat(self.df_samples_list) + complete_header = self.sorter[:] + complete_header.insert(0,'Time') + complete_header.extend(shifted_cols_header) + #print("Complete Header", complete_header) + self._concatenated_samples = self._concatenated_samples[complete_header] + #print("Concat Samples",self._concatenated_samples) def build_list_of_samples_array(self, data_frame: pd.DataFrame) -> typing.List: """ - Costruisce una lista contenente le colonne presenti nel dataframe data_frame convertendole in numpy_array + Builds a List containing the columns of dataframe and converts them to a numpy array. Parameters: - :data_frame: il dataframe da cui estrarre e convertire le colonne + :data_frame: the dataframe from which the columns have to be extracted and converted Returns: - :columns_list: la lista contenente le colonne convertite in numpyarray - + :columns_list: the resulting list of numpy arrays """ - columns_list = [] - for column in data_frame: - columns_list.append(data_frame[column].to_numpy()) + columns_list = [data_frame[column].to_numpy() for column in data_frame] + #for column in data_frame: + #columns_list.append(data_frame[column].to_numpy()) return columns_list def clear_concatenated_frame(self): """ - Rimuove tutti i valori contenuti nei data_frames presenti in df_samples_list + Removes all values in the dataframe concatenated_samples Parameters: void Returns: @@ -151,10 +229,13 @@ class JsonImporter(AbstractImporter): self._concatenated_samples = self._concatenated_samples.iloc[0:0] def clear_data_frame_list(self): - for indx in range(len(self.df_samples_list)): # Le singole traj non servono più + """ + Removes all values present in the dataframes in the list df_samples_list + """ + for indx in range(len(self.df_samples_list)): # Le singole traj non servono più #TODO usare list comprens self.df_samples_list[indx] = self.df_samples_list[indx].iloc[0:0] - def import_sampled_cims(self, raw_data: pd.DataFrame, indx: int, cims_key: str) -> typing.Dict: + def import_sampled_cims(self, raw_data: typing.List, indx: int, cims_key: str) -> typing.Dict: cims_for_all_vars = {} for var in raw_data[indx][cims_key]: sampled_cims_list = [] @@ -163,7 +244,6 @@ class JsonImporter(AbstractImporter): cims_for_all_vars[var].append(pd.DataFrame(raw_data[indx][cims_key][var][p_comb]).to_numpy()) return cims_for_all_vars - @property def concatenated_samples(self): return self._concatenated_samples diff --git a/main_package/classes/network_graph.py b/main_package/classes/network_graph.py index db3ee5d..f01c270 100644 --- a/main_package/classes/network_graph.py +++ b/main_package/classes/network_graph.py @@ -1,198 +1,279 @@ import networkx as nx import numpy as np +import typing - -class NetworkGraph(): +class NetworkGraph: """ - Rappresenta il grafo che contiene i nodi e gli archi presenti nell'oggetto Structure graph_struct. - Ogni nodo contine la label node_id, al nodo è anche associato un id numerico progressivo indx che rappresenta la posizione - dei sui valori nella colonna indx della traj - - :graph_struct: l'oggetto Structure da cui estrarre i dati per costruire il grafo graph - :graph: il grafo - + Abstracts the infos contained in the Structure class in the form of a directed graph. + Has the task of creating all the necessary filtering structures for parameters estimation + + :graph_struct: the Structure object from which infos about the net will be extracted + :graph: directed graph + :nodes_labels: the symbolic names of the variables + :nodes_indexes: the indexes of the nodes + :nodes_values: the cardinalites of the nodes + :aggregated_info_about_nodes_parents: a structure that contains all the necessary infos about every parents of every + node in the net + :_fancy_indexing: the indexes of every parent of every node in the net + :_time_scalar_indexing_structure: the indexing structure for state res time estimation + :_transition_scalar_indexing_structure: the indexing structure for transition computation + :_time_filtering: the columns filtering structure used in the computation of the state res times + :_transition_filtering: the columns filtering structure used in the computation of the transition from one state to another + :self._p_combs_structure: all the possibile parents states combination for every node in the net """ def __init__(self, graph_struct): self.graph_struct = graph_struct self.graph = nx.DiGraph() - self._nodes_indexes = self.graph_struct.list_of_nodes_indexes() - self._nodes_labels = self.graph_struct.list_of_nodes_labels() + self._nodes_indexes = self.graph_struct.nodes_indexes + self._nodes_labels = self.graph_struct.nodes_labels + self._nodes_values = self.graph_struct.nodes_values self.aggregated_info_about_nodes_parents = None self._fancy_indexing = None - self._time_scalar_indexing_structure = [] - self._transition_scalar_indexing_structure = [] - self._time_filtering = [] - self._transition_filtering = [] + self._time_scalar_indexing_structure = None + self._transition_scalar_indexing_structure = None + self._time_filtering = None + self._transition_filtering = None + self._p_combs_structure = None def init_graph(self): - self.add_nodes(self.graph_struct.list_of_nodes_labels()) - self.add_edges(self.graph_struct.list_of_edges()) + self.add_nodes(self._nodes_labels) + self.add_edges(self.graph_struct.edges) self.aggregated_info_about_nodes_parents = self.get_ord_set_of_par_of_all_nodes() self._fancy_indexing = self.build_fancy_indexing_structure(0) - self.build_time_scalar_indexing_structure() + self.build_scalar_indexing_structures() self.build_time_columns_filtering_structure() - self.build_transition_scalar_indexing_structure() self.build_transition_columns_filtering_structure() + self._p_combs_structure = self.build_p_combs_structure() + + def fast_init(self, node_id: str): + """ + Initializes all the necessary structures for parameters estimation of the node identified by the label node_id + Parameters: + node_id: the label of the node + Returns: + void + """ + self.add_nodes(self._nodes_labels) + self.add_edges(self.graph_struct.edges) + self.aggregated_info_about_nodes_parents = self.get_ordered_by_indx_set_of_parents(node_id) + self._fancy_indexing = self.aggregated_info_about_nodes_parents[1] + p_indxs = self._fancy_indexing + p_vals = self.aggregated_info_about_nodes_parents[2] + self._time_scalar_indexing_structure = self.build_time_scalar_indexing_structure_for_a_node(node_id, + p_vals) + self._transition_scalar_indexing_structure = self.build_transition_scalar_indexing_structure_for_a_node(node_id, + p_vals) + node_indx = self.get_node_indx(node_id) + self._time_filtering = self.build_time_columns_filtering_for_a_node(node_indx, p_indxs) + self._transition_filtering = self.build_transition_filtering_for_a_node(node_indx, p_indxs) + self._p_combs_structure = self.build_p_comb_structure_for_a_node(p_vals) + + def add_nodes(self, list_of_nodes: typing.List): + """ + Adds the nodes to the graph contained in the list of nodes list_of_nodes. + Sets all the properties that identify a nodes (index, positional index, cardinality) + + Parameters: + list_of_nodes: the nodes to add to graph + Returns: + void + """ + nodes_indxs = self._nodes_indexes + nodes_vals = self.graph_struct.nodes_values + pos = 0 + for id, node_indx, node_val in zip(list_of_nodes, nodes_indxs, nodes_vals): + self.graph.add_node(id, indx=node_indx, val=node_val, pos_indx=pos) + pos += 1 + + def add_edges(self, list_of_edges: typing.List): + """ + Add the edges to the graph contained in the list list_of_edges. + + Parameters: + list_of_edges + Returns: + void + """ + self.graph.add_edges_from(list_of_edges) - def add_nodes(self, list_of_nodes): - #self.graph.add_nodes_from(list_of_nodes) - for id in list_of_nodes: - self.graph.add_node(id) - nx.set_node_attributes(self.graph, {id:self.graph_struct.get_node_indx(id)}, 'indx') + def get_ordered_by_indx_set_of_parents(self, node: str): + """ + Builds the aggregated structure that holds all the infos relative to the parent set of the node, namely + (parents_labels, parents_indexes, parents_cardinalities). + N.B. The parent set is sorted using the list of sorted nodes nodes - def add_edges(self, list_of_edges): - self.graph.add_edges_from(list_of_edges) + Parameters: + node: the label of the node + Returns: + a tuple containing all the parent set infos - def get_ordered_by_indx_set_of_parents(self, node): - #print(node) - #ordered_set = {} + """ parents = self.get_parents_by_id(node) - #print(parents) - sorted_parents = [x for _, x in sorted(zip(self.graph_struct.list_of_nodes_labels(), parents))] - #print(sorted_parents) - #print(parents) - p_indxes= [] - p_values = [] - for n in parents: - #indx = self.graph_struct.get_node_indx(n) - - #print(indx) - #ordered_set[n] = indx - node_indx = self.get_node_indx(n) - p_indxes.append(node_indx) - #p_values.append(self.graph_struct.get_states_number(n)) - p_values.append(self.get_states_number_by_indx(node_indx)) - ordered_set = (sorted_parents, p_indxes, p_values) - #print(ordered_set) - - #ordered_set = {k: v for k, v in sorted(ordered_set.items(), key=lambda item: item[1])} - return ordered_set + nodes = self._nodes_labels + d = {v: i for i, v in enumerate(nodes)} + sorted_parents = sorted(parents, key=lambda v: d[v]) + get_node_indx = self.get_node_indx + p_indxes = [get_node_indx(node) for node in sorted_parents] + p_values = [self.get_states_number(node) for node in sorted_parents] + return (sorted_parents, p_indxes, p_values) def get_ord_set_of_par_of_all_nodes(self): - result = [] - for node in self._nodes_labels: - result.append(self.get_ordered_by_indx_set_of_parents(node)) - #print(result) + get_ordered_by_indx_set_of_parents = self.get_ordered_by_indx_set_of_parents + result = [get_ordered_by_indx_set_of_parents(node) for node in self._nodes_labels] return result - """def get_ordered_by_indx_parents_values(self, node): - parents_values = [] - parents = self.get_ordered_by_indx_set_of_parents(node) - for n in parents: - parents_values.append(self.graph_struct.get_states_number(n)) - return parents_values""" - def get_ordered_by_indx_parents_values_for_all_nodes(self): - """result = [] - for node in self._nodes_labels: - result.append(self.get_ordered_by_indx_parents_values(node)) - return result""" pars_values = [i[2] for i in self.aggregated_info_about_nodes_parents] return pars_values - def get_states_number_of_all_nodes_sorted(self): - states_number_list = [] - for node in self._nodes_labels: - states_number_list.append(self.get_states_number(node)) - return states_number_list - def build_fancy_indexing_structure(self, start_indx): - """list_of_parents_list = self.get_ord_set_of_par_of_all_nodes() - #print(list_of_parents_list) - index_structure = [] - for i, list_of_parents in enumerate(list_of_parents_list): - indexes_for_a_node = [] - for j, node in enumerate(list_of_parents): - indexes_for_a_node.append(self.get_node_indx(node) + start_indx) - index_structure.append(np.array(indexes_for_a_node, dtype=np.int)) - #print(index_structure) - return index_structure""" if start_indx > 0: pass else: fancy_indx = [i[1] for i in self.aggregated_info_about_nodes_parents] return fancy_indx + def build_time_scalar_indexing_structure_for_a_node(self, node_id: str, parents_vals: typing.List) -> np.ndarray: + """ + Builds an indexing structure for the computation of state residence times values. + + Parameters: + node_id: the node label + parents_vals: the caridinalites of the node's parents + Returns: + a numpy array. - def build_time_scalar_indexing_structure_for_a_node(self, node_indx, parents_indxs): - #print(node_indx) - #print("Parents_id", parents_indxs) - #T_vector = np.array([self.graph_struct.variables_frame.iloc[node_id, 1].astype(np.int)]) - T_vector = np.array([self.get_states_number_by_indx(node_indx)]) - #print(T_vector) - #print("Here ", self.graph_struct.variables_frame.iloc[parents_id[0], 1]) - T_vector = np.append(T_vector, [self.graph_struct.get_states_number_by_indx(x) for x in parents_indxs]) - #print(T_vector) + """ + T_vector = np.array([self.get_states_number(node_id)]) + T_vector = np.append(T_vector, parents_vals) T_vector = T_vector.cumprod().astype(np.int) return T_vector - #print(T_vector) - - def build_time_scalar_indexing_structure(self): - #parents_indexes_list = self._fancy_indexing - for node_indx, p_indxs in zip(self.graph_struct.list_of_nodes_indexes(), self._fancy_indexing): - #if not p_indxs: - #self._time_scalar_indexing_structure.append(np.array([self.get_states_number_by_indx(node_indx)], - #dtype=np.int)) - #else: - self._time_scalar_indexing_structure.append( - self.build_time_scalar_indexing_structure_for_a_node(node_indx, p_indxs)) - - def build_transition_scalar_indexing_structure_for_a_node(self, node_indx, parents_indxs): - #M_vector = np.array([self.graph_struct.variables_frame.iloc[node_id, 1], - #self.graph_struct.variables_frame.iloc[node_id, 1].astype(np.int)]) - M_vector = np.array([self.get_states_number_by_indx(node_indx), - self.get_states_number_by_indx(node_indx)]) - M_vector = np.append(M_vector, [self.graph_struct.get_states_number_by_indx(x) for x in parents_indxs]) + + + def build_transition_scalar_indexing_structure_for_a_node(self, node_id: str, parents_vals: typing.List) -> np.ndarray: + """ + Builds an indexing structure for the computation of state transitions values. + + Parameters: + node_id: the node label + parents_vals: the caridinalites of the node's parents + Returns: + a numpy array. + + """ + node_states_number = self.get_states_number(node_id) + M_vector = np.array([node_states_number, + node_states_number]) + M_vector = np.append(M_vector, parents_vals) M_vector = M_vector.cumprod().astype(np.int) return M_vector - def build_transition_scalar_indexing_structure(self): - #parents_indexes_list = self._fancy_indexing - for node_indx, p_indxs in zip(self.graph_struct.list_of_nodes_indexes(), self._fancy_indexing): - self._transition_scalar_indexing_structure.append( - self.build_transition_scalar_indexing_structure_for_a_node(node_indx, p_indxs)) + def build_time_columns_filtering_for_a_node(self, node_indx: int, p_indxs: typing.List) -> np.ndarray: + """ + Builds the necessary structure to filter the desired columns indicated by node_indx and p_indxs in the dataset. + This structute will be used in the computation of the state res times. + Parameters: + node_indx: the index of the node + p_indxs: the indexes of the node's parents + Returns: + a numpy array + """ + return np.append(np.array([node_indx], dtype=np.int), p_indxs).astype(np.int) + + def build_transition_filtering_for_a_node(self, node_indx, p_indxs) -> np.ndarray: + """ + Builds the necessary structure to filter the desired columns indicated by node_indx and p_indxs in the dataset. + This structute will be used in the computation of the state transitions values. + Parameters: + node_indx: the index of the node + p_indxs: the indexes of the node's parents + Returns: + a numpy array + """ + nodes_number = self.graph_struct.total_variables_number + return np.array([node_indx + nodes_number, node_indx, *p_indxs], dtype=np.int) + + def build_p_comb_structure_for_a_node(self, parents_values: typing.List) -> np.ndarray: + """ + Builds the combinatory structure that contains the combinations of all the values contained in parents_values. + + Parameters: + parents_values: the cardinalities of the nodes + Returns: + a numpy matrix containinga grid of the combinations + """ + tmp = [] + for val in parents_values: + tmp.append([x for x in range(val)]) + if len(parents_values) > 0: + parents_comb = np.array(np.meshgrid(*tmp)).T.reshape(-1, len(parents_values)) + if len(parents_values) > 1: + tmp_comb = parents_comb[:, 1].copy() + parents_comb[:, 1] = parents_comb[:, 0].copy() + parents_comb[:, 0] = tmp_comb + else: + parents_comb = np.array([[]], dtype=np.int) + return parents_comb def build_time_columns_filtering_structure(self): - #parents_indexes_list = self._fancy_indexing - for node_indx, p_indxs in zip(self.graph_struct.list_of_nodes_indexes(), self._fancy_indexing): - #if p_indxs.size == 0: - #self._time_filtering.append(np.append(p_indxs, np.array([node_indx], dtype=np.int))) - #else: - self._time_filtering.append(np.append(np.array([node_indx], dtype=np.int), p_indxs).astype(np.int)) + nodes_indxs = self._nodes_indexes + self._time_filtering = [np.append(np.array([node_indx], dtype=np.int), p_indxs).astype(np.int) + for node_indx, p_indxs in zip(nodes_indxs, self._fancy_indexing)] def build_transition_columns_filtering_structure(self): - #parents_indexes_list = self._fancy_indexing nodes_number = self.graph_struct.total_variables_number - for node_indx, p_indxs in zip(self.graph_struct.list_of_nodes_indexes(), self._fancy_indexing): - self._transition_filtering.append(np.array([node_indx + nodes_number, node_indx, *p_indxs], dtype=np.int)) - - def get_nodes(self): - return list(self.graph.nodes) - - def get_edges(self): - return list(self.graph.edges) - - def get_nodes_sorted_by_indx(self): - return self.graph_struct.list_of_nodes_labels() + nodes_indxs = self._nodes_indexes + self._transition_filtering = [np.array([node_indx + nodes_number, node_indx, *p_indxs], dtype=np.int) + for node_indx, p_indxs in zip(nodes_indxs, + self._fancy_indexing)] + + def build_scalar_indexing_structures(self): + parents_values_for_all_nodes = self.get_ordered_by_indx_parents_values_for_all_nodes() + build_transition_scalar_indexing_structure_for_a_node = self.build_transition_scalar_indexing_structure_for_a_node + build_time_scalar_indexing_structure_for_a_node = self.build_time_scalar_indexing_structure_for_a_node + aggr = [(build_transition_scalar_indexing_structure_for_a_node(node_id, p_vals), + build_time_scalar_indexing_structure_for_a_node(node_id, p_vals)) + for node_id, p_vals in + zip(self._nodes_labels, + parents_values_for_all_nodes)] + self._transition_scalar_indexing_structure = [i[0] for i in aggr] + self._time_scalar_indexing_structure = [i[1] for i in aggr] + + def build_p_combs_structure(self): + parents_values_for_all_nodes = self.get_ordered_by_indx_parents_values_for_all_nodes() + p_combs_struct = [self.build_p_comb_structure_for_a_node(p_vals) for p_vals in parents_values_for_all_nodes] + return p_combs_struct def get_parents_by_id(self, node_id): return list(self.graph.predecessors(node_id)) def get_states_number(self, node_id): - return self.graph_struct.get_states_number(node_id) - - def get_states_number_by_indx(self, node_indx): - return self.graph_struct.get_states_number_by_indx(node_indx) - - def get_node_by_index(self, node_indx): - return self.graph_struct.get_node_id(node_indx) + return self.graph.nodes[node_id]['val'] def get_node_indx(self, node_id): return nx.get_node_attributes(self.graph, 'indx')[node_id] - #return self.graph_struct.get_node_indx(node_id) + + def get_positional_node_indx(self, node_id): + return self.graph.nodes[node_id]['pos_indx'] + + @property + def nodes(self): + return self._nodes_labels + + @property + def edges(self): + return list(self.graph.edges) + + @property + def nodes_indexes(self): + return self._nodes_indexes + + @property + def nodes_values(self): + return self._nodes_values @property def time_scalar_indexing_strucure(self): @@ -210,16 +291,8 @@ class NetworkGraph(): def transition_filtering(self): return self._transition_filtering - """def remove_node(self, node_id): - node_indx = self.get_node_indx(node_id) - self.graph_struct.remove_node(node_id) - self.graph.remove_node(node_id) - del self._fancy_indexing[node_indx] - del self._time_filtering[node_indx] - del self._nodes_labels[node_indx] - del self._transition_scalar_indexing_structure[node_indx] - del self._transition_filtering[node_indx] - del self._time_scalar_indexing_structure[node_indx] - del self.aggregated_info_about_nodes_parents[node_indx] - del self._nodes_indexes[node_indx]""" + @property + def p_combs(self): + return self._p_combs_structure + diff --git a/main_package/classes/parameters_estimator.py b/main_package/classes/parameters_estimator.py index ca1b497..18b60b0 100644 --- a/main_package/classes/parameters_estimator.py +++ b/main_package/classes/parameters_estimator.py @@ -1,32 +1,52 @@ -import os -from line_profiler import LineProfiler - -import numba as nb import numpy as np -import network_graph as ng -import sample_path as sp import sets_of_cims_container as acims +import set_of_cims as sofc +import sample_path as sp +import network_graph as ng class ParametersEstimator: + """ + Has the task of computing the cims of particular node given the trajectories in samplepath and the net structure + in the graph net_graph + + :sample_path: the container of the trajectories + :net_graph: the net structure + :single_srt_of_cims: the set of cims object that will hold the cims of the node + """ - def __init__(self, sample_path, net_graph): + def __init__(self, sample_path: sp.SamplePath, net_graph: ng.NetworkGraph): self.sample_path = sample_path self.net_graph = net_graph self.sets_of_cims_struct = None + self.single_set_of_cims = None def init_sets_cims_container(self): - self.sets_of_cims_struct = acims.SetsOfCimsContainer(self.net_graph.get_nodes(), - self.net_graph.get_states_number_of_all_nodes_sorted(), - self.net_graph.get_ordered_by_indx_parents_values_for_all_nodes()) + self.sets_of_cims_struct = acims.SetsOfCimsContainer(self.net_graph.nodes, + self.net_graph.nodes_values, + self.net_graph.get_ordered_by_indx_parents_values_for_all_nodes(), + self.net_graph.p_combs) + + def fast_init(self, node_id: str): + """ + Initializes all the necessary structures for the parameters estimation. + + Parameters: + node_id: the node label + Returns: + void + """ + p_vals = self.net_graph.aggregated_info_about_nodes_parents[2] + node_states_number = self.net_graph.get_states_number(node_id) + self.single_set_of_cims = sofc.SetOfCims(node_id, p_vals, node_states_number, self.net_graph.p_combs) def compute_parameters(self): #print(self.net_graph.get_nodes()) #print(self.amalgamated_cims_struct.sets_of_cims) #enumerate(zip(self.net_graph.get_nodes(), self.amalgamated_cims_struct.sets_of_cims)) - for indx, aggr in enumerate(zip(self.net_graph.get_nodes(), self.sets_of_cims_struct.sets_of_cims)): + for indx, aggr in enumerate(zip(self.net_graph.nodes, self.sets_of_cims_struct.sets_of_cims)): #print(self.net_graph.time_filtering[indx]) #print(self.net_graph.time_scalar_indexing_strucure[indx]) self.compute_state_res_time_for_node(self.net_graph.get_node_indx(aggr[0]), self.sample_path.trajectories.times, @@ -43,75 +63,79 @@ class ParametersEstimator: aggr[1].transition_matrices) aggr[1].build_cims(aggr[1].state_residence_times, aggr[1].transition_matrices) - def compute_parameters_for_node(self, node_id): - pos_index = self.net_graph.graph_struct.get_positional_node_indx(node_id) + def compute_parameters_for_node(self, node_id: str) -> sofc.SetOfCims: + """ + Compute the CIMS of the node identified by the label node_id + + Parameters: + node_id: the node label + Returns: + A setOfCims object filled with the computed CIMS + """ node_indx = self.net_graph.get_node_indx(node_id) - #print("Nodes", self.net_graph.get_nodes()) + state_res_times = self.single_set_of_cims.state_residence_times + transition_matrices = self.single_set_of_cims.transition_matrices + trajectory = self.sample_path.trajectories.trajectory self.compute_state_res_time_for_node(node_indx, self.sample_path.trajectories.times, - self.sample_path.trajectories.trajectory, - self.net_graph.time_filtering[pos_index], - self.net_graph.time_scalar_indexing_strucure[pos_index], - self.sets_of_cims_struct.sets_of_cims[pos_index].state_residence_times) - # print(self.net_graph.transition_filtering[indx]) - # print(self.net_graph.transition_scalar_indexing_structure[indx]) + trajectory, + self.net_graph.time_filtering, + self.net_graph.time_scalar_indexing_strucure, + state_res_times) self.compute_state_transitions_for_a_node(node_indx, self.sample_path.trajectories.complete_trajectory, - self.net_graph.transition_filtering[pos_index], - self.net_graph.transition_scalar_indexing_structure[pos_index], - self.sets_of_cims_struct.sets_of_cims[pos_index].transition_matrices) - self.sets_of_cims_struct.sets_of_cims[pos_index].build_cims( - self.sets_of_cims_struct.sets_of_cims[pos_index].state_residence_times, - self.sets_of_cims_struct.sets_of_cims[pos_index].transition_matrices) - - - def compute_state_res_time_for_node(self, node_indx, times, trajectory, cols_filter, scalar_indexes_struct, T): - #print(times.size) - #print(trajectory) - #print(cols_filter) - #print(scalar_indexes_struct) - #print(T) + self.net_graph.transition_filtering, + self.net_graph.transition_scalar_indexing_structure, + transition_matrices) + self.single_set_of_cims.build_cims(state_res_times, transition_matrices) + return self.single_set_of_cims + + def compute_state_res_time_for_node(self, node_indx: int, times: np.ndarray, trajectory: np.ndarray, + cols_filter: np.ndarray, scalar_indexes_struct: np.ndarray, T: np.ndarray): + """ + Compute the state residence times for a node and fill the matrix T with the results + + Parameters: + node_indx: the index of the node + times: the times deltas vector + trajectory: the trajectory + cols_filter: the columns filtering structure + scalar_indexes_struct: the indexing structure + T: the state residence times vectors + Returns: + void + """ T[:] = np.bincount(np.sum(trajectory[:, cols_filter] * scalar_indexes_struct / scalar_indexes_struct[0], axis=1) .astype(np.int), \ times, minlength=scalar_indexes_struct[-1]).reshape(-1, T.shape[1]) - #print("Done This NODE", T) - - def compute_state_residence_time_for_all_nodes(self): - for node_indx, set_of_cims in enumerate(self.amalgamated_cims_struct.sets_of_cims): - self.compute_state_res_time_for_node(node_indx, self.sample_path.trajectories[0].get_times(), - self.sample_path.trajectories[0].get_trajectory(), self.columns_filtering_structure[node_indx], - self.scalar_indexes_converter[node_indx], set_of_cims.state_residence_times) - def compute_state_transitions_for_a_node(self, node_indx, trajectory, cols_filter, scalar_indexing, M): - #print(node_indx) - #print(trajectory) - #print(cols_filter) - #print(scalar_indexing) - #print(M) + """ + Compute the state residence times for a node and fill the matrices M with the results + + Parameters: + node_indx: the index of the node + times: the times deltas vector + trajectory: the trajectory + cols_filter: the columns filtering structure + scalar_indexes: the indexing structure + M: the state transition matrices + Returns: + void + """ diag_indices = np.array([x * M.shape[1] + x % M.shape[1] for x in range(M.shape[0] * M.shape[1])], dtype=np.int64) trj_tmp = trajectory[trajectory[:, int(trajectory.shape[1] / 2) + node_indx].astype(np.int) >= 0] - #print(trj_tmp) - #print("Summing", np.sum(trj_tmp[:, cols_filter] * scalar_indexing / scalar_indexing[0], axis=1).astype(np.int)) - #print(M.shape[1]) - #print(M.shape[2]) - M[:] = np.bincount(np.sum(trj_tmp[:, cols_filter] * scalar_indexing / scalar_indexing[0], axis=1).astype(np.int), minlength=scalar_indexing[-1]).reshape(-1, M.shape[1], M.shape[2]) M_raveled = M.ravel() M_raveled[diag_indices] = 0 - #print(M_raveled) M_raveled[diag_indices] = np.sum(M, axis=2).ravel() - #print(M_raveled) - #print(M) - def compute_state_transitions_for_all_nodes(self): - for node_indx, set_of_cims in enumerate(self.amalgamated_cims_struct.sets_of_cims): - self.compute_state_transitions_for_a_node(node_indx, self.sample_path.trajectories[0].get_complete_trajectory(), - self.transition_filtering[node_indx], - self.transition_scalar_index_converter[node_indx], set_of_cims.transition_matrices) + + + diff --git a/main_package/classes/sample_path.py b/main_package/classes/sample_path.py index 2d67fe6..49faefe 100644 --- a/main_package/classes/sample_path.py +++ b/main_package/classes/sample_path.py @@ -1,29 +1,41 @@ - +import abstract_sample_path as asam import json_importer as imp import trajectory as tr import structure as st -class SamplePath: +class SamplePath(asam.AbstractSamplePath): """ - Contiene l'aggregazione di una o più traiettorie e la struttura della rete. - Ha il compito dato di costruire tutte gli oggetti Trajectory e l'oggetto Structure - a partire dai dataframe contenuti in self.importer + Aggregates all the informations about the trajectories, the real structure of the sampled net and variables + cardinalites. + Has the task of creating the objects that will contain the mentioned data. + :importer: the Importer objects that will import ad process data + :trajectories: the Trajectory object that will contain all the concatenated trajectories + :structure: the Structure Object that will contain all the structurral infos about the net + :total_variables_count: the number of variables in the net - :importer: l'oggetto Importer che ha il compito di caricare i dataset - :trajectories: lista di oggetti Trajectories - :structure: oggetto Structure """ - def __init__(self, files_path, samples_label, structure_label, variables_label, time_key, variables_key): - self.importer = imp.JsonImporter(files_path, samples_label, structure_label, - variables_label, time_key, variables_key) - self._trajectories = None - self._structure = None + #def __init__(self, files_path: str, samples_label: str, structure_label: str, variables_label: str, time_key: str, + #variables_key: str): + def __init__(self, importer: imp.JsonImporter): + #self.importer =importer + super().__init__(importer) + #self._trajectories = None + #self._structure = None self.total_variables_count = None def build_trajectories(self): + """ + Builds the Trajectory object that will contain all the trajectories. + Clears all the unused dataframes in Importer Object + + Parameters: + void + Returns: + void + """ self.importer.import_data() self._trajectories = \ tr.Trajectory(self.importer.build_list_of_samples_array(self.importer.concatenated_samples), @@ -32,8 +44,20 @@ class SamplePath: self.importer.clear_concatenated_frame() def build_structure(self): + """ + Builds the Structure object that aggregates all the infos about the net. + Parameters: + void + Returns: + void + """ self.total_variables_count = len(self.importer.sorter) - self._structure = st.Structure(self.importer.structure, self.importer.variables, + labels = self.importer.variables[self.importer.variables_key].to_list() + #print("SAMPLE PATH LABELS",labels) + indxs = self.importer.variables.index.to_numpy() + vals = self.importer.variables['Value'].to_numpy() + edges = list(self.importer.structure.to_records(index=False)) + self._structure = st.Structure(labels, indxs, vals, edges, self.total_variables_count) @property @@ -47,12 +71,6 @@ class SamplePath: def total_variables_count(self): return self.total_variables_count - """def build_possible_values_variables_structure(self): - possible_val_list = [] - print(self.importer.variables) - for cardinality in self.importer.variables['Value']: - possible_val_list.append(list(range(0, cardinality))) - self.possible_variables_values = possible_val_list""" diff --git a/main_package/classes/set_of_cims.py b/main_package/classes/set_of_cims.py index cc75015..066dfcd 100644 --- a/main_package/classes/set_of_cims.py +++ b/main_package/classes/set_of_cims.py @@ -1,27 +1,41 @@ import numpy as np +import typing import conditional_intensity_matrix as cim class SetOfCims: """ - Rappresenta la struttura che aggrega tutte le CIM per la variabile di label node_id + Aggregates all the CIMS of the node identified by the label node_id. - :node_id: la label della varibile a cui fanno riferimento le CIM - :ordered_parent_set: il set dei parent della variabile node_id ordinata secondo la property indx - :value: il numero massimo di stati assumibili dalla variabile - :actual_cims: le CIM della varibile + :node_id: the node label + :parents_states_number: the cardinalities of the parents + :node_states_number: the caridinality of the node + :p_combs: the relative p_comb structure + + :state_residence_time: matrix containing all the state residence time vectors for the node + :transition_matrices: matrix containing all the transition matrices for the node + :actaul_cims: the cims of the node """ - def __init__(self, node_id, parents_states_number, node_states_number): + def __init__(self, node_id: str, parents_states_number: typing.List, node_states_number: int, p_combs: np.ndarray): self.node_id = node_id self.parents_states_number = parents_states_number self.node_states_number = node_states_number self.actual_cims = [] self.state_residence_times = None self.transition_matrices = None - self.build_actual_cims_structure() + self.p_combs = p_combs + self.build_times_and_transitions_structures() + + def build_times_and_transitions_structures(self): + """ + Initializes at the correct dimensions the state residence times matrix and the state transition matrices - def build_actual_cims_structure(self): + Parameters: + void + Returns: + void + """ if not self.parents_states_number: self.state_residence_times = np.zeros((1, self.node_states_number), dtype=np.float) self.transition_matrices = np.zeros((1,self.node_states_number, self.node_states_number), dtype=np.int) @@ -31,41 +45,60 @@ class SetOfCims: self.transition_matrices = np.zeros([np.prod(self.parents_states_number), self.node_states_number, self.node_states_number], dtype=np.int) + def build_cims(self, state_res_times: typing.List, transition_matrices: typing.List): + """ + Build the ConditionalIntensityMatrix object given the state residence times and transitions matrices. + Compute the cim coefficients. - def get_cims_number(self): - return len(self.actual_cims) - - def indexes_converter(self, indexes): # Si aspetta array del tipo [2,2] dove - assert len(indexes) == len(self.parents_states_number) - vector_index = 0 - if not indexes: - return vector_index - else: - for indx, value in enumerate(indexes): - vector_index = vector_index*self.parents_states_number[indx] + indexes[indx] - return vector_index - - def build_cims(self, state_res_times, transition_matrices): + Parameters: + state_res_times: the state residence times matrix + transition_matrices: the transition matrices + Returns: + void + """ for state_res_time_vector, transition_matrix in zip(state_res_times, transition_matrices): - #print(state_res_time_vector, transition_matrix) cim_to_add = cim.ConditionalIntensityMatrix(state_res_time_vector, transition_matrix) cim_to_add.compute_cim_coefficients() - #print(cim_to_add) self.actual_cims.append(cim_to_add) + self.actual_cims = np.array(self.actual_cims) self.transition_matrices = None self.state_residence_times = None + def filter_cims_with_mask(self, mask_arr: np.ndarray, comb: typing.List) -> np.ndarray: + """ + Filter the cims contained in the array actual_cims given the boolean mask mask_arr and the index comb. + Parameters: + mask_arr: the boolean mask + comb: the indexes of the selected cims + + Returns: + Array of ConditionalIntensityMatrix + """ + if mask_arr.size <= 1: + return self.actual_cims + else: + tmp_parents_comb_from_ids = np.argwhere(np.all(self.p_combs[:, mask_arr] == comb, axis=1)).ravel() + return self.actual_cims[tmp_parents_comb_from_ids] + + @property def get_cims(self): return self.actual_cims + def get_cims_number(self): + return len(self.actual_cims) +""" def get_cim(self, index): flat_index = self.indexes_converter(index) return self.actual_cims[flat_index] + def indexes_converter(self, indexes): + assert len(indexes) == len(self.parents_states_number) + vector_index = 0 + if not indexes: + return vector_index + else: + for indx, value in enumerate(indexes): + vector_index = vector_index*self.parents_states_number[indx] + indexes[indx] + return vector_index""" + -"""sofc = SetOfCims('Z', [3, 3], 3) -sofc.build_actual_cims_structure() -print(sofc.actual_cims) -print(sofc.actual_cims[0,0]) -print(sofc.actual_cims[1,2]) -#print(sofc.indexes_converter([]))""" diff --git a/main_package/classes/sets_of_cims_container.py b/main_package/classes/sets_of_cims_container.py index a8520a7..cf1cc82 100644 --- a/main_package/classes/sets_of_cims_container.py +++ b/main_package/classes/sets_of_cims_container.py @@ -1,21 +1,21 @@ import set_of_cims as socim - class SetsOfCimsContainer: """ Aggrega un insieme di oggetti SetOfCims """ - # list_of_vars_orders contiene tutte le liste con i parent ordinati secondo il valore indx - def __init__(self, list_of_keys, states_number_per_node, list_of_parents_states_number): - self.sets_of_cims = [] - self.init_cims_structure(list_of_keys, states_number_per_node, list_of_parents_states_number) + def __init__(self, list_of_keys, states_number_per_node, list_of_parents_states_number, p_combs_list): + self.sets_of_cims = None + self.init_cims_structure(list_of_keys, states_number_per_node, list_of_parents_states_number, p_combs_list) #self.states_per_variable = states_number - def init_cims_structure(self, keys, states_number_per_node, list_of_parents_states_number): - for indx, key in enumerate(keys): + def init_cims_structure(self, keys, states_number_per_node, list_of_parents_states_number, p_combs_list): + """for indx, key in enumerate(keys): self.sets_of_cims.append( - socim.SetOfCims(key, list_of_parents_states_number[indx], states_number_per_node[indx])) + socim.SetOfCims(key, list_of_parents_states_number[indx], states_number_per_node[indx]))""" + self.sets_of_cims = [socim.SetOfCims(pair[1], list_of_parents_states_number[pair[0]], states_number_per_node[pair[0]], p_combs_list[pair[0]]) + for pair in enumerate(keys)] def get_set_of_cims(self, node_indx): return self.sets_of_cims[node_indx] @@ -23,13 +23,3 @@ class SetsOfCimsContainer: def get_cims_of_node(self, node_indx, cim_indx): return self.sets_of_cims[node_indx].get_cim(cim_indx) -""" - def get_vars_order(self, node): - return self.actual_cims[node][1] - - def update_state_transition_for_matrix(self, node, which_matrix, element_indx): - self.sets_of_cims[node].update_state_transition(which_matrix, element_indx) - - def update_state_residence_time_for_matrix(self, which_node, which_matrix, which_element, time): - self.sets_of_cims[which_node].update_state_residence_time(which_matrix, which_element, time) -""" diff --git a/main_package/classes/structure.py b/main_package/classes/structure.py index 83d2e47..a462e11 100644 --- a/main_package/classes/structure.py +++ b/main_package/classes/structure.py @@ -1,64 +1,73 @@ +import typing as ty import numpy as np + class Structure: """ - Contiene tutte il informazioni sulla struttura della rete (connessione dei nodi, valori assumibili dalle variabili) + Contains all the infos about the network structure(nodes names, nodes caridinalites, edges...) - :structure_frame: il dataframe contenente le connessioni dei nodi della rete - :variables_frame: il data_frame contenente i valori assumibili dalle variabili e si suppone il corretto ordinamento - rispetto alle colonne del dataset + :nodes_labels_list: the symbolic names of the variables + :nodes_indexes_arr: the indexes of the nodes + :nodes_vals_arr: the cardinalites of the nodes + :edges_list: the edges of the network + :total_variables_number: the total number of variables in the net """ - def __init__(self, structure, variables, total_variables_number): - self.structure_frame = structure - self.variables_frame = variables - self.total_variables_number = total_variables_number - self.name_label = variables.columns.values[0] - self.value_label = variables.columns.values[1] + def __init__(self, nodes_label_list: ty.List, node_indexes_arr: np.ndarray, nodes_vals_arr: np.ndarray, + edges_list: ty.List, total_variables_number: int): + self._nodes_labels_list = nodes_label_list + self._nodes_indexes_arr = node_indexes_arr + self._nodes_vals_arr = nodes_vals_arr + self._edges_list = edges_list + self._total_variables_number = total_variables_number - def list_of_edges(self): - records = self.structure_frame.to_records(index=False) - edges_list = list(records) - return edges_list + @property + def edges(self): + #records = self.structure_frame.to_records(index=False) + #edges_list = list(records) + return self._edges_list - def list_of_nodes_labels(self): - return self.variables_frame[self.name_label].values.tolist() + @property + def nodes_labels(self): + return self._nodes_labels_list - def list_of_nodes_indexes(self): - return list(self.variables_frame.index) + @property + def nodes_indexes(self) -> np.ndarray: + return self._nodes_indexes_arr - def get_node_id(self, node_indx): - return self.variables_frame[self.name_label][node_indx] + @property + def nodes_values(self) -> np.ndarray: + return self._nodes_vals_arr - def get_node_indx(self, node_id): - return self.variables_frame[self.name_label][self.variables_frame[self.name_label] == node_id].index[0] + @property + def total_variables_number(self): + return self._total_variables_number - def get_positional_node_indx(self, node_id): - return np.flatnonzero(self.variables_frame[self.name_label] == node_id)[0] + def get_node_id(self, node_indx: int) -> str: + return self._nodes_labels_list[node_indx] - def get_states_number(self, node): - #print("node", node) - return self.variables_frame[self.value_label][self.get_node_indx(node)] + def get_node_indx(self, node_id: str) -> int: + pos_indx = self._nodes_labels_list.index(node_id) + return self._nodes_indexes_arr[pos_indx] - def get_states_number_by_indx(self, node_indx): - #print(self.value_label) - #print("Node indx", node_indx) - return self.variables_frame[self.value_label][node_indx] + def get_positional_node_indx(self, node_id: str) -> int: + return self._nodes_labels_list.index(node_id) - def total_variables_number(self): - return self.total_variables_number + def get_states_number(self, node: str) -> int: + pos_indx = self._nodes_labels_list.index(node) + return self._nodes_vals_arr[pos_indx] def __repr__(self): - return "Variables:\n" + str(self.variables_frame) + "\nEdges: \n" + str(self.structure_frame) + return "Variables:\n" + str(self._nodes_labels_list) +"\nValues:\n"+ str(self._nodes_vals_arr) +\ + "\nEdges: \n" + str(self._edges_list) def __eq__(self, other): """Overrides the default implementation""" if isinstance(other, Structure): - return self.structure_frame.equals(other.structure_frame) and \ - self.variables_frame.equals(other.variables_frame) + return set(self._nodes_labels_list) == set(other._nodes_labels_list) and \ + np.array_equal(self._nodes_vals_arr, other._nodes_vals_arr) and \ + np.array_equal(self._nodes_indexes_arr, other._nodes_indexes_arr) and \ + self._edges_list == other._edges_list + return NotImplemented - """def remove_node(self, node_id): - self.variables_frame = self.variables_frame[self.variables_frame.Name != node_id] - self.structure_frame = self.structure_frame[(self.structure_frame.From != node_id) & - (self.structure_frame.To != node_id)]""" diff --git a/main_package/classes/structure_estimator.py b/main_package/classes/structure_estimator.py index 63eec6d..be0892b 100644 --- a/main_package/classes/structure_estimator.py +++ b/main_package/classes/structure_estimator.py @@ -1,161 +1,197 @@ -import pandas as pd + import numpy as np import itertools import networkx as nx +from networkx.readwrite import json_graph +import json +import typing from scipy.stats import f as f_dist from scipy.stats import chi2 as chi2_dist - import sample_path as sp import structure as st import network_graph as ng +import conditional_intensity_matrix as condim import parameters_estimator as pe import cache as ch class StructureEstimator: + """ + Has the task of estimating the network structure given the trajectories in samplepath. + + :sample_path: the sample_path object containing the trajectories and the real structure + :exp_test_sign: the significance level for the exponential Hp test + :chi_test_alfa: the significance level for the chi Hp test - def __init__(self, sample_path, exp_test_alfa, chi_test_alfa): + :nodes: the nodes labels + :nodes_vals: the nodes cardinalities + :nodes_indxs: the nodes indexes + :complete_graph: the complete directed graph built using the nodes labels in nodes + :cache: the cache object + """ + + def __init__(self, sample_path: sp.SamplePath, exp_test_alfa: float, chi_test_alfa: float): self.sample_path = sample_path - self.complete_graph_frame = self.build_complete_graph_frame(self.sample_path.structure.list_of_nodes_labels()) - self.complete_graph = self.build_complete_graph(self.sample_path.structure.list_of_nodes_labels()) + self.nodes = np.array(self.sample_path.structure.nodes_labels) + self.nodes_vals = self.sample_path.structure.nodes_values + self.nodes_indxs = self.sample_path.structure.nodes_indexes + self.complete_graph = self.build_complete_graph(self.sample_path.structure.nodes_labels) self.exp_test_sign = exp_test_alfa self.chi_test_alfa = chi_test_alfa self.cache = ch.Cache() - def build_complete_graph_frame(self, node_ids): - complete_frame = pd.DataFrame(itertools.permutations(node_ids, 2)) - complete_frame.columns = ['From', 'To'] - return complete_frame + def build_complete_graph(self, node_ids: typing.List): + """ + Builds a complete directed graph (no self loops) given the nodes labels in the list node_ids: - def build_complete_graph(self, node_ids): + Parameters: + node_ids: the list of nodes labels + Returns: + a complete Digraph Object + """ complete_graph = nx.DiGraph() complete_graph.add_nodes_from(node_ids) complete_graph.add_edges_from(itertools.permutations(node_ids, 2)) return complete_graph - def complete_test(self, test_parent, test_child, parent_set): + def complete_test(self, test_parent: str, test_child: str, parent_set: typing.List, child_states_numb: int, + tot_vars_count: int): + """ + Permorms a complete independence test on the directed graphs G1 = test_child U parent_set + G2 = G1 U test_parent (added as an additional parent of the test_child). + Generates all the necessary structures and datas to perform the tests. + + Parameters: + test_parent: the node label of the test parent + test_child: the node label of the child + parent_set: the common parent set + child_states_numb: the cardinality of the test_child + tot_vars_count_ the total number of variables in the net + Returns: + True iff test_child and test_parent are independent given the sep_set parent_set + False otherwise + """ + #print("Test Parent:", test_parent) + #print("Sep Set", parent_set) p_set = parent_set[:] complete_info = parent_set[:] - complete_info.append(test_parent) - tmp_df = self.complete_graph_frame.loc[self.complete_graph_frame['To'].isin([test_child])] - #tmp_df = self.complete_graph_frame.loc[np.in1d(self.complete_graph_frame['To'], test_child)] - d2 = tmp_df.loc[tmp_df['From'].isin(complete_info)] complete_info.append(test_child) - v2 = self.sample_path.structure.variables_frame.loc[ - self.sample_path.structure.variables_frame['Name'].isin(complete_info)] - - #print(tmp_df) - #d1 = tmp_df.loc[tmp_df['From'].isin(parent_set)] - #parent_set.append(test_child) - #print(parent_set) - """v1 = self.sample_path.structure.variables_frame.loc[self.sample_path.structure.variables_frame['Name'].isin(parent_set)] - s1 = st.Structure(d1, v1, self.sample_path.total_variables_count) - g1 = ng.NetworkGraph(s1) - g1.init_graph()""" - - #parent_set.append(test_parent) - """d2 = tmp_df.loc[tmp_df['From'].isin(parent_set)] - v2 = self.sample_path.structure.variables_frame.loc[self.sample_path.structure.variables_frame['Name'].isin(parent_set)] - s2 = st.Structure(d2, v2, self.sample_path.total_variables_count) - g2 = ng.NetworkGraph(s2) - g2.init_graph()""" - #parent_set.append(test_child) - sofc1 = None - #if not sofc1: - if not p_set: - sofc1 = self.cache.find(test_child) + + parents = np.array(parent_set) + parents = np.append(parents, test_parent) + #print("PARENTS", parents) + #parents.sort() + sorted_parents = self.nodes[np.isin(self.nodes, parents)] + #print("SORTED PARENTS", sorted_parents) + cims_filter = sorted_parents != test_parent + #print("PARENTS NO FROM MASK", cims_filter) + #if not p_set: + #print("EMPTY PSET TRYING TO FIND", test_child) + #sofc1 = self.cache.find(test_child) + #else: + sofc1 = self.cache.find(set(p_set)) + if not sofc1: - #d1 = tmp_df.loc[tmp_df['From'].isin(parent_set)] - d1 = d2[d2.From != test_parent] - - #v1 = self.sample_path.structure.variables_frame.loc[ - #self.sample_path.structure.variables_frame['Name'].isin(parent_set)] - v1 = v2[v2.Name != test_parent] - #print("D1", d1) - #print("V1", v1) - s1 = st.Structure(d1, v1, self.sample_path.total_variables_count) + #print("CACHE MISSS SOFC1") + bool_mask1 = np.isin(self.nodes,complete_info) + #print("Bool mask 1", bool_mask1) + l1 = list(self.nodes[bool_mask1]) + #print("L1", l1) + indxs1 = self.nodes_indxs[bool_mask1] + #print("INDXS 1", indxs1) + vals1 = self.nodes_vals[bool_mask1] + eds1 = list(itertools.product(parent_set,test_child)) + s1 = st.Structure(l1, indxs1, vals1, eds1, tot_vars_count) g1 = ng.NetworkGraph(s1) - g1.init_graph() + g1.fast_init(test_child) p1 = pe.ParametersEstimator(self.sample_path, g1) - p1.init_sets_cims_container() - #print("Computing params for",test_child, test_parent, parent_set) - p1.compute_parameters_for_node(test_child) - sofc1 = p1.sets_of_cims_struct.sets_of_cims[s1.get_positional_node_indx(test_child)] - self.cache.put(test_child,sofc1) + p1.fast_init(test_child) + sofc1 = p1.compute_parameters_for_node(test_child) + #if not p_set: + #self.cache.put(test_child, sofc1) + #else: + self.cache.put(set(p_set), sofc1) sofc2 = None - p_set.append(test_parent) + #p_set.append(test_parent) + p_set.insert(0, test_parent) if p_set: + #print("FULL PSET TRYING TO FIND", p_set) #p_set.append(test_parent) #print("PSET ", p_set) - set_p_set = set(p_set) - sofc2 = self.cache.find(set_p_set) - #print("Sofc2 ", sofc2) + #set_p_set = set(p_set) + sofc2 = self.cache.find(set(p_set)) + #if sofc2: + #print("Sofc2 in CACHE ", sofc2.actual_cims) #print(self.cache.list_of_sets_of_indxs) - - """p2 = pe.ParametersEstimator(self.sample_path, g2) - p2.init_sets_cims_container() - #p2.compute_parameters() - p2.compute_parameters_for_node(test_child) - sofc2 = p2.sets_of_cims_struct.sets_of_cims[s2.get_positional_node_indx(test_child)]""" - if not sofc2 or p_set: - print("Cache Miss SOC2") - #parent_set.append(test_parent) - #d2 = tmp_df.loc[tmp_df['From'].isin(p_set)] - #v2 = self.sample_path.structure.variables_frame.loc[ - #self.sample_path.structure.variables_frame['Name'].isin(parent_set)] - #print("D2", d2) - #print("V2", v2) - #s2 = st.Structure(d2, v2, self.sample_path.total_variables_count) - s2 = st.Structure(d2, v2, self.sample_path.total_variables_count) + if not sofc2: + #print("Cache MISSS SOFC2") + complete_info.append(test_parent) + bool_mask2 = np.isin(self.nodes, complete_info) + #print("BOOL MASK 2",bool_mask2) + l2 = list(self.nodes[bool_mask2]) + #print("L2", l2) + indxs2 = self.nodes_indxs[bool_mask2] + #print("INDXS 2", indxs2) + vals2 = self.nodes_vals[bool_mask2] + eds2 = list(itertools.product(p_set, test_child)) + s2 = st.Structure(l2, indxs2, vals2, eds2, tot_vars_count) g2 = ng.NetworkGraph(s2) - g2.init_graph() + g2.fast_init(test_child) p2 = pe.ParametersEstimator(self.sample_path, g2) - p2.init_sets_cims_container() - # p2.compute_parameters() - p2.compute_parameters_for_node(test_child) - sofc2 = p2.sets_of_cims_struct.sets_of_cims[s2.get_positional_node_indx(test_child)] - if p_set: - #set_p_set = set(p_set) - self.cache.put(set_p_set, sofc2) - end = 0 - increment = self.sample_path.structure.get_states_number(test_parent) - for cim1 in sofc1.actual_cims: - start = end - end = start + increment - for j in range(start, end): + p2.fast_init(test_child) + sofc2 = p2.compute_parameters_for_node(test_child) + self.cache.put(set(p_set), sofc2) + for cim1, p_comb in zip(sofc1.actual_cims, sofc1.p_combs): + #print("GETTING THIS P COMB", p_comb) + #if len(parent_set) > 1: + cond_cims = sofc2.filter_cims_with_mask(cims_filter, p_comb) + #else: + #cond_cims = sofc2.actual_cims + #print("COnd Cims", cond_cims) + for cim2 in cond_cims: #cim2 = sofc2.actual_cims[j] #print(indx) #print("Run Test", i, j) - if not self.independence_test(test_child, cim1, sofc2.actual_cims[j]): + if not self.independence_test(child_states_numb, cim1, cim2): return False return True - def independence_test(self, tested_child, cim1, cim2): - # Fake exp test - r1s = cim1.state_transition_matrix.diagonal() - r2s = cim2.state_transition_matrix.diagonal() - F_stats = cim2.cim.diagonal() / cim1.cim.diagonal() - child_states_numb = self.sample_path.structure.get_states_number(tested_child) - for val in range(0, child_states_numb): # i possibili valori di tested child TODO QUESTO CONTO DEVE ESSERE VETTORIZZATO - #r1 = cim1.state_transition_matrix[val][val] - #r2 = cim2.state_transition_matrix[val][val] - #print("No Test Parent:",cim1.cim[val][val],"With Test Parent", cim2.cim[val][val]) - #F = cim2.cim[val][val] / cim1.cim[val][val] - - #print("Exponential test", F_stats[val], r1s[val], r2s[val]) - #print(f_dist.ppf(1 - self.exp_test_sign / 2, r1, r2)) - #print(f_dist.ppf(self.exp_test_sign / 2, r1, r2)) - if F_stats[val] < f_dist.ppf(self.exp_test_sign / 2, r1s[val], r2s[val]) or \ - F_stats[val] > f_dist.ppf(1 - self.exp_test_sign / 2, r1s[val], r2s[val]): - print("CONDITIONALLY DEPENDENT EXP") + def independence_test(self, child_states_numb: int, cim1: condim.ConditionalIntensityMatrix, + cim2: condim.ConditionalIntensityMatrix): + """ + Compute the actual independence test using two cims. + It is performed first the exponential test and if the null hypothesis is not rejected, + it is permormed also the chi_test. + + Parameters: + child_states_numb: the cardinality of the test child + cim1: a cim belonging to the graph without test parent + cim2: a cim belonging to the graph with test parent + + Returns: + True iff both tests do NOT reject the null hypothesis of indipendence + False otherwise + """ + M1 = cim1.state_transition_matrix + M2 = cim2.state_transition_matrix + r1s = M1.diagonal() + r2s = M2.diagonal() + C1 = cim1.cim + C2 = cim2.cim + F_stats = C2.diagonal() / C1.diagonal() + exp_alfa = self.exp_test_sign + for val in range(0, child_states_numb): + if F_stats[val] < f_dist.ppf(exp_alfa / 2, r1s[val], r2s[val]) or \ + F_stats[val] > f_dist.ppf(1 - exp_alfa / 2, r1s[val], r2s[val]): + #print("CONDITIONALLY DEPENDENT EXP") return False - # fake chi test - M1_no_diag = self.remove_diagonal_elements(cim1.state_transition_matrix) - M2_no_diag = self.remove_diagonal_elements(cim2.state_transition_matrix) - #print("M1 no diag", M1_no_diag) - #print("M2 no diag", M2_no_diag) + #M1_no_diag = self.remove_diagonal_elements(cim1.state_transition_matrix) + #M2_no_diag = self.remove_diagonal_elements(cim2.state_transition_matrix) + M1_no_diag = M1[~np.eye(M1.shape[0], dtype=bool)].reshape(M1.shape[0], -1) + M2_no_diag = M2[~np.eye(M2.shape[0], dtype=bool)].reshape( + M2.shape[0], -1) chi_2_quantile = chi2_dist.ppf(1 - self.chi_test_alfa, child_states_numb - 1) """ Ks = np.sqrt(cim1.state_transition_matrix.diagonal() / cim2.state_transition_matrix.diagonal()) @@ -174,70 +210,108 @@ class StructureEstimator: #print("Chi Quantile", chi_2_quantile) if Chi > chi_2_quantile: #if np.any(chi_stats > chi_2_quantile): - print("CONDITIONALLY DEPENDENT CHI") + #print("CONDITIONALLY DEPENDENT CHI") return False #print("Chi test", Chi) return True - def one_iteration_of_CTPC_algorithm(self, var_id): + def one_iteration_of_CTPC_algorithm(self, var_id: str, tot_vars_count: int): + """ + Performs an iteration of the CTPC algorithm using the node var_id as test_child. + + Parameters: + var_id: the node label of the test child + tot_vars_count: the number of nodes in the net + Returns: + void + """ + print("##################TESTING VAR################", var_id) u = list(self.complete_graph.predecessors(var_id)) - tests_parents_numb = len(u) - #print(u) + #tests_parents_numb = len(u) + #complete_frame = self.complete_graph_frame + #test_frame = complete_frame.loc[complete_frame['To'].isin([var_id])] + child_states_numb = self.sample_path.structure.get_states_number(var_id) b = 0 - #parent_indx = 0 while b < len(u): #for parent_id in u: parent_indx = 0 - while u and parent_indx < tests_parents_numb and b < len(u): - # list_without_test_parent = u.remove(parent_id) + while parent_indx < len(u): + #print("Parent_indx",parent_indx) + #print("LEN U", len(u)) + removed = False - #print("b", b) - #print("Parent Indx", parent_indx) #if not list(self.generate_possible_sub_sets_of_size(u, b, u[parent_indx])): #break S = self.generate_possible_sub_sets_of_size(u, b, u[parent_indx]) #print("U Set", u) #print("S", S) + test_parent = u[parent_indx] + #print("Test Parent", test_parent) for parents_set in S: #print("Parent Set", parents_set) - #print("Test Parent", u[parent_indx]) - if self.complete_test(u[parent_indx], var_id, parents_set): - #print("Removing EDGE:", u[parent_indx], var_id) - self.complete_graph.remove_edge(u[parent_indx], var_id) - #print(self.complete_graph_frame) - """self.complete_graph_frame = \ - self.complete_graph_frame.drop( - self.complete_graph_frame[(self.complete_graph_frame.From == - u[parent_indx]) & (self.complete_graph_frame.To == var_id)].index)""" - self.complete_graph_frame.drop(self.complete_graph_frame[(self.complete_graph_frame.From == u[parent_indx]) & (self.complete_graph_frame.To == var_id)].index) - #print(self.complete_graph_frame) - #u.remove(u[parent_indx]) - del u[parent_indx] + #print("Test Parent", test_parent) + if self.complete_test(test_parent, var_id, parents_set, child_states_numb, tot_vars_count): + #print("Removing EDGE:", test_parent, var_id) + self.complete_graph.remove_edge(test_parent, var_id) + u.remove(test_parent) removed = True + break #else: #parent_indx += 1 if not removed: parent_indx += 1 b += 1 - self.cache.clear() + self.cache.clear() + + def generate_possible_sub_sets_of_size(self, u: typing.List, size: int, parent_label: str): + """ + Creates a list containing all possible subsets of the list u of size size, + that do not contains a the node identified by parent_label. - def generate_possible_sub_sets_of_size(self, u, size, parent_id): - #print("Inside Generate subsets", u) - #print("InsideGenerate Subsets", parent_id) + Parameters: + u: the list of nodes + size: the size of the subsets + parent_label: the nodes to exclude in the subsets generation + Returns: + a Map Object containing a list of lists + + """ list_without_test_parent = u[:] - list_without_test_parent.remove(parent_id) - # u.remove(parent_id) - #print(list(map(list, itertools.combinations(list_without_test_parent, size)))) + list_without_test_parent.remove(parent_label) return map(list, itertools.combinations(list_without_test_parent, size)) + def ctpc_algorithm(self): + """ + Compute the CTPC algorithm. + Parameters: + void + Returns: + void + """ + ctpc_algo = self.one_iteration_of_CTPC_algorithm + total_vars_numb = self.sample_path.total_variables_count + [ctpc_algo(n, total_vars_numb) for n in self.nodes] + + def save_results(self): + """ + Save the estimated Structure to a .json file + + Parameters: + void + Returns: + void + """ + res = json_graph.node_link_data(self.complete_graph) + name = self.sample_path.importer.file_path.rsplit('/',1)[-1] + #print(name) + name = 'results_' + name + with open(name, 'w') as f: + json.dump(res, f) + + def remove_diagonal_elements(self, matrix): m = matrix.shape[0] strided = np.lib.stride_tricks.as_strided s0, s1 = matrix.strides return strided(matrix.ravel()[1:], shape=(m - 1, m), strides=(s0 + s1, s1)).reshape(m, -1) - def ctpc_algorithm(self): - for node_id in self.sample_path.structure.list_of_nodes_labels(): - print("TESTING VAR:", node_id) - self.one_iteration_of_CTPC_algorithm(node_id) - diff --git a/main_package/classes/trajectory.py b/main_package/classes/trajectory.py index ec85c5d..1c5d9ea 100644 --- a/main_package/classes/trajectory.py +++ b/main_package/classes/trajectory.py @@ -4,30 +4,41 @@ import numpy as np class Trajectory: """ - Rappresenta una traiettoria come un numpy_array contenente n-ple (indx, T_k,S_i,.....,Sj) - Offre i metodi utili alla computazione sulla struttura stessa. + Abstracts the infos about a complete set of trajectories, represented as a numpy array of doubles and a numpy matrix + of ints. - Una Trajectory viene costruita a partire da una lista di numpyarray dove ogni elemento rappresenta una colonna - della traj - - :actual_trajectory: il numpy_array contenente la successione di n-ple (indx, T_k,S_i,.....,Sj) + :list_of_columns: the list containing the times array and values matrix + :original_cols_numb: total number of cols in the data + :actual_trajectory: the trajectory containing also the duplicated and shifted values + :times: the array containing the time deltas """ def __init__(self, list_of_columns, original_cols_number): if type(list_of_columns[0][0]) != np.float64: raise TypeError('The first array in the list has to be Times') - #TODO valutare se vale la pena ordinare la lista di numpy array per tipo self.original_cols_number = original_cols_number self._actual_trajectory = np.array(list_of_columns[1:], dtype=np.int).T self._times = np.array(list_of_columns[0], dtype=np.float) @property - def trajectory(self): + def trajectory(self) -> np.ndarray: + """ + Parameters: + void + Returns: + a numpy matrix containing ONLY the original columns values, not the shifted ones + """ return self._actual_trajectory[:, :self.original_cols_number] @property - def complete_trajectory(self): + def complete_trajectory(self) -> np.ndarray: + """ + Parameters: + void + Returns: + a numpy matrix containing all the values + """ return self._actual_trajectory @property diff --git a/main_package/data/esempio_dataset.csv b/main_package/data/esempio_dataset.csv deleted file mode 100644 index 09f00dd..0000000 --- a/main_package/data/esempio_dataset.csv +++ /dev/null @@ -1,1864 +0,0 @@ -,Time,X,Y,Z -0,0.0,2,2,2 -1,0.0795,1,2,2 -2,0.0979,1,2,1 -3,0.1675,1,1,1 -4,0.2181,1,0,1 -5,0.3233,1,0,2 -6,0.4132,1,1,2 -7,0.5572,1,2,2 -8,0.6689,1,2,0 -9,0.7529,2,2,0 -10,0.8074,1,2,0 -11,0.8133,1,2,2 -12,0.8669,0,2,2 -13,0.9124,0,2,1 -14,0.9892,0,2,2 -15,1.0446,2,2,2 -16,1.0976,0,2,2 -17,1.1542,2,2,2 -18,1.1747,2,0,2 -19,1.1875,1,0,2 -20,1.204,1,1,2 -21,1.2138,1,2,2 -22,1.2627,1,2,0 -23,1.3446,1,1,0 -24,1.3733,1,2,0 -25,1.4162,1,2,1 -26,1.4438,1,1,1 -27,1.4645,0,1,1 -28,1.4807,1,1,1 -29,1.6109,1,0,1 -30,1.6348,2,0,1 -31,1.6714,1,0,1 -32,1.7189,1,2,1 -33,1.733,1,1,1 -34,1.8187,1,0,1 -35,1.8947,1,0,2 -36,1.9035,1,0,1 -37,1.9272,0,0,1 -38,1.9505,0,0,0 -39,2.0831,1,0,0 -40,2.136,1,0,1 -41,2.1623,1,0,2 -42,2.1857,1,0,0 -43,2.4266,1,0,2 -44,2.5518,1,0,1 -45,2.7025,0,0,1 -46,2.8049,0,0,0 -47,2.809,1,0,0 -48,2.8325,1,0,1 -49,2.8831,0,0,1 -50,2.9658,0,1,1 -51,3.1578,0,2,1 -52,3.1846,0,1,1 -53,3.3439,2,1,1 -54,3.3693,0,1,1 -55,3.3985,2,1,1 -56,3.4281,0,1,1 -57,3.4766,0,1,2 -58,3.526,0,2,2 -59,3.5697,0,0,2 -60,3.5974,0,2,2 -61,3.6629,1,2,2 -62,3.7055,1,2,0 -63,3.8235,1,0,0 -64,3.9595,1,2,0 -65,4.0246,1,2,1 -66,4.0262,1,2,2 -67,4.1098,1,1,2 -68,4.2318,1,1,0 -69,4.236,1,1,2 -70,4.2592,1,1,0 -71,4.2707,1,0,0 -72,4.3029,1,0,2 -73,4.3524,1,2,2 -74,4.3749,2,2,2 -75,4.3944,0,2,2 -76,4.4505,1,2,2 -77,4.5283,1,1,2 -78,4.5606,1,2,2 -79,4.5979,1,0,2 -80,4.79,1,2,2 -81,4.967,1,0,2 -82,4.9825,1,2,2 -83,4.9867,1,1,2 -84,5.0395,0,1,2 -85,5.1153,0,2,2 -86,5.1724,0,2,1 -87,5.2174,0,1,1 -88,5.2275,1,1,1 -89,5.255,1,0,1 -90,5.3457,1,1,1 -91,5.3758,1,0,1 -92,5.3988,1,1,1 -93,5.6471,1,1,0 -94,5.6582,1,1,2 -95,5.7239,1,1,0 -96,5.784,1,1,2 -97,5.8513,1,2,2 -98,5.99,1,2,0 -99,6.064,1,2,1 -100,6.1111,1,2,0 -101,6.223,1,2,1 -102,6.2316,1,0,1 -103,6.2572,1,2,1 -104,6.2691,1,1,1 -105,6.2935,1,2,1 -106,6.3944,1,2,0 -107,6.4256,1,1,0 -108,6.4348,1,2,0 -109,6.5102,1,1,0 -110,6.5208,1,2,0 -111,6.545,1,2,1 -112,6.5879,1,0,1 -113,6.6558,1,0,0 -114,6.6972,1,0,1 -115,6.7036,1,2,1 -116,6.713,1,2,0 -117,6.7366,1,2,2 -118,6.7522,1,2,0 -119,6.7586,1,0,0 -120,6.8169,1,2,0 -121,6.8337,1,2,2 -122,6.8463,1,2,1 -123,6.9374,1,1,1 -124,7.0371,1,0,1 -125,7.1873,1,0,2 -126,7.2019,2,0,2 -127,7.2859,2,0,1 -128,7.2957,2,0,2 -129,7.3575,1,0,2 -130,7.5165,1,0,1 -131,7.5863,1,0,2 -132,7.6055,1,0,1 -133,7.8261,1,0,0 -134,7.8353,1,2,0 -135,7.8646,1,1,0 -136,7.9157,1,0,0 -137,8.0518,1,2,0 -138,8.3077,2,2,0 -139,8.3346,2,0,0 -140,8.3875,2,2,0 -141,8.5414,0,2,0 -142,8.5571,0,2,1 -143,8.565,0,1,1 -144,8.6032,0,2,1 -145,8.6114,1,2,1 -146,8.6283,1,2,0 -147,8.6577,1,0,0 -148,8.6618,2,0,0 -149,8.6789,0,0,0 -150,8.7114,1,0,0 -151,8.8288,1,0,1 -152,8.8352,1,0,2 -153,8.8676,1,2,2 -154,8.934,2,2,2 -155,8.9999,2,2,1 -156,9.0146,2,1,1 -157,9.1077,2,1,0 -158,9.1677,2,1,1 -159,9.181,2,1,2 -160,9.2049,2,2,2 -161,9.2426,0,2,2 -162,9.3478,2,2,2 -163,9.4303,0,2,2 -164,9.5705,0,2,0 -165,9.6056,2,2,0 -166,9.6112,0,2,0 -167,9.6117,2,2,0 -168,9.663,1,2,0 -169,9.8987,2,2,0 -170,9.9486,2,0,0 -171,9.9563,0,0,0 -172,10.0293,0,2,0 -173,10.0652,2,2,0 -174,10.0683,0,2,0 -175,10.0895,0,1,0 -176,10.1199,0,0,0 -177,10.1656,2,0,0 -178,10.3267,2,2,0 -179,10.3593,1,2,0 -180,10.3677,1,2,2 -181,10.4038,2,2,2 -182,10.4184,2,1,2 -183,10.4541,2,1,1 -184,10.5078,2,2,1 -185,10.5507,2,1,1 -186,10.6822,1,1,1 -187,10.6895,1,1,0 -188,10.7081,1,0,0 -189,10.7297,1,0,1 -190,10.7299,1,2,1 -191,10.7827,1,2,2 -192,10.8673,1,1,2 -193,10.8734,1,2,2 -194,11.0143,1,2,0 -195,11.1236,1,2,2 -196,11.1941,1,2,0 -197,11.2744,2,2,0 -198,11.284,2,2,2 -199,11.3411,1,2,2 -200,11.4209,1,0,2 -201,11.425,1,1,2 -202,11.5115,1,1,0 -203,11.6297,1,2,0 -204,11.6371,0,2,0 -205,11.6628,1,2,0 -206,11.7306,1,1,0 -207,11.8644,1,2,0 -208,11.8744,2,2,0 -209,12.0028,1,2,0 -210,12.0231,1,0,0 -211,12.0381,1,0,2 -212,12.043,1,0,1 -213,12.0625,1,2,1 -214,12.0993,1,1,1 -215,12.1118,1,1,2 -216,12.1937,1,2,2 -217,12.2106,1,2,0 -218,12.2212,2,2,0 -219,12.2472,2,0,0 -220,12.2803,0,0,0 -221,12.304,0,0,1 -222,12.3087,0,0,2 -223,12.3185,1,0,2 -224,12.3413,1,0,1 -225,12.471,1,2,1 -226,12.6159,2,2,1 -227,12.734,2,0,1 -228,12.787,2,2,1 -229,12.8012,2,2,0 -230,12.8591,2,2,2 -231,12.8924,2,2,0 -232,13.0487,2,1,0 -233,13.1244,2,2,0 -234,13.1573,0,2,0 -235,13.2086,0,2,1 -236,13.3017,0,2,2 -237,13.5649,0,2,0 -238,13.6949,0,1,0 -239,13.7259,1,1,0 -240,13.7844,2,1,0 -241,13.8647,1,1,0 -242,13.9843,1,0,0 -243,13.9857,1,2,0 -244,14.0411,2,2,0 -245,14.1539,2,0,0 -246,14.4909,2,0,1 -247,14.6408,2,0,0 -248,14.802,2,0,2 -249,14.9388,2,0,1 -250,14.9523,2,2,1 -251,15.0736,2,1,1 -252,15.1878,2,1,2 -253,15.2382,2,2,2 -254,15.3132,2,1,2 -255,15.3179,2,2,2 -256,15.3212,0,2,2 -257,15.4264,1,2,2 -258,15.6402,2,2,2 -259,15.6767,2,1,2 -260,15.7451,1,1,2 -261,15.7472,1,1,0 -262,15.788,1,1,2 -263,15.7917,1,1,1 -264,15.9557,2,1,1 -265,15.991,2,2,1 -266,16.0447,2,1,1 -267,16.0905,2,2,1 -268,16.1135,2,0,1 -269,16.246,2,0,2 -270,16.2546,0,0,2 -271,16.2986,0,0,1 -272,16.3298,0,2,1 -273,16.3707,0,1,1 -274,16.4046,2,1,1 -275,16.4073,2,1,2 -276,16.4141,2,1,0 -277,16.4351,2,2,0 -278,16.4831,2,1,0 -279,16.5386,2,0,0 -280,16.5466,0,0,0 -281,16.6126,0,0,1 -282,16.6416,0,0,2 -283,16.6434,0,1,2 -284,16.7608,1,1,2 -285,16.8749,1,2,2 -286,16.891,0,2,2 -287,16.892,2,2,2 -288,17.0821,2,1,2 -289,17.1085,0,1,2 -290,17.1594,0,1,1 -291,17.285,0,0,1 -292,17.2895,1,0,1 -293,17.3458,1,0,2 -294,17.3749,2,0,2 -295,17.4182,2,0,0 -296,17.4365,0,0,0 -297,17.5099,0,2,0 -298,17.5182,0,0,0 -299,17.5507,0,2,0 -300,17.5916,0,2,2 -301,17.604,1,2,2 -302,17.7472,1,0,2 -303,17.813,2,0,2 -304,17.8192,2,2,2 -305,17.8344,2,1,2 -306,17.9153,0,1,2 -307,18.0901,0,2,2 -308,18.1454,0,2,1 -309,18.201,0,1,1 -310,18.2141,0,0,1 -311,18.3243,0,2,1 -312,18.3384,0,1,1 -313,18.3472,0,1,0 -314,18.4036,0,0,0 -315,18.409,0,0,1 -316,18.5107,0,2,1 -317,18.5911,1,2,1 -318,18.6044,1,2,2 -319,18.7143,1,0,2 -320,18.7363,1,0,1 -321,18.738,1,0,2 -322,18.8067,2,0,2 -323,18.8258,1,0,2 -324,18.8762,1,0,1 -325,18.8999,1,0,0 -326,18.9042,1,0,1 -327,18.934,1,2,1 -328,18.9645,1,1,1 -329,19.241,1,0,1 -330,19.3245,1,1,1 -331,19.3432,1,0,1 -332,19.3641,1,1,1 -333,19.3711,0,1,1 -334,19.4859,2,1,1 -335,19.537,0,1,1 -336,19.608,0,2,1 -337,19.6275,0,0,1 -338,19.7304,1,0,1 -339,19.7306,1,2,1 -340,19.8026,2,2,1 -341,19.8083,2,1,1 -342,19.843,2,2,1 -343,19.8587,0,2,1 -344,19.9644,0,2,0 -345,20.0163,0,2,1 -346,20.0176,0,2,0 -347,20.0529,1,2,0 -348,20.0739,1,2,2 -349,20.1519,1,2,1 -350,20.388,1,1,1 -351,20.4335,1,0,1 -352,20.4947,1,0,2 -353,20.5781,2,0,2 -354,20.5964,0,0,2 -355,20.6086,0,2,2 -356,20.681,0,1,2 -357,20.6839,0,1,0 -358,20.7439,0,1,2 -359,20.7553,0,2,2 -360,20.7683,2,2,2 -361,20.9932,2,0,2 -362,21.0526,1,0,2 -363,21.1485,1,1,2 -364,21.2072,1,2,2 -365,21.3602,1,2,0 -366,21.4356,1,2,2 -367,21.5536,1,2,0 -368,21.5736,1,1,0 -369,21.5849,1,2,0 -370,21.6194,1,0,0 -371,21.62,1,0,2 -372,21.7054,1,0,1 -373,21.7906,1,1,1 -374,21.847,0,1,1 -375,22.1857,0,0,1 -376,22.2518,0,0,0 -377,22.2627,2,0,0 -378,22.2743,0,0,0 -379,22.3469,0,0,1 -380,22.4748,2,0,1 -381,22.4813,2,0,2 -382,22.4944,2,0,0 -383,22.5494,0,0,0 -384,22.6107,0,0,1 -385,22.6279,0,1,1 -386,22.6969,1,1,1 -387,22.7149,1,1,0 -388,22.7303,1,0,0 -389,22.8614,1,0,1 -390,22.8737,1,0,2 -391,22.8882,1,0,1 -392,22.8958,1,2,1 -393,22.9424,1,0,1 -394,22.981,1,2,1 -395,22.9897,1,2,2 -396,22.9973,1,1,2 -397,23.081,1,2,2 -398,23.1523,2,2,2 -399,23.1983,2,0,2 -400,23.2627,2,2,2 -401,23.3006,2,2,1 -402,23.3421,2,0,1 -403,23.381,0,0,1 -404,23.3978,2,0,1 -405,23.4183,2,0,2 -406,23.4212,1,0,2 -407,23.4245,2,0,2 -408,23.546,2,1,2 -409,23.5486,1,1,2 -410,23.6357,1,2,2 -411,23.8447,1,2,0 -412,23.8738,2,2,0 -413,23.9067,2,2,2 -414,23.9577,2,1,2 -415,23.9735,0,1,2 -416,24.0201,0,0,2 -417,24.0572,0,2,2 -418,24.0905,0,2,0 -419,24.1886,1,2,0 -420,24.2253,1,2,2 -421,24.3021,1,2,1 -422,24.36,1,2,0 -423,24.3677,1,2,1 -424,24.4821,2,2,1 -425,24.485,1,2,1 -426,24.4971,1,2,2 -427,24.5322,1,2,0 -428,24.5709,1,0,0 -429,24.5953,1,0,2 -430,24.6746,1,2,2 -431,24.6918,1,0,2 -432,24.7596,1,1,2 -433,24.9392,1,2,2 -434,24.9557,1,2,1 -435,24.9841,1,2,0 -436,25.0531,1,2,1 -437,25.0655,1,2,2 -438,25.0709,1,1,2 -439,25.1702,1,1,1 -440,25.1886,1,0,1 -441,25.2167,1,2,1 -442,25.3794,1,0,1 -443,25.4413,1,0,2 -444,25.5297,1,0,1 -445,25.5369,1,1,1 -446,25.5486,1,1,0 -447,25.6292,1,0,0 -448,25.7656,0,0,0 -449,25.7678,0,0,1 -450,25.9455,0,2,1 -451,25.9613,0,1,1 -452,26.0037,0,0,1 -453,26.0062,0,0,2 -454,26.026,1,0,2 -455,26.0617,1,2,2 -456,26.0662,1,1,2 -457,26.0778,1,1,0 -458,26.1318,2,1,0 -459,26.1697,2,0,0 -460,26.2511,0,0,0 -461,26.3814,0,0,1 -462,26.3867,0,0,2 -463,26.4286,0,0,0 -464,26.5313,0,1,0 -465,26.599,0,0,0 -466,26.6982,0,0,2 -467,26.7073,1,0,2 -468,26.742,1,2,2 -469,26.8259,1,1,2 -470,26.947,1,1,1 -471,26.9619,0,1,1 -472,26.9777,1,1,1 -473,27.0568,0,1,1 -474,27.3265,0,1,2 -475,27.3511,1,1,2 -476,27.3684,1,1,0 -477,27.3789,1,0,0 -478,27.3849,1,2,0 -479,27.4694,1,2,2 -480,27.5131,1,2,0 -481,27.558,1,0,0 -482,27.5596,0,0,0 -483,27.6507,0,2,0 -484,27.7795,0,2,1 -485,27.8356,1,2,1 -486,27.8576,1,2,2 -487,27.8941,1,1,2 -488,27.936,1,2,2 -489,27.9585,1,1,2 -490,27.9806,1,1,0 -491,28.0413,1,0,0 -492,28.0943,1,0,1 -493,28.1653,1,0,2 -494,28.2819,1,1,2 -495,28.2897,1,1,0 -496,28.2962,1,2,0 -497,28.5013,1,2,2 -498,28.6755,1,0,2 -499,28.7102,1,2,2 -500,28.7214,1,2,0 -501,28.7727,1,2,2 -502,28.8352,1,0,2 -503,28.8509,1,1,2 -504,28.8776,1,2,2 -505,28.9025,1,2,0 -506,28.9258,2,2,0 -507,28.9575,2,1,0 -508,29.0573,0,1,0 -509,29.1549,2,1,0 -510,29.1576,2,2,0 -511,29.1725,2,2,1 -512,29.1854,0,2,1 -513,29.2548,0,2,0 -514,29.2671,2,2,0 -515,29.378,0,2,0 -516,29.4219,0,1,0 -517,29.4451,2,1,0 -518,29.4578,2,2,0 -519,29.4717,0,2,0 -520,29.6018,1,2,0 -521,29.6065,1,2,1 -522,29.7716,1,2,0 -523,29.7819,0,2,0 -524,29.8965,0,0,0 -525,29.9296,0,0,1 -526,29.9317,0,0,2 -527,29.9414,0,1,2 -528,30.0248,2,1,2 -529,30.0491,2,2,2 -530,30.1023,1,2,2 -531,30.1669,1,2,1 -532,30.301,1,2,0 -533,30.3476,1,1,0 -534,30.3549,0,1,0 -535,30.3884,0,0,0 -536,30.4346,0,2,0 -537,30.4746,1,2,0 -538,30.4973,1,1,0 -539,30.5991,2,1,0 -540,30.6394,2,1,2 -541,30.6989,2,2,2 -542,30.7811,0,2,2 -543,30.8491,0,2,1 -544,30.8653,0,2,0 -545,31.1308,0,1,0 -546,31.1957,0,1,2 -547,31.3925,0,2,2 -548,31.4364,2,2,2 -549,31.5823,0,2,2 -550,31.585,0,1,2 -551,31.5959,2,1,2 -552,31.5961,1,1,2 -553,31.641,1,2,2 -554,31.6488,1,1,2 -555,31.7463,1,2,2 -556,31.8959,1,2,0 -557,31.9496,1,2,2 -558,31.9686,1,0,2 -559,31.9973,1,0,1 -560,32.1254,1,2,1 -561,32.2004,1,2,0 -562,32.2289,1,2,2 -563,32.2882,1,0,2 -564,32.3392,1,0,1 -565,32.3789,1,0,0 -566,32.386,1,0,1 -567,32.4003,1,0,2 -568,32.4026,0,0,2 -569,32.4059,0,0,1 -570,32.4545,2,0,1 -571,32.4824,0,0,1 -572,32.5412,0,2,1 -573,32.5465,2,2,1 -574,32.604,2,2,2 -575,32.663,2,0,2 -576,32.6753,2,0,0 -577,32.7262,2,2,0 -578,32.7814,2,2,2 -579,32.833,0,2,2 -580,32.8788,2,2,2 -581,32.8833,2,1,2 -582,32.904,2,2,2 -583,33.0008,2,0,2 -584,33.093,1,0,2 -585,33.0944,2,0,2 -586,33.1435,2,1,2 -587,33.208,2,2,2 -588,33.2809,2,1,2 -589,33.3212,1,1,2 -590,33.359,1,1,0 -591,33.4519,2,1,0 -592,33.4709,1,1,0 -593,33.4803,1,1,2 -594,33.562,0,1,2 -595,33.568,0,1,1 -596,33.5975,0,1,2 -597,33.6277,0,1,0 -598,33.6351,0,0,0 -599,33.68,0,0,2 -600,33.7583,2,0,2 -601,33.7615,2,2,2 -602,33.8483,2,0,2 -603,33.8601,2,2,2 -604,33.8687,2,2,0 -605,33.8735,1,2,0 -606,33.878,1,1,0 -607,34.0028,1,2,0 -608,34.0271,2,2,0 -609,34.0327,0,2,0 -610,34.0627,2,2,0 -611,34.3017,2,2,2 -612,34.3199,2,1,2 -613,34.3202,2,1,0 -614,34.3493,0,1,0 -615,34.4607,2,1,0 -616,34.5047,2,0,0 -617,34.5223,1,0,0 -618,34.562,2,0,0 -619,34.5944,0,0,0 -620,34.5967,2,0,0 -621,34.6872,1,0,0 -622,34.6907,1,0,2 -623,34.8604,1,2,2 -624,34.8742,1,2,0 -625,34.9015,1,1,0 -626,35.0209,1,2,0 -627,35.1462,0,2,0 -628,35.1853,0,2,2 -629,35.2545,0,2,1 -630,35.3178,2,2,1 -631,35.344,0,2,1 -632,35.3626,2,2,1 -633,35.3737,2,0,1 -634,35.4375,2,1,1 -635,35.4394,2,1,0 -636,35.4477,2,1,2 -637,35.4692,1,1,2 -638,35.4881,1,1,0 -639,35.6352,1,2,0 -640,35.6432,1,2,1 -641,35.694,1,2,2 -642,35.7844,1,1,2 -643,35.7948,1,2,2 -644,35.9062,1,2,1 -645,35.9209,1,1,1 -646,35.9299,1,0,1 -647,35.9506,1,2,1 -648,36.0014,2,2,1 -649,36.0043,2,2,2 -650,36.0454,0,2,2 -651,36.0887,0,2,1 -652,36.0961,0,0,1 -653,36.1445,0,0,2 -654,36.1459,2,0,2 -655,36.1695,1,0,2 -656,36.1876,1,0,0 -657,36.3722,1,0,1 -658,36.5983,1,2,1 -659,36.7255,1,2,2 -660,37.0271,0,2,2 -661,37.061,0,2,0 -662,37.1062,0,0,0 -663,37.197,0,0,1 -664,37.4171,0,0,0 -665,37.478,0,0,1 -666,37.5307,0,1,1 -667,37.646,2,1,1 -668,37.6548,2,1,0 -669,37.6695,0,1,0 -670,37.8353,0,1,2 -671,37.8464,0,2,2 -672,37.8633,1,2,2 -673,37.9266,1,0,2 -674,37.9429,2,0,2 -675,38.0492,2,0,1 -676,38.0766,1,0,1 -677,38.1013,2,0,1 -678,38.1448,0,0,1 -679,38.1451,0,2,1 -680,38.1572,0,2,0 -681,38.1902,2,2,0 -682,38.2291,2,0,0 -683,38.2953,0,0,0 -684,38.4535,1,0,0 -685,38.5217,1,0,1 -686,38.5717,0,0,1 -687,38.665,0,1,1 -688,38.6775,0,0,1 -689,38.7657,0,2,1 -690,38.7766,0,1,1 -691,38.8258,0,1,2 -692,38.8516,1,1,2 -693,38.8983,1,1,1 -694,38.9502,1,0,1 -695,38.9958,1,0,2 -696,39.3057,1,0,1 -697,39.3228,1,2,1 -698,39.3403,1,2,2 -699,39.4363,1,1,2 -700,39.4493,1,1,1 -701,39.4618,1,2,1 -702,39.5144,0,2,1 -703,39.5216,0,0,1 -704,39.5819,2,0,1 -705,39.601,2,1,1 -706,39.6222,2,1,0 -707,39.6504,0,1,0 -708,39.6791,0,1,2 -709,39.7127,0,0,2 -710,39.7361,0,0,1 -711,39.7852,0,0,0 -712,39.8897,0,2,0 -713,39.9036,0,0,0 -714,39.9633,2,0,0 -715,39.9806,0,0,0 -716,40.0178,0,2,0 -717,40.1145,2,2,0 -718,40.1716,2,2,2 -719,40.1862,2,2,1 -720,40.3393,2,2,0 -721,40.3975,2,2,1 -722,40.4097,1,2,1 -723,40.4134,1,2,2 -724,40.5548,1,1,2 -725,40.5952,1,2,2 -726,40.598,1,2,0 -727,40.6079,1,1,0 -728,40.6137,1,1,1 -729,40.7164,1,1,2 -730,40.8416,1,1,1 -731,40.8528,1,1,2 -732,40.9449,1,2,2 -733,41.0573,1,0,2 -734,41.1593,1,0,1 -735,41.1688,2,0,1 -736,41.2155,2,1,1 -737,41.2636,2,1,0 -738,41.352,2,2,0 -739,41.421,2,1,0 -740,41.4699,1,1,0 -741,41.5288,1,0,0 -742,41.5463,1,0,1 -743,41.5764,1,2,1 -744,41.5895,1,2,0 -745,41.6683,1,1,0 -746,41.6971,1,1,1 -747,41.7045,1,1,2 -748,41.7223,2,1,2 -749,41.7293,0,1,2 -750,41.8027,2,1,2 -751,41.808,2,1,0 -752,41.8673,2,0,0 -753,41.8678,0,0,0 -754,41.8684,0,0,2 -755,41.8931,1,0,2 -756,41.9085,2,0,2 -757,42.0736,0,0,2 -758,42.1111,1,0,2 -759,42.1254,1,0,1 -760,42.1839,1,0,2 -761,42.1915,1,2,2 -762,42.197,1,0,2 -763,42.2787,0,0,2 -764,42.3331,0,2,2 -765,42.3814,1,2,2 -766,42.4777,1,1,2 -767,42.642,1,1,0 -768,42.6886,0,1,0 -769,42.7757,0,1,2 -770,42.7917,1,1,2 -771,42.7978,1,1,1 -772,42.8293,1,1,0 -773,42.94,2,1,0 -774,43.0639,2,0,0 -775,43.0666,0,0,0 -776,43.1991,0,0,1 -777,43.2138,0,2,1 -778,43.2359,1,2,1 -779,43.2754,1,0,1 -780,43.2877,1,1,1 -781,43.3022,1,1,2 -782,43.3135,2,1,2 -783,43.3401,2,1,0 -784,43.3823,2,2,0 -785,43.4078,2,2,2 -786,43.4915,2,2,0 -787,43.4987,2,2,2 -788,43.5521,1,2,2 -789,43.7632,2,2,2 -790,43.8124,2,0,2 -791,43.8271,1,0,2 -792,43.8332,2,0,2 -793,43.8577,2,0,1 -794,43.8873,2,0,0 -795,43.8901,2,0,2 -796,43.9351,0,0,2 -797,43.9744,0,1,2 -798,44.0585,0,2,2 -799,44.0642,1,2,2 -800,44.1328,1,0,2 -801,44.1856,1,1,2 -802,44.2647,1,2,2 -803,44.2986,0,2,2 -804,44.3459,2,2,2 -805,44.5809,2,1,2 -806,44.658,2,1,1 -807,44.7978,1,1,1 -808,44.8305,1,0,1 -809,44.8628,2,0,1 -810,44.8897,0,0,1 -811,44.8912,1,0,1 -812,44.9644,1,0,2 -813,44.9733,1,0,1 -814,44.9782,1,2,1 -815,44.9786,1,2,2 -816,44.9992,1,1,2 -817,45.0222,1,1,1 -818,45.1632,2,1,1 -819,45.2428,0,1,1 -820,45.3771,0,0,1 -821,45.418,0,0,2 -822,45.47,1,0,2 -823,45.4772,2,0,2 -824,45.4997,2,0,0 -825,45.5748,1,0,0 -826,45.5975,1,2,0 -827,45.6268,1,1,0 -828,45.6412,1,0,0 -829,45.746,2,0,0 -830,45.7851,2,0,1 -831,45.8283,2,2,1 -832,45.8458,2,2,2 -833,45.8994,2,1,2 -834,45.8998,0,1,2 -835,45.9098,1,1,2 -836,46.0034,1,1,1 -837,46.0424,1,0,1 -838,46.1504,1,0,2 -839,46.2049,1,2,2 -840,46.241,2,2,2 -841,46.2579,2,1,2 -842,46.2717,0,1,2 -843,46.2968,1,1,2 -844,46.4702,1,1,1 -845,46.5575,1,1,2 -846,46.6118,1,1,0 -847,46.6158,0,1,0 -848,46.7248,0,0,0 -849,46.7332,1,0,0 -850,46.7405,2,0,0 -851,46.7838,1,0,0 -852,46.8302,1,0,1 -853,47.0207,1,2,1 -854,47.0274,1,2,0 -855,47.0392,1,0,0 -856,47.24,2,0,0 -857,47.3767,2,0,2 -858,47.4601,2,1,2 -859,47.5123,0,1,2 -860,47.5491,2,1,2 -861,47.6347,2,2,2 -862,47.6515,2,1,2 -863,47.7127,0,1,2 -864,47.7303,0,1,0 -865,47.7693,1,1,0 -866,47.7899,1,0,0 -867,47.9561,1,1,0 -868,47.9768,1,2,0 -869,47.9958,0,2,0 -870,48.0401,0,2,1 -871,48.1287,0,2,2 -872,48.1829,0,2,0 -873,48.217,0,2,1 -874,48.2407,0,1,1 -875,48.246,0,1,2 -876,48.2959,1,1,2 -877,48.3505,1,2,2 -878,48.6209,1,0,2 -879,48.6731,0,0,2 -880,48.7934,0,0,0 -881,48.8246,1,0,0 -882,48.8612,1,2,0 -883,48.8862,1,0,0 -884,48.9116,1,0,2 -885,48.9219,1,2,2 -886,48.9355,0,2,2 -887,48.9484,1,2,2 -888,48.9699,1,0,2 -889,48.9819,2,0,2 -890,49.0093,0,0,2 -891,49.0188,0,2,2 -892,49.1049,1,2,2 -893,49.284,2,2,2 -894,49.3282,2,1,2 -895,49.4233,0,1,2 -896,49.4444,0,1,1 -897,49.4768,2,1,1 -898,49.4798,0,1,1 -899,49.4942,1,1,1 -900,49.6552,2,1,1 -901,49.6946,2,2,1 -902,49.7204,0,2,1 -903,49.7859,2,2,1 -904,49.7864,2,0,1 -905,49.8174,1,0,1 -906,49.8615,1,0,2 -907,49.9572,1,2,2 -908,50.032,1,0,2 -909,50.2144,1,2,2 -910,50.2776,1,1,2 -911,50.3029,1,2,2 -912,50.3349,1,2,0 -913,50.3425,1,1,0 -914,50.401,1,2,0 -915,50.4278,1,0,0 -916,50.4624,1,2,0 -917,50.6934,1,1,0 -918,50.7814,1,1,1 -919,50.782,1,2,1 -920,50.8019,1,1,1 -921,50.8166,1,0,1 -922,50.8671,1,0,0 -923,50.8786,2,0,0 -924,50.9204,2,0,1 -925,50.9862,0,0,1 -926,51.0075,0,0,2 -927,51.0086,0,0,1 -928,51.0345,0,0,2 -929,51.0889,0,0,0 -930,51.0902,0,2,0 -931,51.0985,0,2,1 -932,51.2129,1,2,1 -933,51.26,1,2,0 -934,51.3187,0,2,0 -935,51.3518,0,1,0 -936,51.3544,0,2,0 -937,51.469,0,1,0 -938,51.5026,0,2,0 -939,51.5296,0,1,0 -940,51.5636,0,2,0 -941,51.7784,0,0,0 -942,51.8686,0,2,0 -943,51.9565,2,2,0 -944,51.9777,2,2,2 -945,52.1087,2,2,1 -946,52.1398,2,2,2 -947,52.1971,2,0,2 -948,52.2547,2,0,1 -949,52.271,2,0,2 -950,52.3833,2,2,2 -951,52.3951,2,1,2 -952,52.4047,2,1,1 -953,52.4455,2,1,0 -954,52.5004,1,1,0 -955,52.5161,0,1,0 -956,52.544,0,0,0 -957,52.5442,1,0,0 -958,52.5654,1,0,1 -959,52.7153,1,0,2 -960,52.7661,1,2,2 -961,52.7947,1,1,2 -962,52.853,1,0,2 -963,52.8736,1,2,2 -964,53.0678,1,1,2 -965,53.1599,1,1,0 -966,53.1829,1,2,0 -967,53.2851,1,2,1 -968,53.3814,1,1,1 -969,53.4873,1,2,1 -970,53.4959,1,2,2 -971,53.5013,1,0,2 -972,53.5033,1,0,1 -973,53.5558,1,0,0 -974,53.5613,1,0,2 -975,53.5963,1,1,2 -976,53.7209,1,0,2 -977,53.7993,2,0,2 -978,53.8346,2,1,2 -979,53.8433,2,1,0 -980,53.9248,2,1,2 -981,53.9997,0,1,2 -982,54.0045,1,1,2 -983,54.0206,1,2,2 -984,54.0747,1,2,0 -985,54.0778,1,1,0 -986,54.1275,1,0,0 -987,54.1604,1,0,1 -988,54.1697,1,0,2 -989,54.1762,2,0,2 -990,54.282,2,2,2 -991,54.2966,2,1,2 -992,54.3719,1,1,2 -993,54.4028,1,1,0 -994,54.4513,1,0,0 -995,54.4683,1,0,2 -996,54.4821,1,2,2 -997,54.5601,1,0,2 -998,54.5852,1,2,2 -999,54.6504,2,2,2 -1000,54.7021,1,2,2 -1001,54.7282,1,2,1 -1002,54.7325,1,2,2 -1003,54.8082,1,1,2 -1004,54.8417,1,2,2 -1005,55.0424,1,2,1 -1006,55.0656,1,0,1 -1007,55.1133,2,0,1 -1008,55.1711,2,0,0 -1009,55.1827,2,1,0 -1010,55.1833,1,1,0 -1011,55.2378,1,1,2 -1012,55.3369,1,2,2 -1013,55.3409,1,2,0 -1014,55.3535,1,1,0 -1015,55.3602,1,2,0 -1016,55.4003,1,2,2 -1017,55.4586,1,0,2 -1018,55.4904,1,2,2 -1019,55.6486,2,2,2 -1020,55.7091,2,1,2 -1021,55.8616,2,2,2 -1022,55.895,2,0,2 -1023,55.9184,2,2,2 -1024,55.9352,2,2,0 -1025,55.9803,0,2,0 -1026,56.0149,0,0,0 -1027,56.0514,0,0,1 -1028,56.1097,0,0,2 -1029,56.1498,0,2,2 -1030,56.1713,0,0,2 -1031,56.1778,0,1,2 -1032,56.327,0,1,0 -1033,56.4688,0,0,0 -1034,56.6018,2,0,0 -1035,56.6833,1,0,0 -1036,56.754,0,0,0 -1037,56.8233,0,2,0 -1038,56.8711,0,1,0 -1039,56.8764,0,1,1 -1040,56.8817,1,1,1 -1041,56.9164,1,1,2 -1042,56.9465,1,1,1 -1043,56.9787,1,2,1 -1044,57.0522,1,0,1 -1045,57.144,1,2,1 -1046,57.1676,0,2,1 -1047,57.2436,1,2,1 -1048,57.4194,1,0,1 -1049,57.4333,1,0,0 -1050,57.4458,1,0,1 -1051,57.4658,1,1,1 -1052,57.5619,1,1,2 -1053,57.5989,1,1,1 -1054,57.6595,1,1,2 -1055,57.7821,0,1,2 -1056,57.7886,0,2,2 -1057,57.8393,0,1,2 -1058,57.8511,0,2,2 -1059,57.8748,0,2,1 -1060,57.8827,1,2,1 -1061,57.8858,1,2,2 -1062,57.8984,1,0,2 -1063,57.9161,1,2,2 -1064,58.0479,1,2,0 -1065,58.0559,1,2,1 -1066,58.1276,1,2,2 -1067,58.1912,1,0,2 -1068,58.3022,1,0,1 -1069,58.4511,1,0,2 -1070,58.5193,2,0,2 -1071,58.5498,2,1,2 -1072,58.5675,0,1,2 -1073,58.6935,0,1,0 -1074,58.8336,0,2,0 -1075,59.0031,1,2,0 -1076,59.0568,1,0,0 -1077,59.1181,1,0,1 -1078,59.1816,1,0,2 -1079,59.2001,1,1,2 -1080,59.2787,1,1,1 -1081,59.5875,1,1,2 -1082,59.6261,1,1,0 -1083,59.6268,1,2,0 -1084,59.6474,1,2,2 -1085,59.6491,1,1,2 -1086,59.6836,1,1,1 -1087,59.6938,1,2,1 -1088,59.7043,1,2,0 -1089,59.7483,1,1,0 -1090,59.7874,1,1,2 -1091,59.8575,1,1,0 -1092,60.0145,1,2,0 -1093,60.0261,1,0,0 -1094,60.0688,1,2,0 -1095,60.0978,1,0,0 -1096,60.1422,1,0,1 -1097,60.1445,1,2,1 -1098,60.2295,1,2,0 -1099,60.2301,1,1,0 -1100,60.2861,1,1,1 -1101,60.3492,1,1,2 -1102,60.4328,1,1,1 -1103,60.4919,1,0,1 -1104,60.6452,1,2,1 -1105,60.6543,1,1,1 -1106,60.7234,1,1,2 -1107,60.7757,1,1,0 -1108,60.7874,1,2,0 -1109,60.8061,1,1,0 -1110,60.8543,1,0,0 -1111,60.9125,1,0,2 -1112,60.975,1,2,2 -1113,61.0191,1,1,2 -1114,61.025,1,1,0 -1115,61.0868,1,0,0 -1116,61.0906,1,0,2 -1117,61.1139,2,0,2 -1118,61.1255,2,0,0 -1119,61.1752,2,2,0 -1120,61.1765,0,2,0 -1121,61.1912,2,2,0 -1122,61.2947,0,2,0 -1123,61.3013,2,2,0 -1124,61.4061,2,1,0 -1125,61.4336,2,0,0 -1126,61.466,2,0,2 -1127,61.485,2,2,2 -1128,61.5117,0,2,2 -1129,61.5313,2,2,2 -1130,61.6431,0,2,2 -1131,61.8245,1,2,2 -1132,62.0663,1,0,2 -1133,62.118,1,2,2 -1134,62.1497,1,0,2 -1135,62.2431,1,2,2 -1136,62.3672,1,1,2 -1137,62.3731,1,1,0 -1138,62.4261,1,2,0 -1139,62.4462,1,2,2 -1140,62.5013,1,1,2 -1141,62.5064,1,2,2 -1142,62.5692,0,2,2 -1143,62.6088,0,0,2 -1144,62.6144,0,2,2 -1145,62.6446,0,0,2 -1146,62.7838,0,2,2 -1147,62.815,0,1,2 -1148,62.8695,0,2,2 -1149,62.8742,0,1,2 -1150,62.8881,0,2,2 -1151,62.8895,1,2,2 -1152,62.891,1,1,2 -1153,62.9383,1,1,1 -1154,62.9421,2,1,1 -1155,62.9551,0,1,1 -1156,62.9838,0,1,0 -1157,63.0047,2,1,0 -1158,63.0913,2,2,0 -1159,63.1177,0,2,0 -1160,63.1179,2,2,0 -1161,63.298,2,2,2 -1162,63.3074,2,0,2 -1163,63.31,2,0,0 -1164,63.4633,1,0,0 -1165,63.6307,1,0,2 -1166,63.6379,1,0,1 -1167,63.6539,1,0,2 -1168,63.6775,1,2,2 -1169,63.7173,0,2,2 -1170,63.8565,1,2,2 -1171,63.8945,1,2,0 -1172,63.941,1,1,0 -1173,63.9628,0,1,0 -1174,63.9898,0,0,0 -1175,64.0071,0,0,2 -1176,64.053,0,0,1 -1177,64.0998,0,0,2 -1178,64.1664,0,0,1 -1179,64.1757,1,0,1 -1180,64.1792,1,1,1 -1181,64.1891,1,0,1 -1182,64.3983,1,1,1 -1183,64.4431,1,0,1 -1184,64.47,1,2,1 -1185,64.4914,1,2,0 -1186,64.523,1,1,0 -1187,64.5562,1,2,0 -1188,64.5827,1,0,0 -1189,64.5844,1,0,1 -1190,64.6006,1,0,0 -1191,64.9407,2,0,0 -1192,64.9974,2,1,0 -1193,65.0504,2,2,0 -1194,65.1846,2,2,2 -1195,65.33,1,2,2 -1196,65.3614,1,2,1 -1197,65.3623,2,2,1 -1198,65.4658,2,1,1 -1199,65.4681,1,1,1 -1200,65.6767,1,2,1 -1201,65.6902,1,1,1 -1202,65.7844,0,1,1 -1203,65.7868,0,1,2 -1204,65.8823,0,0,2 -1205,65.9254,1,0,2 -1206,65.9518,2,0,2 -1207,66.1833,1,0,2 -1208,66.2696,1,0,1 -1209,66.3522,1,2,1 -1210,66.4081,1,0,1 -1211,66.4536,1,1,1 -1212,66.5094,1,1,0 -1213,66.5724,1,2,0 -1214,66.5959,1,1,0 -1215,66.6136,1,2,0 -1216,66.8624,1,2,1 -1217,66.8874,1,2,0 -1218,66.9112,0,2,0 -1219,66.9434,1,2,0 -1220,66.9865,1,2,1 -1221,66.9927,0,2,1 -1222,67.0154,0,1,1 -1223,67.0561,2,1,1 -1224,67.059,2,1,0 -1225,67.1251,0,1,0 -1226,67.166,2,1,0 -1227,67.1871,2,1,1 -1228,67.2127,2,0,1 -1229,67.2443,2,1,1 -1230,67.3317,2,0,1 -1231,67.3319,2,2,1 -1232,67.4256,0,2,1 -1233,67.4604,1,2,1 -1234,67.6128,1,2,2 -1235,67.6369,0,2,2 -1236,67.6506,0,2,1 -1237,67.6706,0,2,0 -1238,67.7192,0,2,1 -1239,67.8187,0,2,0 -1240,67.8378,0,1,0 -1241,67.8427,0,1,2 -1242,67.9206,0,2,2 -1243,67.9582,0,1,2 -1244,68.1134,2,1,2 -1245,68.1213,0,1,2 -1246,68.2287,2,1,2 -1247,68.2687,2,2,2 -1248,68.2922,2,1,2 -1249,68.3399,2,1,1 -1250,68.3508,0,1,1 -1251,68.5625,0,1,2 -1252,68.6382,1,1,2 -1253,68.6824,1,0,2 -1254,68.6931,2,0,2 -1255,68.7135,0,0,2 -1256,68.7328,0,0,1 -1257,68.8458,0,2,1 -1258,68.9071,0,1,1 -1259,68.9285,0,2,1 -1260,68.9314,0,0,1 -1261,68.9319,0,2,1 -1262,68.9631,2,2,1 -1263,68.9868,2,1,1 -1264,68.9876,2,1,0 -1265,69.0074,2,0,0 -1266,69.0511,2,0,2 -1267,69.0677,2,1,2 -1268,69.0756,2,2,2 -1269,69.1248,2,0,2 -1270,69.1439,0,0,2 -1271,69.1497,2,0,2 -1272,69.2007,2,2,2 -1273,69.2284,2,2,1 -1274,69.2515,0,2,1 -1275,69.2547,0,0,1 -1276,69.2739,0,0,2 -1277,69.2832,0,0,0 -1278,69.2946,2,0,0 -1279,69.3776,2,0,2 -1280,69.3837,2,2,2 -1281,69.3984,2,2,0 -1282,69.4081,1,2,0 -1283,69.4366,1,2,1 -1284,69.5526,1,1,1 -1285,69.6874,1,1,2 -1286,69.703,1,1,1 -1287,69.7244,1,1,2 -1288,69.7497,1,1,1 -1289,69.8551,2,1,1 -1290,69.8718,0,1,1 -1291,69.9079,0,0,1 -1292,70.1237,0,0,0 -1293,70.1311,0,2,0 -1294,70.1343,0,2,1 -1295,70.173,2,2,1 -1296,70.2074,2,2,0 -1297,70.2111,2,2,2 -1298,70.2229,2,0,2 -1299,70.2252,0,0,2 -1300,70.2273,2,0,2 -1301,70.2466,2,0,1 -1302,70.2897,2,0,0 -1303,70.291,2,0,1 -1304,70.3737,0,0,1 -1305,70.4019,2,0,1 -1306,70.4416,0,0,1 -1307,70.5093,0,1,1 -1308,70.5816,0,0,1 -1309,70.6166,0,0,2 -1310,70.6504,0,0,0 -1311,70.7002,0,1,0 -1312,70.7044,0,2,0 -1313,70.7638,0,1,0 -1314,70.833,2,1,0 -1315,70.8635,2,2,0 -1316,70.8789,0,2,0 -1317,70.9021,0,2,1 -1318,70.9126,0,1,1 -1319,70.9639,0,0,1 -1320,71.0243,2,0,1 -1321,71.0255,2,0,2 -1322,71.0661,2,1,2 -1323,71.2639,2,2,2 -1324,71.3872,0,2,2 -1325,71.4153,0,2,1 -1326,71.4335,0,2,0 -1327,71.5769,2,2,0 -1328,71.6025,0,2,0 -1329,71.6647,0,2,1 -1330,71.6716,0,2,0 -1331,71.7172,2,2,0 -1332,71.7296,0,2,0 -1333,71.7552,0,1,0 -1334,71.8533,2,1,0 -1335,71.8844,1,1,0 -1336,71.9072,1,0,0 -1337,72.0414,1,2,0 -1338,72.0973,1,1,0 -1339,72.1028,1,1,2 -1340,72.1127,1,2,2 -1341,72.1238,0,2,2 -1342,72.126,0,1,2 -1343,72.1608,2,1,2 -1344,72.2405,2,2,2 -1345,72.3169,1,2,2 -1346,72.347,1,1,2 -1347,72.3687,1,1,1 -1348,72.5125,0,1,1 -1349,72.6006,2,1,1 -1350,72.6467,2,0,1 -1351,72.677,2,0,2 -1352,72.7177,0,0,2 -1353,72.7537,0,1,2 -1354,72.9848,0,1,0 -1355,72.9945,0,1,2 -1356,73.0426,0,1,0 -1357,73.0788,2,1,0 -1358,73.0914,2,0,0 -1359,73.125,2,1,0 -1360,73.1545,2,0,0 -1361,73.3142,2,0,2 -1362,73.3237,2,2,2 -1363,73.341,2,2,0 -1364,73.3541,2,2,2 -1365,73.4379,1,2,2 -1366,73.4627,2,2,2 -1367,73.5002,2,2,1 -1368,73.5801,2,2,0 -1369,73.6162,2,2,2 -1370,73.7423,2,1,2 -1371,73.7758,2,1,0 -1372,73.7823,2,0,0 -1373,73.8852,2,0,1 -1374,73.9343,2,0,2 -1375,73.959,1,0,2 -1376,73.9628,1,1,2 -1377,73.9795,1,0,2 -1378,74.0485,1,2,2 -1379,74.1278,2,2,2 -1380,74.1932,2,2,1 -1381,74.2277,2,0,1 -1382,74.2403,2,2,1 -1383,74.3338,2,0,1 -1384,74.348,2,0,2 -1385,74.3845,2,0,1 -1386,74.4718,2,0,2 -1387,74.4874,2,2,2 -1388,74.5067,2,1,2 -1389,74.5132,0,1,2 -1390,74.5162,0,1,0 -1391,74.5909,2,1,0 -1392,74.6526,0,1,0 -1393,74.7129,2,1,0 -1394,74.7502,2,0,0 -1395,74.7741,1,0,0 -1396,74.7979,1,0,1 -1397,74.9251,1,0,2 -1398,74.9706,0,0,2 -1399,74.9895,1,0,2 -1400,75.0389,1,0,1 -1401,75.0464,1,2,1 -1402,75.2052,1,1,1 -1403,75.3646,1,1,2 -1404,75.4292,1,1,0 -1405,75.5615,0,1,0 -1406,75.5932,0,1,2 -1407,75.6371,0,1,0 -1408,75.6783,0,2,0 -1409,75.7239,1,2,0 -1410,75.7269,1,0,0 -1411,75.8568,1,2,0 -1412,76.0307,1,2,2 -1413,76.1863,1,1,2 -1414,76.3023,1,1,0 -1415,76.3416,1,2,0 -1416,76.3582,1,0,0 -1417,76.4189,1,0,1 -1418,76.422,1,1,1 -1419,76.4454,1,1,0 -1420,76.5259,1,2,0 -1421,76.5619,2,2,0 -1422,76.5771,1,2,0 -1423,76.5976,1,1,0 -1424,76.6947,1,1,2 -1425,76.7887,1,0,2 -1426,76.864,1,0,0 -1427,76.9518,1,2,0 -1428,76.9746,1,2,1 -1429,77.0618,0,2,1 -1430,77.078,2,2,1 -1431,77.0894,2,0,1 -1432,77.1235,2,2,1 -1433,77.143,2,2,2 -1434,77.1536,0,2,2 -1435,77.1875,0,2,0 -1436,77.2361,1,2,0 -1437,77.2684,1,1,0 -1438,77.273,1,1,1 -1439,77.4354,1,1,0 -1440,77.47,1,2,0 -1441,77.5096,1,2,2 -1442,77.6405,1,1,2 -1443,77.698,1,1,1 -1444,77.8847,1,1,2 -1445,77.9016,1,2,2 -1446,77.9883,1,1,2 -1447,78.0231,1,2,2 -1448,78.0391,0,2,2 -1449,78.1124,0,1,2 -1450,78.1536,0,1,0 -1451,78.1624,1,1,0 -1452,78.2059,1,2,0 -1453,78.2407,1,2,2 -1454,78.2956,0,2,2 -1455,78.4285,0,1,2 -1456,78.4916,0,0,2 -1457,78.5156,0,2,2 -1458,78.54,2,2,2 -1459,78.5535,1,2,2 -1460,78.5978,1,1,2 -1461,78.622,1,2,2 -1462,78.6396,1,2,1 -1463,78.7314,0,2,1 -1464,78.7337,0,0,1 -1465,78.7433,2,0,1 -1466,78.7624,2,0,2 -1467,78.7711,0,0,2 -1468,78.8588,0,1,2 -1469,78.8763,2,1,2 -1470,78.9382,2,2,2 -1471,78.9939,2,1,2 -1472,79.0739,2,2,2 -1473,79.1912,2,0,2 -1474,79.2292,2,1,2 -1475,79.245,2,2,2 -1476,79.2779,1,2,2 -1477,79.3108,1,1,2 -1478,79.3303,1,2,2 -1479,79.4297,1,2,1 -1480,79.4488,1,2,0 -1481,79.4703,1,2,1 -1482,79.5834,1,1,1 -1483,79.608,1,2,1 -1484,79.6472,1,0,1 -1485,79.6723,1,1,1 -1486,79.9281,1,0,1 -1487,79.9525,1,2,1 -1488,79.9537,1,0,1 -1489,79.9748,0,0,1 -1490,80.0405,0,2,1 -1491,80.0744,1,2,1 -1492,80.0997,1,2,0 -1493,80.1552,2,2,0 -1494,80.1919,2,1,0 -1495,80.1944,0,1,0 -1496,80.2094,0,1,2 -1497,80.2907,0,1,0 -1498,80.2966,0,1,1 -1499,80.3072,1,1,1 -1500,80.3283,2,1,1 -1501,80.3622,2,0,1 -1502,80.4092,1,0,1 -1503,80.4514,1,2,1 -1504,80.4986,1,1,1 -1505,80.5212,1,0,1 -1506,80.5615,1,2,1 -1507,80.5697,1,2,2 -1508,80.6034,2,2,2 -1509,80.6184,1,2,2 -1510,80.6192,2,2,2 -1511,80.6204,2,0,2 -1512,80.6353,0,0,2 -1513,80.6483,0,0,1 -1514,80.6546,0,2,1 -1515,80.8419,2,2,1 -1516,80.8505,2,1,1 -1517,81.0409,2,1,0 -1518,81.1001,2,0,0 -1519,81.1104,0,0,0 -1520,81.3016,0,0,2 -1521,81.3639,0,2,2 -1522,81.4545,2,2,2 -1523,81.4746,0,2,2 -1524,81.5442,1,2,2 -1525,81.5589,1,1,2 -1526,81.5928,1,2,2 -1527,81.6212,1,2,1 -1528,81.8477,1,0,1 -1529,81.945,1,2,1 -1530,81.9992,0,2,1 -1531,82.0275,2,2,1 -1532,82.0426,0,2,1 -1533,82.0753,0,0,1 -1534,82.1103,2,0,1 -1535,82.2129,1,0,1 -1536,82.3542,1,1,1 -1537,82.3847,1,1,2 -1538,82.4053,1,1,0 -1539,82.4645,1,1,1 -1540,82.5793,1,2,1 -1541,82.6188,0,2,1 -1542,82.6404,0,0,1 -1543,82.69,2,0,1 -1544,82.7285,1,0,1 -1545,82.7627,1,2,1 -1546,82.9099,1,1,1 -1547,82.924,1,0,1 -1548,82.9388,1,0,2 -1549,82.9457,1,2,2 -1550,83.034,0,2,2 -1551,83.0344,0,2,0 -1552,83.0857,2,2,0 -1553,83.0903,0,2,0 -1554,83.1056,0,1,0 -1555,83.1871,1,1,0 -1556,83.3572,1,0,0 -1557,83.3867,2,0,0 -1558,83.4372,2,2,0 -1559,83.5193,2,1,0 -1560,83.5518,2,0,0 -1561,83.5726,2,0,1 -1562,83.626,1,0,1 -1563,83.642,1,0,2 -1564,83.6792,1,2,2 -1565,83.6894,1,1,2 -1566,83.6962,1,2,2 -1567,83.7851,1,2,0 -1568,83.7994,1,1,0 -1569,83.8917,1,0,0 -1570,83.9414,1,2,0 -1571,83.9695,1,1,0 -1572,84.017,1,1,1 -1573,84.0462,1,0,1 -1574,84.0902,1,1,1 -1575,84.1023,1,1,2 -1576,84.2031,0,1,2 -1577,84.2561,2,1,2 -1578,84.3242,1,1,2 -1579,84.3267,1,2,2 -1580,84.3318,1,2,1 -1581,84.3938,2,2,1 -1582,84.426,0,2,1 -1583,84.5476,0,2,2 -1584,84.5795,0,2,1 -1585,84.584,0,1,1 -1586,84.6349,0,1,2 -1587,84.6461,1,1,2 -1588,84.713,1,1,0 -1589,84.7134,1,2,0 -1590,84.7612,1,0,0 -1591,84.8494,1,2,0 -1592,84.9198,1,2,1 -1593,84.926,1,0,1 -1594,84.9783,1,2,1 -1595,84.9819,1,1,1 -1596,85.1614,2,1,1 -1597,85.2586,0,1,1 -1598,85.317,0,0,1 -1599,85.3222,0,0,2 -1600,85.3521,0,2,2 -1601,85.5275,0,0,2 -1602,85.5536,0,0,0 -1603,85.6113,2,0,0 -1604,85.6716,1,0,0 -1605,85.7768,0,0,0 -1606,85.7817,0,2,0 -1607,85.8483,1,2,0 -1608,86.0393,1,2,2 -1609,86.0648,1,2,1 -1610,86.104,1,0,1 -1611,86.1241,1,2,1 -1612,86.2204,1,1,1 -1613,86.2833,0,1,1 -1614,86.3256,0,0,1 -1615,86.3296,0,0,2 -1616,86.3632,0,1,2 -1617,86.5542,0,1,0 -1618,86.5556,2,1,0 -1619,86.6254,2,2,0 -1620,86.7892,2,2,2 -1621,86.8351,2,2,0 -1622,86.859,2,2,1 -1623,86.8702,2,2,2 -1624,86.9558,2,1,2 -1625,86.9738,2,2,2 -1626,87.0353,2,2,1 -1627,87.1105,2,2,2 -1628,87.1127,1,2,2 -1629,87.2116,1,0,2 -1630,87.2162,1,2,2 -1631,87.2288,1,1,2 -1632,87.2492,1,1,0 -1633,87.4093,1,2,0 -1634,87.4467,1,2,2 -1635,87.5657,2,2,2 -1636,87.6072,0,2,2 -1637,87.6164,0,2,0 -1638,87.6171,0,2,1 -1639,87.6511,2,2,1 -1640,87.7263,2,2,0 -1641,87.7701,2,0,0 -1642,87.7709,2,0,2 -1643,87.786,0,0,2 -1644,87.82,0,2,2 -1645,87.8296,1,2,2 -1646,87.8573,1,2,0 -1647,87.9113,1,1,0 -1648,87.9729,1,2,0 -1649,88.2559,1,2,1 -1650,88.2805,1,1,1 -1651,88.425,1,1,2 -1652,88.5093,0,1,2 -1653,88.5617,1,1,2 -1654,88.7929,1,1,0 -1655,88.8167,1,0,0 -1656,88.8786,1,0,2 -1657,88.9475,1,0,1 -1658,89.1265,1,2,1 -1659,89.1705,0,2,1 -1660,89.235,2,2,1 -1661,89.2529,2,0,1 -1662,89.324,2,0,0 -1663,89.3449,2,0,2 -1664,89.3722,2,2,2 -1665,89.4361,0,2,2 -1666,89.5011,1,2,2 -1667,89.5424,1,0,2 -1668,89.663,1,1,2 -1669,89.8345,1,1,1 -1670,89.8352,1,0,1 -1671,89.8489,1,2,1 -1672,89.8494,1,0,1 -1673,89.851,1,0,0 -1674,90.0136,1,1,0 -1675,90.1333,1,1,1 -1676,90.2379,1,1,2 -1677,90.3825,1,0,2 -1678,90.3992,1,0,1 -1679,90.4015,2,0,1 -1680,90.4291,0,0,1 -1681,90.5112,2,0,1 -1682,90.5311,1,0,1 -1683,90.5844,1,1,1 -1684,90.6863,1,2,1 -1685,90.7048,1,0,1 -1686,90.7435,1,0,2 -1687,90.8132,1,2,2 -1688,90.823,1,0,2 -1689,91.1317,1,0,0 -1690,91.1575,1,0,1 -1691,91.2982,1,0,2 -1692,91.3033,1,0,1 -1693,91.3197,0,0,1 -1694,91.3318,2,0,1 -1695,91.4891,1,0,1 -1696,91.6641,1,0,2 -1697,91.6878,1,2,2 -1698,91.739,1,2,1 -1699,91.7726,1,2,2 -1700,91.842,1,0,2 -1701,91.8435,1,2,2 -1702,92.0026,2,2,2 -1703,92.0465,2,1,2 -1704,92.057,1,1,2 -1705,92.135,1,0,2 -1706,92.1429,0,0,2 -1707,92.1584,0,1,2 -1708,92.268,0,1,0 -1709,92.2848,2,1,0 -1710,92.3066,2,2,0 -1711,92.3335,2,0,0 -1712,92.4529,1,0,0 -1713,92.4653,1,0,2 -1714,92.4965,2,0,2 -1715,92.6314,0,0,2 -1716,92.6466,0,1,2 -1717,92.705,0,2,2 -1718,92.7835,1,2,2 -1719,92.8322,1,1,2 -1720,92.8604,2,1,2 -1721,92.8648,2,1,0 -1722,92.8886,1,1,0 -1723,92.9563,0,1,0 -1724,93.0185,2,1,0 -1725,93.0472,2,0,0 -1726,93.0519,1,0,0 -1727,93.0632,0,0,0 -1728,93.1065,1,0,0 -1729,93.2822,1,0,1 -1730,93.2832,1,0,2 -1731,93.411,1,0,1 -1732,93.4598,1,2,1 -1733,93.4983,1,2,0 -1734,93.5105,1,0,0 -1735,93.5982,1,0,2 -1736,93.6578,1,2,2 -1737,93.7847,1,1,2 -1738,93.8024,2,1,2 -1739,93.8416,2,1,1 -1740,93.8669,2,1,2 -1741,93.9362,2,2,2 -1742,94.1152,2,1,2 -1743,94.1643,0,1,2 -1744,94.2284,1,1,2 -1745,94.2336,1,1,1 -1746,94.333,1,1,2 -1747,94.4192,1,0,2 -1748,94.4331,1,0,1 -1749,94.4962,1,0,0 -1750,94.5353,1,0,2 -1751,94.5411,1,1,2 -1752,94.5555,1,1,0 -1753,94.5742,1,1,2 -1754,94.5876,1,1,1 -1755,94.613,1,1,2 -1756,94.6449,1,1,0 -1757,94.6502,1,0,0 -1758,94.6578,1,0,2 -1759,94.7383,1,2,2 -1760,94.8089,2,2,2 -1761,94.8365,2,2,1 -1762,94.8398,2,0,1 -1763,94.8654,2,0,0 -1764,94.884,0,0,0 -1765,94.887,2,0,0 -1766,94.934,2,0,2 -1767,94.98,1,0,2 -1768,95.016,0,0,2 -1769,95.0688,1,0,2 -1770,95.239,1,2,2 -1771,95.4006,1,1,2 -1772,95.4394,1,1,1 -1773,95.4625,1,2,1 -1774,95.485,1,2,2 -1775,95.4956,1,2,1 -1776,95.5109,1,2,2 -1777,95.5131,2,2,2 -1778,95.6887,1,2,2 -1779,95.717,1,0,2 -1780,95.8036,1,1,2 -1781,95.8356,2,1,2 -1782,95.8415,2,2,2 -1783,95.8573,0,2,2 -1784,95.8639,2,2,2 -1785,95.9058,0,2,2 -1786,95.9096,0,0,2 -1787,95.949,0,2,2 -1788,95.9575,0,1,2 -1789,96.1054,0,2,2 -1790,96.2514,0,1,2 -1791,96.2927,1,1,2 -1792,96.3744,1,1,0 -1793,96.3918,1,1,2 -1794,96.5096,1,1,1 -1795,96.5913,1,2,1 -1796,96.6428,1,2,0 -1797,96.7423,1,1,0 -1798,96.7469,1,0,0 -1799,96.8154,2,0,0 -1800,96.8339,0,0,0 -1801,96.837,0,0,1 -1802,96.8595,0,1,1 -1803,96.8881,0,1,0 -1804,96.9219,0,1,2 -1805,96.9881,0,1,0 -1806,96.9881,1,1,0 -1807,97.0005,1,0,0 -1808,97.0255,1,0,1 -1809,97.0302,1,2,1 -1810,97.0411,1,1,1 -1811,97.0667,1,1,0 -1812,97.0779,1,0,0 -1813,97.1854,1,0,2 -1814,97.2579,1,2,2 -1815,97.3316,1,2,1 -1816,97.4264,0,2,1 -1817,97.446,0,1,1 -1818,97.4573,0,2,1 -1819,97.4874,0,0,1 -1820,97.4917,2,0,1 -1821,97.5029,2,0,2 -1822,97.5248,1,0,2 -1823,97.6817,1,0,1 -1824,97.6897,2,0,1 -1825,97.8303,0,0,1 -1826,97.8513,0,0,2 -1827,97.8675,0,0,1 -1828,97.8792,1,0,1 -1829,97.9157,1,1,1 -1830,98.0196,2,1,1 -1831,98.024,2,1,0 -1832,98.0294,2,1,2 -1833,98.0406,2,1,0 -1834,98.1331,2,0,0 -1835,98.1975,0,0,0 -1836,98.2551,1,0,0 -1837,98.2805,2,0,0 -1838,98.3159,2,0,1 -1839,98.3289,2,2,1 -1840,98.382,1,2,1 -1841,98.3909,1,2,2 -1842,98.5164,1,2,1 -1843,98.5526,2,2,1 -1844,98.5534,2,2,2 -1845,98.5998,2,1,2 -1846,98.6135,2,2,2 -1847,98.6542,1,2,2 -1848,98.7799,1,2,1 -1849,98.8027,0,2,1 -1850,98.8145,1,2,1 -1851,98.8459,1,1,1 -1852,98.9322,1,0,1 -1853,99.124,1,2,1 -1854,99.3102,1,0,1 -1855,99.4348,1,0,2 -1856,99.4377,1,2,2 -1857,99.4955,1,2,1 -1858,99.7188,1,0,1 -1859,99.9105,1,2,1 -1860,99.9363,1,2,0 -1861,99.9492,2,2,0 -1862,100.0,-1,-1,-1 diff --git a/main_package/tests/test_cache.py b/main_package/tests/test_cache.py new file mode 100644 index 0000000..ccb7c21 --- /dev/null +++ b/main_package/tests/test_cache.py @@ -0,0 +1,61 @@ +import unittest +import numpy as np + +import cache as ch +import set_of_cims as soci + + +class TestCache(unittest.TestCase): + + def test_init(self): + c1 = ch.Cache() + self.assertFalse(c1.list_of_sets_of_parents) + self.assertFalse(c1.actual_cache) + + def test_put(self): + c1 = ch.Cache() + pset1 = {'X', 'Y'} + sofc1 = soci.SetOfCims('Z', [], 3, np.array([])) + c1.put(pset1, sofc1) + self.assertEqual(1, len(c1.actual_cache)) + self.assertEqual(1, len(c1.list_of_sets_of_parents)) + self.assertEqual(sofc1, c1.actual_cache[0]) + pset2 = {'X'} + sofc2 = soci.SetOfCims('Z', [], 3, np.array([])) + c1.put(pset2, sofc2) + self.assertEqual(2, len(c1.actual_cache)) + self.assertEqual(2, len(c1.list_of_sets_of_parents)) + self.assertEqual(sofc2, c1.actual_cache[1]) + + def test_find(self): + c1 = ch.Cache() + pset1 = {'X', 'Y'} + sofc1 = soci.SetOfCims('Z', [], 3, np.array([])) + c1.put(pset1, sofc1) + self.assertEqual(1, len(c1.actual_cache)) + self.assertEqual(1, len(c1.list_of_sets_of_parents)) + self.assertIsInstance(c1.find(pset1), soci.SetOfCims) + self.assertEqual(sofc1, c1.find(pset1)) + self.assertIsInstance(c1.find({'Y', 'X'}), soci.SetOfCims) + self.assertEqual(sofc1, c1.find({'Y', 'X'})) + self.assertIsNone(c1.find({'X'})) + + def test_clear(self): + c1 = ch.Cache() + pset1 = {'X', 'Y'} + sofc1 = soci.SetOfCims('Z', [], 3, np.array([])) + c1.put(pset1, sofc1) + self.assertEqual(1, len(c1.actual_cache)) + self.assertEqual(1, len(c1.list_of_sets_of_parents)) + c1.clear() + self.assertFalse(c1.list_of_sets_of_parents) + self.assertFalse(c1.actual_cache) + + + + + + + +if __name__ == '__main__': + unittest.main() diff --git a/main_package/tests/test_json_importer.py b/main_package/tests/test_json_importer.py index d48420e..2bbfef8 100644 --- a/main_package/tests/test_json_importer.py +++ b/main_package/tests/test_json_importer.py @@ -1,25 +1,32 @@ import sys sys.path.append("/Users/Zalum/Desktop/Tesi/CTBN_Project/main_package/classes/") import unittest +import os +import glob import numpy as np import pandas as pd import json_importer as ji +from line_profiler import LineProfiler + import os import json class TestJsonImporter(unittest.TestCase): + @classmethod + def setUpClass(cls) -> None: + cls.read_files = glob.glob(os.path.join('../data', "*.json")) + def test_init(self): - path = os.getcwd() - j1 = ji.JsonImporter(path, 'samples', 'dyn.str', 'variables', 'Time', 'Name') + j1 = ji.JsonImporter(self.read_files[0], 'samples', 'dyn.str', 'variables', 'Time', 'Name') self.assertEqual(j1.samples_label, 'samples') self.assertEqual(j1.structure_label, 'dyn.str') self.assertEqual(j1.variables_label, 'variables') self.assertEqual(j1.time_key, 'Time') self.assertEqual(j1.variables_key, 'Name') - self.assertEqual(j1.files_path, path) + self.assertEqual(j1.file_path, self.read_files[0]) self.assertFalse(j1.df_samples_list) self.assertTrue(j1.variables.empty) self.assertTrue(j1.structure.empty) @@ -31,6 +38,7 @@ class TestJsonImporter(unittest.TestCase): with open('data.json', 'w') as f: json.dump(data_set, f) path = os.getcwd() + path = path + '/data.json' j1 = ji.JsonImporter(path, '', '', '', '', '') imported_data = j1.read_json_file() self.assertTrue(self.ordered(data_set) == self.ordered(imported_data)) @@ -38,28 +46,30 @@ class TestJsonImporter(unittest.TestCase): def test_read_json_file_not_found(self): path = os.getcwd() + path = path + '/data.json' j1 = ji.JsonImporter(path, '', '', '', '', '') - self.assertIsNone(j1.read_json_file()) + self.assertRaises(FileNotFoundError, j1.read_json_file) def test_normalize_trajectories(self): - j1 = ji.JsonImporter('../data', 'samples', 'dyn.str', 'variables', 'Time', 'Name') + j1 = ji.JsonImporter(self.read_files[0], 'samples', 'dyn.str', 'variables', 'Time', 'Name') raw_data = j1.read_json_file() + #print(raw_data) j1.normalize_trajectories(raw_data, 0, j1.samples_label) self.assertEqual(len(j1.df_samples_list), len(raw_data[0][j1.samples_label])) self.assertEqual(list(j1.df_samples_list[0].columns.values)[1:], j1.sorter) def test_normalize_trajectories_wrong_indx(self): - j1 = ji.JsonImporter('../data', 'samples', 'dyn.str', 'variables', 'Time', 'Name') + j1 = ji.JsonImporter(self.read_files[0], 'samples', 'dyn.str', 'variables', 'Time', 'Name') raw_data = j1.read_json_file() - self.assertRaises(IndexError, j1.normalize_trajectories, raw_data, 1, j1.samples_label) + self.assertRaises(IndexError, j1.normalize_trajectories, raw_data, 474, j1.samples_label) def test_normalize_trajectories_wrong_key(self): - j1 = ji.JsonImporter('../data', 'sample', 'dyn.str', 'variables', 'Time', 'Name') + j1 = ji.JsonImporter(self.read_files[0], 'sample', 'dyn.str', 'variables', 'Time', 'Name') raw_data = j1.read_json_file() self.assertRaises(KeyError, j1.normalize_trajectories, raw_data, 0, j1.samples_label) def test_compute_row_delta_single_samples_frame(self): - j1 = ji.JsonImporter('../data', 'samples', 'dyn.str', 'variables', 'Time', 'Name') + j1 = ji.JsonImporter(self.read_files[0], 'samples', 'dyn.str', 'variables', 'Time', 'Name') raw_data = j1.read_json_file() j1.normalize_trajectories(raw_data, 0, j1.samples_label) sample_frame = j1.df_samples_list[0] @@ -72,14 +82,15 @@ class TestJsonImporter(unittest.TestCase): self.assertEqual(sample_frame.shape[0] - 1, new_sample_frame.shape[0]) def test_compute_row_delta_in_all_frames(self): - j1 = ji.JsonImporter('../data', 'samples', 'dyn.str', 'variables', 'Time', 'Name') + j1 = ji.JsonImporter(self.read_files[0], 'samples', 'dyn.str', 'variables', 'Time', 'Name') raw_data = j1.read_json_file() j1.import_trajectories(raw_data) j1.compute_row_delta_in_all_samples_frames(j1.time_key) self.assertEqual(list(j1.df_samples_list[0].columns.values), list(j1.concatenated_samples.columns.values)) + self.assertEqual(list(j1.concatenated_samples.columns.values)[0], j1.time_key) def test_clear_data_frame_list(self): - j1 = ji.JsonImporter('../data', 'samples', 'dyn.str', 'variables', 'Time', 'Name') + j1 = ji.JsonImporter(self.read_files[0], 'samples', 'dyn.str', 'variables', 'Time', 'Name') raw_data = j1.read_json_file() j1.import_trajectories(raw_data) j1.compute_row_delta_in_all_samples_frames(j1.time_key) @@ -92,6 +103,7 @@ class TestJsonImporter(unittest.TestCase): with open('data.json', 'w') as f: json.dump(data_set, f) path = os.getcwd() + path = path + '/data.json' j1 = ji.JsonImporter(path, '', '', '', '', '') raw_data = j1.read_json_file() frame = pd.DataFrame(raw_data) @@ -104,15 +116,20 @@ class TestJsonImporter(unittest.TestCase): os.remove('data.json') def test_import_variables(self): - j1 = ji.JsonImporter('../data', 'samples', 'dyn.str', 'variables', 'Time', 'Name') + j1 = ji.JsonImporter(self.read_files[0], 'samples', 'dyn.str', 'variables', 'Time', 'Name') sorter = ['X', 'Y', 'Z'] raw_data = [{'variables':{"Name": ['Z', 'Y', 'X'], "value": [3, 3, 3]}}] j1.import_variables(raw_data, sorter) self.assertEqual(list(j1.variables[j1.variables_key]), sorter) def test_import_data(self): - j1 = ji.JsonImporter('../data', 'samples', 'dyn.str', 'variables', 'Time', 'Name') - j1.import_data() + j1 = ji.JsonImporter(self.read_files[0], 'samples', 'dyn.str', 'variables', 'Time', 'Name') + lp = LineProfiler() + + lp_wrapper = lp(j1.import_data) + lp_wrapper() + lp.print_stats() + #j1.import_data() self.assertEqual(list(j1.variables[j1.variables_key]), list(j1.concatenated_samples.columns.values[1:len(j1.variables[j1.variables_key]) + 1])) print(j1.variables) diff --git a/main_package/tests/test_networkgraph.py b/main_package/tests/test_networkgraph.py index 438cfa9..49fe550 100644 --- a/main_package/tests/test_networkgraph.py +++ b/main_package/tests/test_networkgraph.py @@ -1,16 +1,23 @@ import unittest +import glob +import os import networkx as nx import numpy as np +import itertools from line_profiler import LineProfiler import sample_path as sp import network_graph as ng +import json_importer as ji + class TestNetworkGraph(unittest.TestCase): @classmethod def setUpClass(cls): - cls.s1 = sp.SamplePath('../data', 'samples', 'dyn.str', 'variables', 'Time', 'Name') + cls.read_files = glob.glob(os.path.join('../data', "*.json")) + cls.importer = ji.JsonImporter(cls.read_files[0], 'samples', 'dyn.str', 'variables', 'Time', 'Name') + cls.s1 = sp.SamplePath(cls.importer) cls.s1.build_trajectories() cls.s1.build_structure() @@ -18,26 +25,26 @@ class TestNetworkGraph(unittest.TestCase): g1 = ng.NetworkGraph(self.s1.structure) self.assertEqual(self.s1.structure, g1.graph_struct) self.assertIsInstance(g1.graph, nx.DiGraph) - #TODO MANCANO TUTTI I TEST DI INIZIALIZZAZIONE DEI DATI PRIVATI della classe aggiungere le property necessarie + self.assertTrue(np.array_equal(g1._nodes_indexes, self.s1.structure.nodes_indexes)) + self.assertListEqual(g1._nodes_labels, self.s1.structure.nodes_labels) + self.assertTrue(np.array_equal(g1._nodes_values, self.s1.structure.nodes_values)) + self.assertIsNone(g1._fancy_indexing) + self.assertIsNone(g1.time_scalar_indexing_strucure) + self.assertIsNone(g1.transition_scalar_indexing_structure) + self.assertIsNone(g1.transition_filtering) + self.assertIsNone(g1.p_combs) def test_add_nodes(self): g1 = ng.NetworkGraph(self.s1.structure) - g1.add_nodes(self.s1.structure.list_of_nodes_labels()) - for n1, n2 in zip(g1.get_nodes(), self.s1.structure.list_of_nodes_labels()): + g1.add_nodes(self.s1.structure.nodes_labels) + for n1, n2 in zip(g1.nodes, self.s1.structure.nodes_labels): self.assertEqual(n1, n2) def test_add_edges(self): g1 = ng.NetworkGraph(self.s1.structure) - g1.add_edges(self.s1.structure.list_of_edges()) - for e in self.s1.structure.list_of_edges(): - self.assertIn(tuple(e), g1.get_edges()) - - """def test_get_ordered_by_indx_set_of_parents(self): - g1 = ng.NetworkGraph(self.s1.structure) - g1.add_nodes(self.s1.structure.list_of_nodes_labels()) - g1.add_edges(self.s1.structure.list_of_edges()) - sorted_par_list_aggregated_info = g1.get_ordered_by_indx_set_of_parents(g1.get_nodes()[2]) - self.test_aggregated_par_list_data(g1, g1.get_nodes()[2], sorted_par_list_aggregated_info)""" + g1.add_edges(self.s1.structure.edges) + for e in self.s1.structure.edges: + self.assertIn(tuple(e), g1.edges) def aux_aggregated_par_list_data(self, graph, node_id, sorted_par_list_aggregated_info): for indx, element in enumerate(sorted_par_list_aggregated_info): @@ -55,12 +62,12 @@ class TestNetworkGraph(unittest.TestCase): def test_get_ord_set_of_par_of_all_nodes(self): g1 = ng.NetworkGraph(self.s1.structure) - g1.add_nodes(self.s1.structure.list_of_nodes_labels()) - g1.add_edges(self.s1.structure.list_of_edges()) + g1.add_nodes(self.s1.structure.nodes_labels) + g1.add_edges(self.s1.structure.edges) sorted_list_of_par_lists = g1.get_ord_set_of_par_of_all_nodes() - for node, par_list in zip(g1.get_nodes_sorted_by_indx(), sorted_list_of_par_lists): + for node, par_list in zip(g1.nodes, sorted_list_of_par_lists): self.aux_aggregated_par_list_data(g1, node, par_list) - + """ def test_get_ordered_by_indx_parents_values_for_all_nodes(self): g1 = ng.NetworkGraph(self.s1.structure) g1.add_nodes(self.s1.structure.list_of_nodes_labels()) @@ -89,67 +96,67 @@ class TestNetworkGraph(unittest.TestCase): self.assertEqual(par_indxs, aggr[1]) def test_build_fancy_indexing_structure_offset(self): - pass #TODO il codice di netgraph deve gestire questo caso + pass #TODO il codice di netgraph deve gestire questo caso""" - def aux_build_time_scalar_indexing_structure_for_a_node(self, graph, node_indx, parents_indxs): - time_scalar_indexing = graph.build_time_scalar_indexing_structure_for_a_node(node_indx, parents_indxs) + def aux_build_time_scalar_indexing_structure_for_a_node(self, graph, node_id, parents_indxs, parents_labels, parents_vals): + time_scalar_indexing = graph.build_time_scalar_indexing_structure_for_a_node(node_id, parents_vals) self.assertEqual(len(time_scalar_indexing), len(parents_indxs) + 1) - merged_list = parents_indxs[:] - merged_list.insert(0, node_indx) - #print(merged_list) + merged_list = parents_labels[:] + merged_list.insert(0, node_id) vals_list = [] for node in merged_list: - vals_list.append(graph.get_states_number_by_indx(node)) + vals_list.append(graph.get_states_number(node)) t_vec = np.array(vals_list) t_vec = t_vec.cumprod() - #print(t_vec) self.assertTrue(np.array_equal(time_scalar_indexing, t_vec)) - def aux_build_transition_scalar_indexing_structure_for_a_node(self, graph, node_indx, parents_indxs): - transition_scalar_indexing = graph.build_transition_scalar_indexing_structure_for_a_node(node_indx, - parents_indxs) - print(transition_scalar_indexing) + def aux_build_transition_scalar_indexing_structure_for_a_node(self, graph, node_id, parents_indxs, parents_labels, + parents_values): + transition_scalar_indexing = graph.build_transition_scalar_indexing_structure_for_a_node(node_id, + parents_values) self.assertEqual(len(transition_scalar_indexing), len(parents_indxs) + 2) - merged_list = parents_indxs[:] - merged_list.insert(0, node_indx) - merged_list.insert(0, node_indx) + merged_list = parents_labels[:] + merged_list.insert(0, node_id) + merged_list.insert(0, node_id) vals_list = [] - for node in merged_list: - vals_list.append(graph.get_states_number_by_indx(node)) + for node_id in merged_list: + vals_list.append(graph.get_states_number(node_id)) m_vec = np.array([vals_list]) m_vec = m_vec.cumprod() self.assertTrue(np.array_equal(transition_scalar_indexing, m_vec)) def test_build_transition_scalar_indexing_structure(self): g1 = ng.NetworkGraph(self.s1.structure) - g1.add_nodes(self.s1.structure.list_of_nodes_labels()) - g1.add_edges(self.s1.structure.list_of_edges()) + g1.add_nodes(self.s1.structure.nodes_labels) + g1.add_edges(self.s1.structure.edges) g1.aggregated_info_about_nodes_parents = g1.get_ord_set_of_par_of_all_nodes() + p_labels = [i[0] for i in g1.aggregated_info_about_nodes_parents] + p_vals = g1.get_ordered_by_indx_parents_values_for_all_nodes() fancy_indx = g1.build_fancy_indexing_structure(0) - print(fancy_indx) - for node_id, p_indxs in zip(g1.graph_struct.list_of_nodes_indexes(), fancy_indx): - self.aux_build_transition_scalar_indexing_structure_for_a_node(g1, node_id, p_indxs) + for node_id, p_i ,p_l, p_v in zip(g1.graph_struct.nodes_labels, fancy_indx, p_labels, p_vals): + self.aux_build_transition_scalar_indexing_structure_for_a_node(g1, node_id, p_i ,p_l, p_v) def test_build_time_scalar_indexing_structure(self): g1 = ng.NetworkGraph(self.s1.structure) - g1.add_nodes(self.s1.structure.list_of_nodes_labels()) - g1.add_edges(self.s1.structure.list_of_edges()) + g1.add_nodes(self.s1.structure.nodes_labels) + g1.add_edges(self.s1.structure.edges) g1.aggregated_info_about_nodes_parents = g1.get_ord_set_of_par_of_all_nodes() fancy_indx = g1.build_fancy_indexing_structure(0) + p_labels = [i[0] for i in g1.aggregated_info_about_nodes_parents] + p_vals = g1.get_ordered_by_indx_parents_values_for_all_nodes() #print(fancy_indx) - for node_id, p_indxs in zip(g1.graph_struct.list_of_nodes_indexes(), fancy_indx): - self.aux_build_time_scalar_indexing_structure_for_a_node(g1, node_id, p_indxs) - + for node_id, p_indxs, p_labels, p_v in zip(g1.graph_struct.nodes_labels, fancy_indx, p_labels, p_vals): + self.aux_build_time_scalar_indexing_structure_for_a_node(g1, node_id, p_indxs, p_labels, p_v) +#TODO Sei arrivato QUI def test_build_time_columns_filtering_structure(self): g1 = ng.NetworkGraph(self.s1.structure) - g1.add_nodes(self.s1.structure.list_of_nodes_labels()) - g1.add_edges(self.s1.structure.list_of_edges()) + g1.add_nodes(self.s1.structure.nodes_labels) + g1.add_edges(self.s1.structure.edges) g1.aggregated_info_about_nodes_parents = g1.get_ord_set_of_par_of_all_nodes() g1._fancy_indexing = g1.build_fancy_indexing_structure(0) g1.build_time_columns_filtering_structure() - print(g1.time_filtering) t_filter = [] - for node_id, p_indxs in zip(g1.get_nodes_sorted_by_indx(), g1._fancy_indexing): + for node_id, p_indxs in zip(g1.nodes, g1._fancy_indexing): single_filter = [] single_filter.append(g1.get_node_indx(node_id)) single_filter.extend(p_indxs) @@ -160,41 +167,72 @@ class TestNetworkGraph(unittest.TestCase): def test_build_transition_columns_filtering_structure(self): g1 = ng.NetworkGraph(self.s1.structure) - g1.add_nodes(self.s1.structure.list_of_nodes_labels()) - g1.add_edges(self.s1.structure.list_of_edges()) + g1.add_nodes(self.s1.structure.nodes_labels) + g1.add_edges(self.s1.structure.edges) g1.aggregated_info_about_nodes_parents = g1.get_ord_set_of_par_of_all_nodes() g1._fancy_indexing = g1.build_fancy_indexing_structure(0) g1.build_transition_columns_filtering_structure() - print(g1.transition_filtering) m_filter = [] - for node_id, p_indxs in zip(g1.get_nodes_sorted_by_indx(), g1._fancy_indexing): + for node_id, p_indxs in zip(g1.nodes, g1._fancy_indexing): single_filter = [] single_filter.append(g1.get_node_indx(node_id) + g1.graph_struct.total_variables_number) single_filter.append(g1.get_node_indx(node_id)) single_filter.extend(p_indxs) m_filter.append(np.array(single_filter)) - print(m_filter) for a1, a2 in zip(g1.transition_filtering, m_filter): self.assertTrue(np.array_equal(a1, a2)) - def test_init_graph(self): + def test_build_p_combs_structure(self): g1 = ng.NetworkGraph(self.s1.structure) - lp = LineProfiler() - lp.add_function(g1.get_ordered_by_indx_set_of_parents) - lp_wrapper = lp(g1.init_graph) - lp_wrapper() - lp.print_stats() - - """def test_remove_node(self): + g1.add_nodes(self.s1.structure.nodes_labels) + g1.add_edges(self.s1.structure.edges) + g1.aggregated_info_about_nodes_parents = g1.get_ord_set_of_par_of_all_nodes() + p_vals = g1.get_ordered_by_indx_parents_values_for_all_nodes() + p_combs = g1.build_p_combs_structure() + + for matrix, p_v in zip(p_combs, p_vals): + p_possible_vals = [] + for val in p_v: + vals = [v for v in range(val)] + p_possible_vals.extend(vals) + comb_struct = set(itertools.product(p_possible_vals,repeat=len(p_v))) + #print(comb_struct) + for comb in comb_struct: + self.assertIn(np.array(comb), matrix) + + def test_fast_init(self): g1 = ng.NetworkGraph(self.s1.structure) + g2 = ng.NetworkGraph(self.s1.structure) g1.init_graph() - g1.remove_node('Y') - print(g1.get_nodes()) - print(g1.get_edges())""" - + for indx, node in enumerate(g1.nodes): + g2.fast_init(node) + self.assertListEqual(g2._fancy_indexing, g1._fancy_indexing[indx]) + self.assertTrue(np.array_equal(g2.time_scalar_indexing_strucure, g1.time_scalar_indexing_strucure[indx])) + self.assertTrue(np.array_equal(g2.transition_scalar_indexing_structure, g1.transition_scalar_indexing_structure[indx])) + self.assertTrue(np.array_equal(g2.time_filtering, g1.time_filtering[indx])) + self.assertTrue(np.array_equal(g2.transition_filtering, g1.transition_filtering[indx])) + self.assertTrue(np.array_equal(g2.p_combs, g1.p_combs[indx])) + + def test_get_parents_by_id(self): + g1 = ng.NetworkGraph(self.s1.structure) + g1.add_nodes(self.s1.structure.nodes_labels) + g1.add_edges(self.s1.structure.edges) + for node in g1.nodes: + self.assertListEqual(g1.get_parents_by_id(node), list(g1.graph.predecessors(node))) + def test_get_states_number(self): + g1 = ng.NetworkGraph(self.s1.structure) + g1.add_nodes(self.s1.structure.nodes_labels) + g1.add_edges(self.s1.structure.edges) + for node, val in zip(g1.nodes, g1.nodes_values): + self.assertEqual(val, g1.get_states_number(node)) + def test_get_node_indx(self): + g1 = ng.NetworkGraph(self.s1.structure) + g1.add_nodes(self.s1.structure.nodes_labels) + g1.add_edges(self.s1.structure.edges) + for node, indx in zip(g1.nodes, g1.nodes_indexes): + self.assertEqual(indx, g1.get_node_indx(node)) -#TODO mancano i test sulle property e sui getters_vari if __name__ == '__main__': unittest.main() diff --git a/main_package/tests/test_parameters_estimator.py b/main_package/tests/test_parameters_estimator.py index b4c70c0..2a161aa 100644 --- a/main_package/tests/test_parameters_estimator.py +++ b/main_package/tests/test_parameters_estimator.py @@ -1,24 +1,69 @@ import unittest import numpy as np +import glob +import os from line_profiler import LineProfiler import network_graph as ng import sample_path as sp -import sets_of_cims_container as scc +import set_of_cims as sofc import parameters_estimator as pe import json_importer as ji -#TODO bisogna trovare un modo per testare i metodi che stimano i tempi e le transizioni per i singoli nodi + class TestParametersEstimatior(unittest.TestCase): @classmethod def setUpClass(cls) -> None: - cls.s1 = sp.SamplePath('../data', 'samples', 'dyn.str', 'variables', 'Time', 'Name') + cls.read_files = glob.glob(os.path.join('../data', "*.json")) + cls.importer = ji.JsonImporter(cls.read_files[0], 'samples', 'dyn.str', 'variables', 'Time', 'Name') + cls.s1 = sp.SamplePath(cls.importer) cls.s1.build_trajectories() cls.s1.build_structure() cls.g1 = ng.NetworkGraph(cls.s1.structure) cls.g1.init_graph() + def test_fast_init(self): + for node in self.g1.nodes: + g = ng.NetworkGraph(self.s1.structure) + g.fast_init(node) + p1 = pe.ParametersEstimator(self.s1, g) + self.assertEqual(p1.sample_path, self.s1) + self.assertEqual(p1.net_graph, g) + self.assertIsNone(p1.single_set_of_cims) + p1.fast_init(node) + self.assertIsInstance(p1.single_set_of_cims, sofc.SetOfCims) + + def test_compute_parameters_for_node(self): + for indx, node in enumerate(self.g1.nodes): + print(node) + g = ng.NetworkGraph(self.s1.structure) + g.fast_init(node) + p1 = pe.ParametersEstimator(self.s1, g) + p1.fast_init(node) + sofc1 = p1.compute_parameters_for_node(node) + sampled_cims = self.aux_import_sampled_cims('dyn.cims') + sc = list(sampled_cims.values()) + #print(sc[indx]) + self.equality_of_cims_of_node(sc[indx], sofc1.actual_cims) + + def equality_of_cims_of_node(self, sampled_cims, estimated_cims): + #print(sampled_cims) + #print(estimated_cims) + self.assertEqual(len(sampled_cims), len(estimated_cims)) + for c1, c2 in zip(sampled_cims, estimated_cims): + self.cim_equality_test(c1, c2.cim) + + def cim_equality_test(self, cim1, cim2): + for r1, r2 in zip(cim1, cim2): + self.assertTrue(np.all(np.isclose(r1, r2, 1e-01, 1e-01) == True)) + + def aux_import_sampled_cims(self, cims_label): + i1 = ji.JsonImporter(self.read_files[0], '', '', '', '', '') + raw_data = i1.read_json_file() + return i1.import_sampled_cims(raw_data, 0, cims_label) + + """ def test_init(self): self.aux_test_init(self.s1, self.g1) @@ -38,47 +83,6 @@ class TestParametersEstimatior(unittest.TestCase): def test_compute_parameters(self): self.aux_test_compute_parameters(self.s1, self.g1) - - def aux_test_compute_parameters(self, sample_p, graph): - pe1 = pe.ParametersEstimator(sample_p, graph) - pe1.init_sets_cims_container() - pe1.compute_parameters() - samples_cims = self.aux_import_sampled_cims('dyn.cims') - for indx, sc in enumerate(samples_cims.values()): - self.equality_of_cims_of_node(sc, pe1.sets_of_cims_struct.get_set_of_cims(indx).get_cims()) - - def equality_of_cims_of_node(self, sampled_cims, estimated_cims): - self.assertEqual(len(sampled_cims), len(estimated_cims)) - for c1, c2 in zip(sampled_cims, estimated_cims): - self.cim_equality_test(c1, c2.cim) - - def cim_equality_test(self, cim1, cim2): - for r1, r2 in zip(cim1, cim2): - self.assertTrue(np.all(np.isclose(r1, r2, 1e-01, 1e-01) == True)) - - def test_compute_parameters_for_node(self):#TODO Questo non è un test - self.g1.remove_node('Y') - print(self.g1.time_filtering) - pe1 = pe.ParametersEstimator(self.s1, self.g1) - pe1.init_sets_cims_container() - lp = LineProfiler() - #lp.add_function(pe1.init_sets_cims_container) - lp_wrapper = lp(pe1.compute_parameters_for_node) - lp_wrapper('X') - lp.print_stats() - #pe1.init_sets_cims_container() - #pe1.compute_parameters_for_node('Y') - print(pe1.sets_of_cims_struct.get_set_of_cims(0).actual_cims) - - - def aux_import_sampled_cims(self, cims_label): - i1 = ji.JsonImporter('../data', '', '', '', '', '') - raw_data = i1.read_json_file() - return i1.import_sampled_cims(raw_data, 0, cims_label) - - - - - + """ if __name__ == '__main__': unittest.main() diff --git a/main_package/tests/sample_path_test.py b/main_package/tests/test_sample_path.py similarity index 67% rename from main_package/tests/sample_path_test.py rename to main_package/tests/test_sample_path.py index 34513b8..951c597 100644 --- a/main_package/tests/sample_path_test.py +++ b/main_package/tests/test_sample_path.py @@ -1,4 +1,7 @@ import unittest +import glob +import os +import json_importer as ji import sample_path as sp import trajectory as tr import structure as st @@ -6,8 +9,13 @@ import structure as st class TestSamplePath(unittest.TestCase): + @classmethod + def setUpClass(cls) -> None: + cls.read_files = glob.glob(os.path.join('../data', "*.json")) + cls.importer = ji.JsonImporter(cls.read_files[0], 'samples', 'dyn.str', 'variables', 'Time', 'Name') + def test_init(self): - s1 = sp.SamplePath('../data', 'samples', 'dyn.str', 'variables', 'Time', 'Name') + s1 = sp.SamplePath(self.importer) s1.build_trajectories() self.assertIsNotNone(s1.trajectories) self.assertIsInstance(s1.trajectories, tr.Trajectory) diff --git a/main_package/tests/test_setofcims.py b/main_package/tests/test_setofcims.py index c685b15..ae0f212 100644 --- a/main_package/tests/test_setofcims.py +++ b/main_package/tests/test_setofcims.py @@ -11,64 +11,84 @@ class TestSetOfCims(unittest.TestCase): def setUpClass(cls) -> None: cls.node_id = 'X' cls.possible_cardinalities = [2, 3] - #cls.possible_states = [[0,1], [0, 1, 2]] + cls.possible_states = [[0,1], [0, 1, 2]] cls.node_states_number = range(2, 4) def test_init(self): # empty parent set for sn in self.node_states_number: - self.aux_test_init(self.node_id, [], sn) + p_combs = self.build_p_comb_structure_for_a_node([]) + self.aux_test_init(self.node_id, [], sn, p_combs) # one parent for sn in self.node_states_number: for p in itertools.product(self.possible_cardinalities, repeat=1): - self.aux_test_init(self.node_id, list(p), sn) + p_combs = self.build_p_comb_structure_for_a_node(list(p)) + self.aux_test_init(self.node_id, list(p), sn, p_combs) #two parents for sn in self.node_states_number: for p in itertools.product(self.possible_cardinalities, repeat=2): - self.aux_test_init(self.node_id, list(p), sn) + p_combs = self.build_p_comb_structure_for_a_node(list(p)) + self.aux_test_init(self.node_id, list(p), sn, p_combs) - def test_indexes_converter(self): + def test_build_cims(self): # empty parent set for sn in self.node_states_number: - self.aux_test_indexes_converter(self.node_id, [], sn) + p_combs = self.build_p_comb_structure_for_a_node([]) + self.aux_test_build_cims(self.node_id, [], sn, p_combs) # one parent for sn in self.node_states_number: for p in itertools.product(self.possible_cardinalities, repeat=1): - self.aux_test_init(self.node_id, list(p), sn) - # two parents + p_combs = self.build_p_comb_structure_for_a_node(list(p)) + self.aux_test_build_cims(self.node_id, list(p), sn, p_combs) + #two parents for sn in self.node_states_number: for p in itertools.product(self.possible_cardinalities, repeat=2): - self.aux_test_init(self.node_id, list(p), sn) + p_combs = self.build_p_comb_structure_for_a_node(list(p)) + self.aux_test_build_cims(self.node_id, list(p), sn, p_combs) - def aux_test_indexes_converter(self, node_id, parents_states_number, node_states_number): - sofcims = soci.SetOfCims(node_id, parents_states_number, node_states_number) - if not parents_states_number: - self.assertEqual(sofcims.indexes_converter([]), 0) - else: - parents_possible_values = [] - for cardi in parents_states_number: - parents_possible_values.extend(range(0, cardi)) - for p in itertools.permutations(parents_possible_values, len(parents_states_number)): - self.assertEqual(sofcims.indexes_converter(list(p)), np.ravel_multi_index(list(p), parents_states_number)) - - def test_build_cims(self): + def test_filter_cims_with_mask(self): + p_combs = self.build_p_comb_structure_for_a_node(self.possible_cardinalities) + sofc1 = soci.SetOfCims('X', self.possible_cardinalities, 3, p_combs) state_res_times_list = [] transition_matrices_list = [] - so1 = soci.SetOfCims('X',[3], 3) - for i in range(0, 3): + for i in range(len(p_combs)): state_res_times = np.random.rand(1, 3)[0] state_res_times = state_res_times * 1000 state_transition_matrix = np.random.randint(1, 10000, (3, 3)) state_res_times_list.append(state_res_times) transition_matrices_list.append(state_transition_matrix) + sofc1.build_cims(state_res_times_list, transition_matrices_list) + for length_of_mask in range(3): + for mask in list(itertools.permutations([True, False],r=length_of_mask)): + m = np.array(mask) + for parent_value in range(self.possible_cardinalities[0]): + cims = sofc1.filter_cims_with_mask(m, [parent_value]) + if length_of_mask == 0 or length_of_mask == 1: + self.assertTrue(np.array_equal(sofc1.actual_cims, cims)) + else: + indxs = self.another_filtering_method(p_combs, m, [parent_value]) + self.assertTrue(np.array_equal(cims, sofc1.actual_cims[indxs])) + + def aux_test_build_cims(self, node_id, p_values, node_states, p_combs): + state_res_times_list = [] + transition_matrices_list = [] + so1 = soci.SetOfCims(node_id, p_values, node_states, p_combs) + for i in range(len(p_combs)): + state_res_times = np.random.rand(1, node_states)[0] + state_res_times = state_res_times * 1000 + state_transition_matrix = np.random.randint(1, 10000, (node_states, node_states)) + state_res_times_list.append(state_res_times) + transition_matrices_list.append(state_transition_matrix) so1.build_cims(state_res_times_list, transition_matrices_list) self.assertEqual(len(state_res_times_list), so1.get_cims_number()) + self.assertIsInstance(so1.actual_cims, np.ndarray) self.assertIsNone(so1.transition_matrices) self.assertIsNone(so1.state_residence_times) - def aux_test_init(self, node_id, parents_states_number, node_states_number): - sofcims = soci.SetOfCims(node_id, parents_states_number, node_states_number) + def aux_test_init(self, node_id, parents_states_number, node_states_number, p_combs): + sofcims = soci.SetOfCims(node_id, parents_states_number, node_states_number, p_combs) self.assertEqual(sofcims.node_id, node_id) + self.assertTrue(np.array_equal(sofcims.p_combs, p_combs)) self.assertTrue(np.array_equal(sofcims.parents_states_number, parents_states_number)) self.assertEqual(sofcims.node_states_number, node_states_number) self.assertFalse(sofcims.actual_cims) @@ -77,7 +97,46 @@ class TestSetOfCims(unittest.TestCase): self.assertEqual(sofcims.transition_matrices.shape[0], np.prod(np.array(parents_states_number))) self.assertEqual(len(sofcims.transition_matrices[0][0]), node_states_number) + def aux_test_indexes_converter(self, node_id, parents_states_number, node_states_number): + sofcims = soci.SetOfCims(node_id, parents_states_number, node_states_number) + if not parents_states_number: + self.assertEqual(sofcims.indexes_converter([]), 0) + else: + parents_possible_values = [] + for cardi in parents_states_number: + parents_possible_values.extend(range(0, cardi)) + for p in itertools.permutations(parents_possible_values, len(parents_states_number)): + self.assertEqual(sofcims.indexes_converter(list(p)), np.ravel_multi_index(list(p), parents_states_number)) + + def build_p_comb_structure_for_a_node(self, parents_values): + """ + Builds the combinatory structure that contains the combinations of all the values contained in parents_values. + + Parameters: + parents_values: the cardinalities of the nodes + Returns: + a numpy matrix containing a grid of the combinations + """ + tmp = [] + for val in parents_values: + tmp.append([x for x in range(val)]) + if len(parents_values) > 0: + parents_comb = np.array(np.meshgrid(*tmp)).T.reshape(-1, len(parents_values)) + if len(parents_values) > 1: + tmp_comb = parents_comb[:, 1].copy() + parents_comb[:, 1] = parents_comb[:, 0].copy() + parents_comb[:, 0] = tmp_comb + else: + parents_comb = np.array([[]], dtype=np.int) + return parents_comb + def another_filtering_method(self,p_combs, mask, parent_value): + masked_combs = p_combs[:, mask] + indxs = [] + for indx, val in enumerate(masked_combs): + if val == parent_value: + indxs.append(indx) + return np.array(indxs) if __name__ == '__main__': unittest.main() diff --git a/main_package/tests/test_structure.py b/main_package/tests/test_structure.py index 47e90a4..fe9a180 100644 --- a/main_package/tests/test_structure.py +++ b/main_package/tests/test_structure.py @@ -1,80 +1,73 @@ import sys sys.path.append("/Users/Zalum/Desktop/Tesi/CTBN_Project/main_package/classes/") import unittest -import pandas as pd +import numpy as np import structure as st class TestStructure(unittest.TestCase): - def setUp(self): - self.structure_frame = pd.DataFrame([{"From":"X","To":"Z"}, {"From":"X","To":"Y"},{"From":"Y","To":"X"}, - {"From":"Y","To":"Z"},{"From":"Z","To":"Y"}, {"From":"Z","To":"X"} ]) - self.variables_frame = pd.DataFrame([{"Name":"X","Value":3},{"Name":"Y","Value":3},{"Name":"Z","Value":3}]) + @classmethod + def setUpClass(cls): + cls.labels = ['X','Y','Z'] + cls.indxs = np.array([0,1,2]) + cls.vals = np.array([3,3,3]) + cls.edges = [('X','Z'),('Y','Z'), ('Z','Y')] + cls.vars_numb = len(cls.labels) def test_init(self): - s1 = st.Structure(self.structure_frame, self.variables_frame, len(self.variables_frame.index)) - self.assertTrue(self.structure_frame.equals(s1.structure_frame)) - self.assertTrue(self.variables_frame.equals(s1.variables_frame)) - self.assertEqual(self.variables_frame.columns.values[0], s1.name_label) - self.assertEqual(self.variables_frame.columns.values[1], s1.value_label) - #print(len(self.variables_frame.index)) - self.assertEqual(len(self.variables_frame.index), s1.total_variables_number) - - def test_list_of_edges(self): - s1 = st.Structure(self.structure_frame, self.variables_frame, len(self.variables_frame.index)) - records = self.structure_frame.to_records(index=False) - result = list(records) - for e1, e2 in zip(result, s1.list_of_edges()): - self.assertEqual(e1, e2) - - def test_list_of_nodes_labels(self): - s1 = st.Structure(self.structure_frame, self.variables_frame, len(self.variables_frame.index)) - self.assertEqual(list(self.variables_frame['Name']), s1.list_of_nodes_labels()) + s1 = st.Structure(self.labels, self.indxs, self.vals, self.edges, self.vars_numb) + self.assertListEqual(self.labels,s1.nodes_labels) + self.assertIsInstance(s1.nodes_indexes, np.ndarray) + self.assertTrue(np.array_equal(self.indxs, s1.nodes_indexes)) + self.assertIsInstance(s1.nodes_values, np.ndarray) + self.assertTrue(np.array_equal(self.vals, s1.nodes_values)) + self.assertListEqual(self.edges, s1.edges) + self.assertEqual(self.vars_numb, s1.total_variables_number) def test_get_node_id(self): - s1 = st.Structure(self.structure_frame, self.variables_frame, len(self.variables_frame.index)) - for indx, var in enumerate(list(self.variables_frame['Name'])): + s1 = st.Structure(self.labels, self.indxs, self.vals, self.edges, self.vars_numb) + for indx, var in enumerate(self.labels): self.assertEqual(var, s1.get_node_id(indx)) def test_get_node_indx(self): - filtered_frame = self.variables_frame.drop(self.variables_frame[self.variables_frame['Name'] == 'Y'].index) - #print(filtered_frame) - s1 = st.Structure(self.structure_frame, filtered_frame, len(self.variables_frame.index)) - for indx, var in zip(filtered_frame.index, filtered_frame['Name']): + l2 = self.labels[:] + l2.remove('Y') + i2 = self.indxs.copy() + np.delete(i2, 1) + v2 = self.vals.copy() + np.delete(v2, 1) + e2 = [('X','Z')] + n2 = self.vars_numb - 1 + s1 = st.Structure(l2, i2, v2, e2, n2) + for indx, var in zip(i2, l2): self.assertEqual(indx, s1.get_node_indx(var)) - def test_list_of_node_indxs(self): - filtered_frame = self.variables_frame.drop(self.variables_frame[self.variables_frame['Name'] == 'Y'].index) - # print(filtered_frame) - s1 = st.Structure(self.structure_frame, filtered_frame, len(self.variables_frame.index)) - - for indx1, indx2 in zip(filtered_frame.index, s1.list_of_nodes_indexes()): - self.assertEqual(indx1, indx2) - def test_get_positional_node_indx(self): - filtered_frame = self.variables_frame.drop(self.variables_frame[self.variables_frame['Name'] == 'Y'].index) - # print(filtered_frame) - s1 = st.Structure(self.structure_frame, filtered_frame, len(self.variables_frame.index)) - for indx, var in enumerate(s1.list_of_nodes_labels()): + l2 = self.labels[:] + l2.remove('Y') + i2 = self.indxs.copy() + np.delete(i2, 1) + v2 = self.vals.copy() + np.delete(v2, 1) + e2 = [('X', 'Z')] + n2 = self.vars_numb - 1 + s1 = st.Structure(l2, i2, v2, e2, n2) + for indx, var in enumerate(s1.nodes_labels): self.assertEqual(indx, s1.get_positional_node_indx(var)) def test_get_states_number(self): - s1 = st.Structure(self.structure_frame, self.variables_frame, len(self.variables_frame.index)) - for indx, row in self.variables_frame.iterrows(): - self.assertEqual(row[1], s1.get_states_number(row[0])) - - def test_get_states_numeber_by_indx(self): - s1 = st.Structure(self.structure_frame, self.variables_frame, len(self.variables_frame.index)) - for indx, row in self.variables_frame.iterrows(): - self.assertEqual(row[1], s1.get_states_number_by_indx(indx)) + l2 = self.labels[:] + l2.remove('Y') + i2 = self.indxs.copy() + np.delete(i2, 1) + v2 = self.vals.copy() + np.delete(v2, 1) + e2 = [('X', 'Z')] + n2 = self.vars_numb - 1 + s1 = st.Structure(l2, i2, v2, e2, n2) + for val, node in zip(v2, l2): + self.assertEqual(val, s1.get_states_number(node)) - def test_remove_node(self): - s1 = st.Structure(self.structure_frame, self.variables_frame, len(self.variables_frame.index)) - s1.remove_node('Y') - print(s1.variables_frame) - print(s1.structure_frame) - print(s1.get_node_indx('Z')) - print(s1.get_positional_node_indx('Z')) if __name__ == '__main__': unittest.main() diff --git a/main_package/tests/test_structure_estimator.py b/main_package/tests/test_structure_estimator.py index a0c377b..b52896d 100644 --- a/main_package/tests/test_structure_estimator.py +++ b/main_package/tests/test_structure_estimator.py @@ -1,39 +1,97 @@ import unittest +import numpy as np +import networkx as nx +import glob +import os +import math from line_profiler import LineProfiler +import psutil +import json_importer as ji import sample_path as sp import structure_estimator as se +import cache as ch + class TestStructureEstimator(unittest.TestCase): @classmethod def setUpClass(cls) -> None: - cls.s1 = sp.SamplePath('../data', 'samples', 'dyn.str', 'variables', 'Time', 'Name') + cls.read_files = glob.glob(os.path.join('../data', "*.json")) + cls.importer = ji.JsonImporter(cls.read_files[0], 'samples', 'dyn.str', 'variables', 'Time', 'Name') + cls.s1 = sp.SamplePath(cls.importer) cls.s1.build_trajectories() cls.s1.build_structure() def test_init(self): - se1 = se.StructureEstimator(self.s1) + exp_alfa = 0.1 + chi_alfa = 0.1 + se1 = se.StructureEstimator(self.s1, exp_alfa, chi_alfa) self.assertEqual(self.s1, se1.sample_path) - self.assertEqual(se1.complete_graph_frame.shape[0], - self.s1.total_variables_count *(self.s1.total_variables_count - 1)) + self.assertTrue(np.array_equal(se1.nodes, np.array(self.s1.structure.nodes_labels))) + self.assertTrue(np.array_equal(se1.nodes_indxs, self.s1.structure.nodes_indexes)) + self.assertTrue(np.array_equal(se1.nodes_vals, self.s1.structure.nodes_values)) + self.assertEqual(se1.exp_test_sign, exp_alfa) + self.assertEqual(se1.chi_test_alfa, chi_alfa) + self.assertIsInstance(se1.complete_graph, nx.DiGraph) + self.assertIsInstance(se1.cache, ch.Cache) + + def test_build_complete_graph(self): + exp_alfa = 0.1 + chi_alfa = 0.1 + nodes_numb = len(self.s1.structure.nodes_labels) + se1 = se.StructureEstimator(self.s1, exp_alfa, chi_alfa) + cg = se1.build_complete_graph(self.s1.structure.nodes_labels) + self.assertEqual(len(cg.edges), nodes_numb*(nodes_numb - 1)) + for node in self.s1.structure.nodes_labels: + no_self_loops = self.s1.structure.nodes_labels[:] + no_self_loops.remove(node) + for n2 in no_self_loops: + self.assertIn((node, n2), cg.edges) + + def test_generate_possible_sub_sets_of_size(self): + exp_alfa = 0.1 + chi_alfa = 0.1 + nodes_numb = len(self.s1.structure.nodes_labels) + se1 = se.StructureEstimator(self.s1, exp_alfa, chi_alfa) - def test_one_iteration(self): + for node in self.s1.structure.nodes_labels: + for b in range(nodes_numb): + sets = se1.generate_possible_sub_sets_of_size(self.s1.structure.nodes_labels, b, node) + sets2 = se1.generate_possible_sub_sets_of_size(self.s1.structure.nodes_labels, b, node) + self.assertEqual(len(list(sets)), math.floor(math.factorial(nodes_numb - 1) / + (math.factorial(b)*math.factorial(nodes_numb -1 - b)))) + for sset in sets2: + self.assertFalse(node in sset) + + def test_time(self): se1 = se.StructureEstimator(self.s1, 0.1, 0.1) - #se1.one_iteration_of_CTPC_algorithm('X') - #self.aux_test_complete_test(se1, 'X', 'Y', ['Z']) lp = LineProfiler() lp.add_function(se1.complete_test) lp.add_function(se1.one_iteration_of_CTPC_algorithm) + lp.add_function(se1.independence_test) lp_wrapper = lp(se1.ctpc_algorithm) lp_wrapper() lp.print_stats() - #se1.ctpc_algorithm() print(se1.complete_graph.edges) + print(self.s1.structure.edges) + for ed in self.s1.structure.edges: + self.assertIn(tuple(ed), se1.complete_graph.edges) + tuples_edges = [tuple(rec) for rec in self.s1.structure.edges] + spurious_edges = [] + for ed in se1.complete_graph.edges: + if not(ed in tuples_edges): + spurious_edges.append(ed) - def aux_test_complete_test(self, estimator, test_par, test_child, p_set): - estimator.complete_test(test_par, test_child, p_set) + print("Spurious Edges:",spurious_edges) + se1.save_results() + def test_memory(self): + se1 = se.StructureEstimator(self.s1, 0.1, 0.1) + se1.ctpc_algorithm() + current_process = psutil.Process(os.getpid()) + mem = current_process.memory_info().rss + print("Average Memory Usage in MB:", mem / 10**6) if __name__ == '__main__': unittest.main() diff --git a/main_package/tests/test_trajectory.py b/main_package/tests/test_trajectory.py index a29de9c..09a776e 100644 --- a/main_package/tests/test_trajectory.py +++ b/main_package/tests/test_trajectory.py @@ -8,7 +8,7 @@ class TestTrajectory(unittest.TestCase): def test_init(self): cols_list = [np.array([1.2,1.3,.14]), np.arange(1,4), np.arange(4,7)] - t1 = tr.Trajectory(cols_list, len(cols_list)) + t1 = tr.Trajectory(cols_list, len(cols_list) - 2) self.assertTrue(np.array_equal(cols_list[0], t1.times)) self.assertTrue(np.array_equal(np.ravel(t1.complete_trajectory[:, : 1]), cols_list[1])) self.assertTrue(np.array_equal(np.ravel(t1.complete_trajectory[:, 1: 2]), cols_list[2])) @@ -19,6 +19,21 @@ class TestTrajectory(unittest.TestCase): cols_list = [np.arange(1, 4), np.arange(4, 7), np.array([1.2, 1.3, .14])] self.assertRaises(TypeError, tr.Trajectory, cols_list, len(cols_list)) + def test_complete_trajectory(self): + cols_list = [np.array([1.2, 1.3, .14]), np.arange(1, 4), np.arange(4, 7)] + t1 = tr.Trajectory(cols_list, len(cols_list) - 2) + complete = np.column_stack((cols_list[1], cols_list[2])) + self.assertTrue(np.array_equal(t1.complete_trajectory, complete)) + + def test_trajectory(self): + cols_list = [np.array([1.2, 1.3, .14]), np.arange(1, 4), np.arange(4, 7)] + t1 = tr.Trajectory(cols_list, len(cols_list) - 2) + self.assertTrue(np.array_equal(cols_list[1], t1.trajectory.ravel())) + + def test_times(self): + cols_list = [np.array([1.2, 1.3, .14]), np.arange(1, 4), np.arange(4, 7)] + t1 = tr.Trajectory(cols_list, len(cols_list) - 2) + self.assertTrue(np.array_equal(cols_list[0], t1.times)) if __name__ == '__main__':