-
Notifications
You must be signed in to change notification settings - Fork 0
/
ecm.py
131 lines (108 loc) · 5.14 KB
/
ecm.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import numpy as np
import networkx as nx
from scipy.sparse import csr_matrix
from scipy.sparse.linalg import eigsh
from geomstats.manifold import RiemannianManifold
from geomstats.geometry.hyperbolic import Hyperbolic
from sklearn.decomposition import PCA
from gudhi import RipsComplex, SimplexTree
from gudhi.wasserstein import wasserstein_distance
class EventContinuumMapping:
def __init__(self, manifold_dim=100):
self.manifold = Hyperbolic(dim=manifold_dim)
self.event_graph = nx.Graph()
self.event_tensor = None
self.pca = PCA(n_components=manifold_dim)
def add_event(self, event_data):
event_id = len(self.event_graph)
self.event_graph.add_node(event_id, **event_data)
self._update_manifold()
return event_id
def add_relation(self, event1_id, event2_id, relation_type, strength):
self.event_graph.add_edge(event1_id, event2_id, type=relation_type, weight=strength)
self._update_manifold()
def _update_manifold(self):
adj_matrix = nx.adjacency_matrix(self.event_graph)
self.event_tensor = self._adjacency_to_tensor(adj_matrix)
# Use PCA to reduce dimensionality of the event tensor
flattened_tensor = self.event_tensor.reshape(-1, self.event_tensor.shape[-1])
pca_result = self.pca.fit_transform(flattened_tensor)
# Update the manifold's metric tensor
metric_tensor = np.dot(pca_result.T, pca_result)
self.manifold.metric.set_metric_matrix(metric_tensor)
def _adjacency_to_tensor(self, adj_matrix):
n = adj_matrix.shape[0]
tensor = np.zeros((n, n, n))
for i in range(n):
for j in range(n):
if adj_matrix[i, j] != 0:
tensor[i, j, :] = adj_matrix[i, :].toarray()
return tensor
def get_manifold_curvature(self):
n = self.manifold.dim
curvature_tensor = np.zeros((n, n, n, n))
metric_tensor = self.manifold.metric.metric_matrix()
for i in range(n):
for j in range(n):
for k in range(n):
for l in range(n):
curvature_tensor[i, j, k, l] = self.manifold.metric.curvature(
np.eye(n)[i],
np.eye(n)[j],
np.eye(n)[k],
np.eye(n)[l]
)
return curvature_tensor
def analyze_event_patterns(self):
centrality = nx.eigenvector_centrality(self.event_graph)
communities = nx.community.louvain_communities(self.event_graph)
# Persistent homology analysis
points = np.array([self.event_graph.nodes[node]['features'] for node in self.event_graph.nodes])
rips_complex = RipsComplex(points=points)
simplex_tree = rips_complex.create_simplex_tree(max_dimension=2)
diag = simplex_tree.persistence()
# Topological features
betti_numbers = simplex_tree.betti_numbers()
return {
'centrality': centrality,
'communities': communities,
'persistence_diagram': diag,
'betti_numbers': betti_numbers
}
def temporal_analysis(self, time_window):
# Create a time-ordered list of events
events = sorted(self.event_graph.nodes(data=True), key=lambda x: x[1]['timestamp'])
# Sliding window analysis
temporal_patterns = []
for i in range(len(events) - time_window + 1):
window_events = events[i:i+time_window]
window_graph = nx.Graph()
for event in window_events:
window_graph.add_node(event[0], **event[1])
# Add edges within the time window
for j in range(len(window_events)):
for k in range(j+1, len(window_events)):
if self.event_graph.has_edge(window_events[j][0], window_events[k][0]):
window_graph.add_edge(window_events[j][0], window_events[k][0])
# Analyze the window
pattern = {
'time_start': window_events[0][1]['timestamp'],
'time_end': window_events[-1][1]['timestamp'],
'num_events': len(window_events),
'density': nx.density(window_graph),
'clustering_coefficient': nx.average_clustering(window_graph)
}
temporal_patterns.append(pattern)
return temporal_patterns
def calculate_wasserstein_distance(self, other_ecm):
# Calculate Wasserstein distance between persistence diagrams
diag1 = self.analyze_event_patterns()['persistence_diagram']
diag2 = other_ecm.analyze_event_patterns()['persistence_diagram']
return wasserstein_distance(diag1, diag2)
def get_event_embeddings(self):
# Get node embeddings using the manifold
embeddings = {}
for node in self.event_graph.nodes():
point = self.manifold.random_point() # Initialize randomly
embeddings[node] = self.manifold.to_tangent_space(point)
return embeddings