def remove_node_presence(self,node,time): """ Remove node and its interactions over the period :param node: node to remove :param time: a period, couple (start, stop) or an interval """ if not isinstance(time,Intervals): time= Intervals(time) if self._graph.has_node(node): self._graph.nodes()[node]["t"]= self._graph.nodes()[node]["t"]-time if self._graph.nodes()[node]["t"].duration()==0: self._graph.remove_node(node) if self._start in time or self._end in time or time.end()==self._end: new_max = -math.inf new_min = math.inf for k,v in self.node_presence().items(): new_max = max(new_max,v.end()) new_min = min(new_min,v.start()) self._start = new_min self._end = new_max
def cumulated_graph(self, times=None): """ Compute the cumulated graph. Return a networkx graph corresponding to the cumulated graph of the given period (whole graph by default) :param times: Intervals object or list of pairs (start, end) :return: a networkx (weighted) graph """ if times == None: times = Intervals([(self._start, self._end)]) elif not isinstance(times, Intervals): times = Intervals(times) to_return = nx.Graph() for n, t in nx.get_node_attributes(self._graph, "t").items(): intersect = t.intersection(times) to_return.add_node(n, weight=intersect.duration()) for (u, v), t in nx.get_edge_attributes(self._graph, "t").items(): intersect = t.intersection(times) to_return.add_edge(u, v, weight=intersect.duration()) return to_return
def local_format_to_dyn_graph(self): to_return = dn.DynGraphIG() for n in self._dyn_graph_nodes: intv = Intervals(self._dyn_graph_nodes[n]) to_return.add_node_presence(n,intv) for e in self._dyn_graph_edges: [n1,n2] = list(e) intv = Intervals(self._dyn_graph_edges[e]) to_return._add_interaction_safe(n1,n2,intv) return to_return
def local_format_to_dyn_graph(self): to_return = dn.DynGraphIG() print(self._dyn_graph_nodes) for n in self._dyn_graph_nodes: intv = Intervals(self._dyn_graph_nodes[n]) print(n, intv) to_return.add_node_presence(n, intv) print(nx.get_node_attributes(to_return._graph, "t")) for e in self._dyn_graph_edges: [n1, n2] = list(e) intv = Intervals(self._dyn_graph_edges[e]) to_return._add_interaction_safe(n1, n2, intv) print(to_return.node_presence()) return to_return
def _to_DynCommunitiesIG_fast(self): """ Work only in the standard represntation: all sn have duration 1, no missing snapshot :return: """ dyn_com_local = {} for t, part in self.snapshot_communities().items(): for id, nodes in part.items(): for n in nodes: name = id dyn_com_local.setdefault(name, {}).setdefault(n, []) if len(dyn_com_local[name] [n]) > 0 and dyn_com_local[name][n][-1][-1] == t: dyn_com_local[name][n][-1] = ( dyn_com_local[name][n][-1][0], t + 1) else: dyn_com_local[name][n].append((t, t + 1)) to_return_com = tn.DynCommunitiesIG() for c in dyn_com_local: for n in dyn_com_local[c]: dyn_com_local[c][n] = Intervals(dyn_com_local[c][n]) to_return_com._fast_set_affiliations(dyn_com_local) return to_return_com
def cumulated_graph(self, times=None, weighted=True): """ Compute the cumulated graph. Return a networkx graph corresponding to the cumulated graph of the given period (whole graph by default) :param times: a pair (start,end) :return: a networkx (weighted) graph """ if times == None: times = (self._start, self._end) times_interval = Intervals(times) to_return = nx.Graph() for n, t in nx.get_node_attributes(self._graph, "t").items(): intersect = t.intersection(times_interval) if weighted: to_return.add_node(n, weight=intersect.duration()) else: to_return.add_node(n) for (u, v), t in nx.get_edge_attributes(self._graph, "t").items(): intersect = list( t.irange(times[0], times[1], inclusive=(True, False))) if len(intersect) > 0: if weighted: to_return.add_edge(u, v, weight=len(intersect)) else: to_return.add_edge(u, v) return to_return
def test_inf(self): print("--------------------") anInt = Intervals() anInt.add_interval((10, np.inf)) anInt.add_interval((20, np.inf)) self.assertEqual([(10, np.inf)], anInt.periods()) anInt._substract_one_period((20, np.inf)) self.assertEqual([(10, 20)], anInt.periods())
def slice(self, start, end): """ Keep only the selected period :param start: time of the beginning of the slice :param end: time of the end of the slice """ to_return = tn.DynGraphIG() slice_time = Intervals((start, end)) for n, presence in self.node_presence().items(): to_return.add_node_presence(n, slice_time.intersection(presence)) for e, presence in self.interactions().items(): to_return.add_interaction(e[0], e[1], slice_time.intersection(presence)) return to_return
def add_node_presence(self, n, time): """ Add presence for a node for a period :param n: node :param time: a period, couple (start, stop) or an interval """ if not isinstance(time, Intervals): time = Intervals(time) if not self._graph.has_node(n): self._graph.add_node(n, t=time) else: self._graph.nodes[n]["t"] += time self._start = min(self._start, time.start()) self._end = max(self._end, time.end())
def _local_formats_to_dyn_structures(self): to_return_graph = dn.DynGraphIG() for n in self._dyn_graph_local_nodes: intv = Intervals(self._dyn_graph_local_nodes[n]) to_return_graph.add_node_presence(n, intv) for e in self._dyn_graph_local_edges: [n1, n2] = list(e) intv = Intervals(self._dyn_graph_local_edges[e]) to_return_graph._add_interaction_safe(n1, n2, intv) for c in self._dyn_com_local: for n in self._dyn_com_local[c]: self._dyn_com_local[c][n] = Intervals( self._dyn_com_local[c][n]) to_return_com = dn.DynCommunitiesIG() to_return_com._fast_set_affiliations(self._dyn_com_local) return to_return_graph, to_return_com
def to_DynGraphSN(self, slices=None): """ Convert to a snapshot representation. :param slices: can be one of - None, snapshot_affiliations are created such as a new snapshot is created at every node/edge change, - an integer, snapshot_affiliations are created using a sliding window - a list of periods, represented as pairs (start, end), each period yielding a snapshot :return: a dynamic graph represented as snapshot_affiliations, the weight of nodes/edges correspond to their presence time during the snapshot """ dgSN = tn.DynGraphSN() if slices == None: times = self.change_times() slices = [(times[i], times[i + 1]) for i in range(len(times) - 1)] if isinstance(slices, int): duration = slices slices = [] start = self.start end = start + duration while (end <= self.end): end = start + duration slices.append((start, end)) start = end end = end + duration for ts in slices: dgSN.add_snapshot(t=ts[0], graphSN=nx.Graph()) for n, interv in self.node_presence().items(): for ts in slices: presence = interv.intersection(Intervals([ts])).duration() if presence > 0: dgSN.snapshots(ts[0]).add_node(n, weight=presence) for e, interv in self.interactions().items(): for ts in slices: presence = interv.intersection(Intervals([ts])).duration() if presence > 0: dgSN.snapshots(ts[0]).add_edge(e[0], e[1], weight=presence) return dgSN
def add_interaction(self, u, v, time): """ Add an interaction between nodes u and v at time time :param u: first node :param b: second node :param time: pair (start,end) or Intervals :return: """ if not isinstance(time, Intervals): time = Intervals(time) self.add_node_presence(u, time) self.add_node_presence(v, time) self._add_interaction_safe(u, v, time) start = time.start() end = time.end() self._start = min(self._start, start) self._end = max(self._end, end)
def slice(self, start, end): """ Keep only the selected period :param start: time of the beginning of the slice (inclusive) :param end: time of the end of the slice (exclusive) """ to_return = tn.DynGraphLS() slice_time = Intervals((start, end)) for n, presence in self.node_presence().items(): duration = slice_time.intersection(presence) if duration.duration() > 0: to_return.add_node_presence(n, duration) for e, presence in self.interactions_intervals().items(): to_return.add_interaction(e[0], e[1], presence.islice(start, end)) to_return.add_interaction(e[0], e[1], slice_time.intersection(presence)) return to_return
def slice(self,start,end): """ Keep only the selected period :param start: time of the beginning of the slice :param end: time of the end of the slice """ to_return = tn.DynGraphIG() slice_time = Intervals((start,end)) for n,presence in self.node_presence().items(): duration = slice_time.intersection(presence) if duration.duration()>0: to_return.add_node_presence(n,duration) for e,presence in self.interactions_intervals().items(): el = list(e) duration = slice_time.intersection(presence) if duration.duration()>0: to_return.add_interaction(el[0],el[1],duration) return to_return
def to_DynCommunitiesIG(self, sn_duration, convertTimeToInteger=False): """ Convert to SG communities :param sn_duration: time of a snapshot, or None for automatic: each snapshot last until start of the next :param convertTimeToInteger: if True, communities IDs will be forgottent and replaced by consecutive integers :return: DynamicCommunitiesIG """ dynComTN = tn.DynCommunitiesIG() for i in range(len(self.snapshots)): if convertTimeToInteger: t = i tNext = i + 1 else: current_t = self.snapshots.peekitem(i)[0] if sn_duration != None: tNext = current_t + sn_duration else: if i < len(self.snapshots) - 1: tNext = self.snapshots.peekitem(i + 1)[0] else: # computing the min duration to choose as duration of the last period dates = list(self.snapshots.keys()) minDuration = min([ dates[i + 1] - dates[i] for i in range(len(dates) - 1) ]) tNext = current_t + minDuration for (cID, nodes) in self.snapshots.peekitem( i)[1].items(): #for each community for this timestep dynComTN.add_affiliation(nodes, cID, Intervals((current_t, tNext))) #convert also events for (u, v, d) in self.events.edges(data=True): if d["type"] != "continue": #if communities have different IDs dynComTN.events.add_event(u[1], v[1], d["time"][0], d["time"][1], d["type"]) return dynComTN
def _add_interaction_safe(self, u, v, time): """ Same as add_interaction but do not modify nodes presences to save time. To use only if nodes have been added manually first :param u: :param v: :param time: pair or directly an Intervals object :return: """ if not self._graph.has_edge(u, v): self._graph.add_edge(u, v, t=Intervals()) if isinstance(time, Intervals): self._graph.add_edge(u, v, t=time) else: start = time[0] end = time[1] self._graph[u][v]["t"].add_interval((start, end))
def add_node_presence(self, n, time): """ Add presence for a node for a period :param n: node :param time: a period, couple (start, stop) """ if not self._graph.has_node(n): self._graph.add_node(n, t=Intervals()) if isinstance(time, Intervals): self._graph.node[n]["t"] = time else: start = time[0] stop = time[1] self._graph.node[n]["t"].add_interval((start, stop)) start = time[0] end = time[1] self.start = min(self.start, start) self.end = max(self.end, end)
def test_union(self): anInt = Intervals() anInt.add_interval((5, 10)) another = Intervals() another.add_interval((3, 105)) test1 = another.union(anInt) test2 = anInt.union(another) print(test1) print(test2) self.assertEqual(test1, test2) self.assertEqual(test1, another) anInt = Intervals() anInt.add_interval((5, 10)) another = Intervals() another.add_interval((30, 105)) test1 = another.union(anInt) test2 = anInt.union(another) self.assertEqual(test1, test2) self.assertEqual(test1, Intervals([(5, 10), (30, 105)]))
def test_addingIntervals(self): anInt = Intervals() anInt.add_interval((2, 3)) anInt.add_interval((5, 7)) results = anInt.periods() self.assertEqual(results, [(2, 3), (5, 7)])
def test_addingIntervalsComplex(self): anInt = Intervals() anInt.add_interval((2, 3)) anInt.add_interval((5, 6)) self.assertEqual(anInt.periods(), [(2, 3), (5, 6)]) anInt.add_interval((6, 10)) self.assertEqual(anInt.periods(), [(2, 3), (5, 10)]) anInt.add_interval((20, 100)) self.assertEqual(anInt.periods(), [(2, 3), (5, 10), (20, 100)]) anInt.add_interval((101, 201)) self.assertEqual(anInt.periods(), [(2, 3), (5, 10), (20, 100), (101, 201)]) anInt.add_interval((100, 101)) self.assertEqual(anInt.periods(), [(2, 3), (5, 10), (20, 201)]) anInt.add_interval((3, 300)) self.assertEqual(anInt.periods(), [(2, 300)])
def test_addingOverlappingIntervals2(self): anInt = Intervals() anInt.add_interval((2, 3)) anInt.add_interval((0, 5)) results = anInt.periods() self.assertEqual(results, [(0, 5)])
def test_intersect(self): anInt = Intervals() anInt.add_interval((5, 10)) anInt.add_interval((12, 20)) anInt.add_interval((50, 100)) another = Intervals() another.add_interval((3, 105)) test1 = another.intersection(anInt) test2 = anInt.intersection(another) self.assertEqual(test1, test2) self.assertEqual(test1, anInt) another = Intervals() another.add_interval((3, 18)) test1 = another.intersection(anInt) self.assertEqual(test1.periods(), [(5, 10), (12, 18)]) another = Intervals() another.add_interval((19, 55)) test1 = anInt.intersection(another) self.assertEqual(test1.periods(), [(19, 20), (50, 55)])
def test_delete(self): anInt = Intervals() anInt.add_interval((10, 100)) anInt._substract_one_period((20, 30)) self.assertEqual(anInt.periods(), [(10, 20), (30, 100)])
def test_deleteComplete(self): anInt = Intervals() anInt.add_interval((10, 100)) anInt.add_interval((200, 300)) anInt._substract_one_period((5, 15)) self.assertEqual([(15, 100), (200, 300)], anInt.periods()) anInt._substract_one_period((20, 30)) self.assertEqual([(15, 20), (30, 100), (200, 300)], anInt.periods()) anInt._substract_one_period((0, 300)) self.assertEqual([], anInt.periods())
def test_oneInterval(self): anInt = Intervals() anInt.add_interval((2, 3)) results = anInt.periods() self.assertEqual(results, [(2, 3)])
def test_delete2(self): anInt = Intervals() anInt.add_interval((10, 100)) anInt.add_interval((200, 300)) anInt._substract_one_period((0, 5)) anInt._substract_one_period((150, 160)) anInt._substract_one_period((350, 450)) self.assertEqual(anInt.periods(), [(10, 100), (200, 300)])