def log_map(x, r, tangent_point=None): """ Let \(\mathcal{M}\) be a CCM of radius `r` and \(T_{p}\mathcal{M}\) the tangent plane of the CCM at point \(p\) (`tangent_point`). This function maps a point `x` on the CCM to the tangent plane, using the Riemannian logarithmic map. :param x: np.array, point on the CCM (extrinsic coordinates); :param r: float, radius of the CCM; :param tangent_point: np.array, origin of the tangent plane on the CCM (extrinsic coordinates); if 'None', defaults to `[0., ..., 0., r]`. :return: the log-map of x to the tangent plane (intrinsic coordinates). """ if not CDG_OK: raise ImportError('`log_map` requires CDG.') extrinsic_dim = x.shape[-1] if tangent_point is None: tangent_point = np.zeros((extrinsic_dim,)) tangent_point[-1] = np.abs(r) if isinstance(tangent_point, np.ndarray): if tangent_point.shape != (extrinsic_dim,) and tangent_point.shape != (1, extrinsic_dim): raise ValueError('Expected tangent_point of shape ({0},) or (1, {0}), got {1}'.format(extrinsic_dim, tangent_point.shape)) if tangent_point.ndim == 1: tangent_point = tangent_point[np.newaxis, ...] if not belongs(tangent_point, r)[0]: raise ValueError('Tangent point must belong to manifold {}'.format(tangent_point)) else: raise TypeError('tangent_point must be np.ndarray or None') if r > 0.: return SphericalManifold.log_map(tangent_point, x) elif r < 0.: return HyperbolicManifold.log_map(tangent_point, x) else: return x
def _d_cdt(_path, _c): _id = _path.split('/')[-2] tpr_avg = [] fpr_avg = [] auc_avg = [] run = 0 skipped = 0 crashed = False while run < P['N_RUNS'] and (skipped < 100 or skipped / (run + skipped) < 0.9): # Read data data = dataset_load(_path) try: nominal, live, labels = data except: live, labels = data nominal = live[labels == 0].copy() live = live[(labels == 0) | (labels == _c)] labels = labels[(labels == 0) | (labels == _c)] labels[labels != 0] = 1 CUSUM_WINDOW_SIZE = int(nominal.shape[0] * P['CUSUM_WINDOW_RATIO']) cut = CUSUM_WINDOW_SIZE * (nominal.shape[0] // CUSUM_WINDOW_SIZE) nominal = nominal[:cut] cut = CUSUM_WINDOW_SIZE * (labels.shape[0] // CUSUM_WINDOW_SIZE) live = live[:cut] labels = labels[:cut] live_n = live[labels == 0].copy() live_nn = live[labels == 1].copy() live = np.vstack((live_n, live_nn)) # Compute distances distances_nom = [] distances_test = [] try: for i_, r_ in enumerate(P['radius']): start = i_ * P['latent_space'] stop = start + P['latent_space'] if r_ > 0.: # Spherical s_mean = SphericalManifold.sample_mean(nominal[:, start:stop], radius=r_) d_nom = SphericalManifold.distance(nominal[:, start:stop], s_mean, radius=r_) d_test = SphericalManifold.distance(live[:, start:stop], s_mean, radius=r_) elif r_ < 0.: # Hyperbolic s_mean = HyperbolicManifold.sample_mean( nominal[:, start:stop], radius=-r_) d_nom = HyperbolicManifold.distance(nominal[:, start:stop], s_mean, radius=-r_) d_test = HyperbolicManifold.distance(live[:, start:stop], s_mean, radius=-r_) else: # Euclidean s_mean = np.mean(nominal[:, start:stop], 0) d_nom = np.linalg.norm(nominal[:, start:stop] - s_mean, axis=-1)[..., None] d_test = np.linalg.norm(live[:, start:stop] - s_mean, axis=-1)[..., None] distances_nom.append(d_nom) distances_test.append(d_test) except FloatingPointError: print('D-CDT: FloatingPointError') skipped += 1 continue # Combined distances_nom = np.concatenate(distances_nom, -1) distances_test = np.concatenate(distances_test, -1) # Change detection cdt = GaussianCusum(arl=P['CUSUM_ARL'], window_size=CUSUM_WINDOW_SIZE) cdt.fit(distances_nom, estimate_threshold=True, len_simulation=P['CUSUM_SIM_LEN']) pred, cum_sum = cdt.predict(distances_test, reset=True) pred = np.array(pred).astype(int) y_true = labels.reshape(-1, CUSUM_WINDOW_SIZE).mean(-1).round().reshape(-1) y_pred = pred.reshape(-1, CUSUM_WINDOW_SIZE).mean(-1).round().reshape(-1) tn, fp, fn, tp = confusion_matrix(y_true, y_pred).ravel() tpr = tp / (tp + fn) fpr = fp / (fp + tn) auc, _ = detection_score(y_pred, y_true) if auc > 0.: tpr_avg.append(tpr) fpr_avg.append(fpr) auc_avg.append(auc) run += 1 else: print('No true positive predictions') skipped += 1 if len(auc_avg) == 0 or np.isnan(np.mean(auc_avg)): crashed = True result_str = 'crashed' if crashed else 'TPR: {:.5f} FPR: {:.5f} - AUC: {:.3f}'.format( np.mean(tpr_avg), np.mean(fpr_avg), np.mean(auc_avg)) print('Done: {} {} - {}'.format(_id, _c, result_str)) if not crashed: return (_id, _c, np.mean(tpr_avg), np.std(tpr_avg), np.mean(fpr_avg), np.std(fpr_avg), np.mean(auc_avg), np.std(auc_avg)) else: return _id, _c, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan
def _r_cdt(_path, _c): _id = _path.split('/')[-2] tpr_avg = [] fpr_avg = [] auc_avg = [] run = 0 skipped = 0 crashed = False while run < P['N_RUNS'] and (skipped < 100 or skipped / (run + skipped) < 0.9): # Read data data = dataset_load(_path) try: nominal, live, labels = data except: live, labels = data nominal = live[labels == 0].copy() live = live[(labels == 0) | (labels == _c)] labels = labels[(labels == 0) | (labels == _c)] labels[labels != 0] = 1 CUSUM_WINDOW_SIZE = int(nominal.shape[0] * P['CUSUM_WINDOW_RATIO']) cut = CUSUM_WINDOW_SIZE * (nominal.shape[0] // CUSUM_WINDOW_SIZE) nominal = nominal[:cut] cut = CUSUM_WINDOW_SIZE * (labels.shape[0] // CUSUM_WINDOW_SIZE) live = live[:cut] labels = labels[:cut] live_n = live[labels == 0].copy() live_nn = live[labels == 1].copy() live = np.vstack((live_n, live_nn)) # Change detection cusum_list = [] indices = [] for i_, r_ in enumerate(P['radius']): start = i_ * P['latent_space'] stop = start + P['latent_space'] indices.append((start, stop)) if r_ < 0.: # Hyperbolic man_tmp = HyperbolicManifold(radius=-r_) cusum_list.append( ManifoldCLTCusum(arl=P['CUSUM_ARL'], manifold=man_tmp, window_size=CUSUM_WINDOW_SIZE)) elif r_ > 0.: # Spherical man_tmp = SphericalManifold(radius=r_) cusum_list.append( ManifoldCLTCusum(arl=P['CUSUM_ARL'], manifold=man_tmp, window_size=CUSUM_WINDOW_SIZE)) else: # Euclidean cusum_list.append( GaussianCusum(arl=P['CUSUM_ARL'], window_size=CUSUM_WINDOW_SIZE)) # Bonferroni on different cdt = BonferroniCusum(cusum_list=cusum_list, arl=P['CUSUM_ARL'] // len(P['radius'])) try: cdt.fit([nominal[..., start:stop] for start, stop in indices], estimate_threshold=True, len_simulation=P['CUSUM_SIM_LEN'], radia=P['radius']) except FloatingPointError: print('R-CDT: FloatingPointError') skipped += 1 continue pred, cum_sum = cdt.predict( [live[..., start:stop] for start, stop in indices], reset=True) pred = np.array(pred).astype(int) y_true = labels.reshape(-1, CUSUM_WINDOW_SIZE).mean(-1).round().reshape(-1) y_pred = pred.reshape(-1, CUSUM_WINDOW_SIZE).mean(-1).round().reshape(-1) tn, fp, fn, tp = confusion_matrix(y_true, y_pred).ravel() tpr = tp / (tp + fn) fpr = fp / (fp + tn) auc, _ = detection_score(y_pred, y_true) if auc > 0.: tpr_avg.append(tpr) fpr_avg.append(fpr) auc_avg.append(auc) run += 1 else: print('No true positive predictions') skipped += 1 if len(auc_avg) == 0 or np.isnan(np.mean(auc_avg)): crashed = True result_str = 'crashed' if crashed else 'TPR: {:.5f} FPR: {:.5f} - AUC: {:.3f}'.format( np.mean(tpr_avg), np.mean(fpr_avg), np.mean(auc_avg)) print('Done: {} {} - {}'.format(_id, _c, result_str)) if not crashed: return (_id, _c, np.mean(tpr_avg), np.std(tpr_avg), np.mean(fpr_avg), np.std(fpr_avg), np.mean(auc_avg), np.std(auc_avg)) else: return _id, _c, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan