highdimensionsmap 0.1.0__tar.gz → 0.2.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. highdimensionsmap-0.2.2/PKG-INFO +103 -0
  2. highdimensionsmap-0.2.2/README.md +84 -0
  3. highdimensionsmap-0.2.2/highdimensionsmap/__init__.py +17 -0
  4. {highdimensionsmap-0.1.0 → highdimensionsmap-0.2.2}/highdimensionsmap/api.py +13 -4
  5. highdimensionsmap-0.2.2/highdimensionsmap/compressor.py +202 -0
  6. highdimensionsmap-0.2.2/highdimensionsmap/core.py +19 -0
  7. highdimensionsmap-0.2.2/highdimensionsmap/scanner.py +135 -0
  8. highdimensionsmap-0.2.2/highdimensionsmap/tensor.py +48 -0
  9. highdimensionsmap-0.2.2/highdimensionsmap/tracker.py +61 -0
  10. highdimensionsmap-0.2.2/highdimensionsmap.egg-info/PKG-INFO +103 -0
  11. {highdimensionsmap-0.1.0 → highdimensionsmap-0.2.2}/highdimensionsmap.egg-info/SOURCES.txt +5 -1
  12. {highdimensionsmap-0.1.0 → highdimensionsmap-0.2.2}/highdimensionsmap.egg-info/requires.txt +5 -0
  13. {highdimensionsmap-0.1.0 → highdimensionsmap-0.2.2}/pyproject.toml +7 -3
  14. highdimensionsmap-0.2.2/tests/test_compressor.py +135 -0
  15. highdimensionsmap-0.2.2/tests/test_scanner_regressions.py +41 -0
  16. highdimensionsmap-0.1.0/PKG-INFO +0 -95
  17. highdimensionsmap-0.1.0/README.md +0 -80
  18. highdimensionsmap-0.1.0/highdimensionsmap/__init__.py +0 -8
  19. highdimensionsmap-0.1.0/highdimensionsmap/core.py +0 -74
  20. highdimensionsmap-0.1.0/highdimensionsmap/scanner.py +0 -80
  21. highdimensionsmap-0.1.0/highdimensionsmap/tracker.py +0 -31
  22. highdimensionsmap-0.1.0/highdimensionsmap.egg-info/PKG-INFO +0 -95
  23. {highdimensionsmap-0.1.0 → highdimensionsmap-0.2.2}/LICENSE +0 -0
  24. {highdimensionsmap-0.1.0 → highdimensionsmap-0.2.2}/highdimensionsmap/kinematics.py +0 -0
  25. {highdimensionsmap-0.1.0 → highdimensionsmap-0.2.2}/highdimensionsmap.egg-info/dependency_links.txt +0 -0
  26. {highdimensionsmap-0.1.0 → highdimensionsmap-0.2.2}/highdimensionsmap.egg-info/top_level.txt +0 -0
  27. {highdimensionsmap-0.1.0 → highdimensionsmap-0.2.2}/setup.cfg +0 -0
  28. {highdimensionsmap-0.1.0 → highdimensionsmap-0.2.2}/tests/test_api.py +0 -0
@@ -0,0 +1,103 @@
1
+ Metadata-Version: 2.4
2
+ Name: highdimensionsmap
3
+ Version: 0.2.2
4
+ Summary: High Dimensions Map: lightweight non-linear geometric scanning and phase-orbit indexing
5
+ Author: Marta Reinhardt
6
+ License-Expression: Apache-2.0
7
+ Keywords: geometry,high-dimensions,embeddings,manifold-learning,kinematics,spectral
8
+ Requires-Python: >=3.8
9
+ Description-Content-Type: text/markdown
10
+ License-File: LICENSE
11
+ Requires-Dist: numpy>=1.20.0
12
+ Requires-Dist: fastapi>=0.110.0
13
+ Requires-Dist: uvicorn>=0.30.0
14
+ Requires-Dist: scipy>=1.7.0
15
+ Provides-Extra: test
16
+ Requires-Dist: pytest>=7.0; extra == "test"
17
+ Requires-Dist: httpx>=0.24; extra == "test"
18
+ Dynamic: license-file
19
+
20
+
21
+ # High Dimensions Map (HDM) 📐
22
+
23
+ <p align="center">
24
+ <b>PT:</b> Biblioteca Python para projeção ortogonal analítica e compressão adaptativa de vetores via DCT-II.<br>
25
+ <b>EN:</b> Python library for analytical orthogonal projection and adaptive vector compression using DCT-II.
26
+ </p>
27
+
28
+ <p align="center">
29
+ <img src="https://img.shields.io/badge/Version-0.2.2-blue?style=flat-square" alt="Version">
30
+ <img src="https://img.shields.io/badge/Python-3.9+-blue?style=flat-square" alt="Python">
31
+ <img src="https://img.shields.io/badge/Status-Active%20Development-orange?style=flat-square" alt="Status">
32
+ <img src="https://img.shields.io/badge/License-Apache-green?style=flat-square" alt="License">
33
+ </p>
34
+
35
+ ---
36
+
37
+ ## 🇧🇷 Português
38
+
39
+ ### Visão Geral
40
+ O **HDM (High Dimensions Map)** é uma biblioteca focada na otimização, redução dimensional e compressão adaptativa de vetores em espaços de alta dimensão.
41
+
42
+ Ao contrário de métodos baseados em aprendizado iterativo ou matrizes de covariância (como PCA), o HDM utiliza a **Transformada Discreta de Cosseno Tipo II (DCT-II)** de forma analítica e determinística (*training-free*), permitindo processamento em lote em tempo real com preservação garantida de energia.
43
+
44
+ ### Principais Recursos
45
+ - **`HDMCompressor` (Compressão Adaptativa):** Reduz a dimensão de vetores ordenando os coeficientes por magnitude decrescente e cortando no limiar exato de energia acumulada (`target_energy`).
46
+ - **Sem Necessidade de Treino (*Training-Free*):** Funciona vetor por vetor ou em lotes sem requerer dados de ajuste prévio.
47
+ - **Processamento Vetorizado:** Algoritmo implementado em C/NumPy nativo, capaz de processar 10.000 vetores de 1.000 dimensões em ~1.7 segundos.
48
+
49
+ ### Exemplo de Uso Prático
50
+
51
+ ```python
52
+ import numpy as np
53
+ from highdimensionmap import HDMCompressor
54
+
55
+ # Matriz de 1.000 vetores de 100 dimensões
56
+ X = np.random.randn(1000, 100)
57
+
58
+ # Instancia o compressor para reter 99.9% da energia do sinal
59
+ compressor = HDMCompressor(target_energy=0.999)
60
+
61
+ # Executa a transformação adaptativa
62
+ X_rec, k_componentes, tempo_ms = compressor.fit_transform(X)
63
+
64
+ print(f"Tempo de execução: {tempo_ms:.2f} ms")
65
+ print(f"Média de dimensões retidas: {np.mean(k_componentes):.1f} / {X.shape[1]}")
66
+ ```
67
+ # 🇬🇧 English
68
+ ## Overview
69
+ **HDM (High Dimensions Map) is a Python library focused on optimization**, dimensional reduction, and adaptive compression of high-dimensional vectors.
70
+ Unlike methods relying on iterative learning or covariance matrices (such as PCA), HDM uses the Discrete Cosine Transform Type II (DCT-II) analytically and deterministically (training-free), enabling real-time batch processing with guaranteed energy preservation.
71
+ Key Features
72
+ ***HDMCompressor (Adaptive Compression): Reduces vector dimensionality by sorting coefficients by descending magnitude and truncating at the exact threshold of cumulative energy (target_energy)."**
73
+ **Training-Free: Operates vector-by-vector or in batches without requiring prior calibration data.**
74
+ **Vectorized Performance: Core algorithm implemented natively using NumPy/SciPy, capable of processing 10,000 1,000-dimensional vectors in ~1.7 seconds.**
75
+ Quickstart Example
76
+
77
+ ```
78
+ import numpy as np
79
+ from highdimensionmap import HDMCompressor
80
+
81
+ # Matrix with 1,000 vectors of 100 dimensions
82
+ X = np.random.randn(1000, 100)
83
+
84
+ # Initialize compressor with 99.9% target energy threshold
85
+ compressor = HDMCompressor(target_energy=0.999)
86
+
87
+ # Execute adaptive transformation
88
+ X_rec, k_components, time_ms = compressor.fit_transform(X)
89
+
90
+ print(f"Execution time: {time_ms:.2f} ms")
91
+ print(f"Average dimensions retained: {np.mean(k_components):.1f} / {X.shape[1]}")
92
+
93
+ ```
94
+
95
+ ⚙️ Instalação / Installation
96
+ # Clone o repositório / Clone the repository
97
+ git clone [https://github.com/reinhardtmarta/hdm.git](https://github.com/reinhardtmarta/hdm.git)
98
+ cd hdm
99
+
100
+ # Instalação local em modo editável / Local editable installation
101
+ pip install -e .
102
+
103
+
@@ -0,0 +1,84 @@
1
+
2
+ # High Dimensions Map (HDM) 📐
3
+
4
+ <p align="center">
5
+ <b>PT:</b> Biblioteca Python para projeção ortogonal analítica e compressão adaptativa de vetores via DCT-II.<br>
6
+ <b>EN:</b> Python library for analytical orthogonal projection and adaptive vector compression using DCT-II.
7
+ </p>
8
+
9
+ <p align="center">
10
+ <img src="https://img.shields.io/badge/Version-0.2.2-blue?style=flat-square" alt="Version">
11
+ <img src="https://img.shields.io/badge/Python-3.9+-blue?style=flat-square" alt="Python">
12
+ <img src="https://img.shields.io/badge/Status-Active%20Development-orange?style=flat-square" alt="Status">
13
+ <img src="https://img.shields.io/badge/License-Apache-green?style=flat-square" alt="License">
14
+ </p>
15
+
16
+ ---
17
+
18
+ ## 🇧🇷 Português
19
+
20
+ ### Visão Geral
21
+ O **HDM (High Dimensions Map)** é uma biblioteca focada na otimização, redução dimensional e compressão adaptativa de vetores em espaços de alta dimensão.
22
+
23
+ Ao contrário de métodos baseados em aprendizado iterativo ou matrizes de covariância (como PCA), o HDM utiliza a **Transformada Discreta de Cosseno Tipo II (DCT-II)** de forma analítica e determinística (*training-free*), permitindo processamento em lote em tempo real com preservação garantida de energia.
24
+
25
+ ### Principais Recursos
26
+ - **`HDMCompressor` (Compressão Adaptativa):** Reduz a dimensão de vetores ordenando os coeficientes por magnitude decrescente e cortando no limiar exato de energia acumulada (`target_energy`).
27
+ - **Sem Necessidade de Treino (*Training-Free*):** Funciona vetor por vetor ou em lotes sem requerer dados de ajuste prévio.
28
+ - **Processamento Vetorizado:** Algoritmo implementado em C/NumPy nativo, capaz de processar 10.000 vetores de 1.000 dimensões em ~1.7 segundos.
29
+
30
+ ### Exemplo de Uso Prático
31
+
32
+ ```python
33
+ import numpy as np
34
+ from highdimensionmap import HDMCompressor
35
+
36
+ # Matriz de 1.000 vetores de 100 dimensões
37
+ X = np.random.randn(1000, 100)
38
+
39
+ # Instancia o compressor para reter 99.9% da energia do sinal
40
+ compressor = HDMCompressor(target_energy=0.999)
41
+
42
+ # Executa a transformação adaptativa
43
+ X_rec, k_componentes, tempo_ms = compressor.fit_transform(X)
44
+
45
+ print(f"Tempo de execução: {tempo_ms:.2f} ms")
46
+ print(f"Média de dimensões retidas: {np.mean(k_componentes):.1f} / {X.shape[1]}")
47
+ ```
48
+ # 🇬🇧 English
49
+ ## Overview
50
+ **HDM (High Dimensions Map) is a Python library focused on optimization**, dimensional reduction, and adaptive compression of high-dimensional vectors.
51
+ Unlike methods relying on iterative learning or covariance matrices (such as PCA), HDM uses the Discrete Cosine Transform Type II (DCT-II) analytically and deterministically (training-free), enabling real-time batch processing with guaranteed energy preservation.
52
+ Key Features
53
+ ***HDMCompressor (Adaptive Compression): Reduces vector dimensionality by sorting coefficients by descending magnitude and truncating at the exact threshold of cumulative energy (target_energy)."**
54
+ **Training-Free: Operates vector-by-vector or in batches without requiring prior calibration data.**
55
+ **Vectorized Performance: Core algorithm implemented natively using NumPy/SciPy, capable of processing 10,000 1,000-dimensional vectors in ~1.7 seconds.**
56
+ Quickstart Example
57
+
58
+ ```
59
+ import numpy as np
60
+ from highdimensionmap import HDMCompressor
61
+
62
+ # Matrix with 1,000 vectors of 100 dimensions
63
+ X = np.random.randn(1000, 100)
64
+
65
+ # Initialize compressor with 99.9% target energy threshold
66
+ compressor = HDMCompressor(target_energy=0.999)
67
+
68
+ # Execute adaptive transformation
69
+ X_rec, k_components, time_ms = compressor.fit_transform(X)
70
+
71
+ print(f"Execution time: {time_ms:.2f} ms")
72
+ print(f"Average dimensions retained: {np.mean(k_components):.1f} / {X.shape[1]}")
73
+
74
+ ```
75
+
76
+ ⚙️ Instalação / Installation
77
+ # Clone o repositório / Clone the repository
78
+ git clone [https://github.com/reinhardtmarta/hdm.git](https://github.com/reinhardtmarta/hdm.git)
79
+ cd hdm
80
+
81
+ # Instalação local em modo editável / Local editable installation
82
+ pip install -e .
83
+
84
+
@@ -0,0 +1,17 @@
1
+ from .scanner import HDMScanner
2
+ from .kinematics import HDMKinematics
3
+ from .tracker import RobustMotionTracker, RobustMotionTracker as MotionNoiseTracker
4
+ from .api import app
5
+ from .tensor import TrajectoryMotionTensor
6
+ from .compressor import HDMCompressor
7
+
8
+ __version__ = "0.2.2"
9
+ __all__ = [
10
+ "HDMScanner",
11
+ "HDMKinematics",
12
+ "MotionNoiseTracker",
13
+ "RobustMotionTracker",
14
+ "app",
15
+ "TrajectoryMotionTensor",
16
+ "HDMCompressor"
17
+ ]
@@ -28,22 +28,31 @@ def healthcheck():
28
28
  @app.post("/transform")
29
29
  def transform_endpoint(payload: TransformRequest):
30
30
  try:
31
- values = np.asarray(payload.input, dtype=float)
31
+ values = np.asarray(payload.input, dtype=np.float64)
32
32
  except ValueError as exc:
33
33
  raise HTTPException(status_code=400, detail="'input' precisa ser numérico.") from exc
34
34
 
35
35
  if values.ndim not in (1, 2):
36
36
  raise HTTPException(status_code=400, detail="'input' deve ser um vetor ou uma matriz 2D.")
37
37
 
38
+ was_1d = values.ndim == 1
38
39
  signature = scanner.transform(values)
39
- return {"signature": np.asarray(signature).tolist()}
40
+ sig_array = np.asarray(signature, dtype=np.float64)
41
+
42
+ # Garante que a estrutura dimensional da resposta corresponda à entrada
43
+ if was_1d and sig_array.ndim > 1:
44
+ sig_array = sig_array[0]
45
+ elif not was_1d and sig_array.ndim == 1:
46
+ sig_array = sig_array.reshape(1, -1)
47
+
48
+ return {"signature": sig_array.tolist()}
40
49
 
41
50
 
42
51
  @app.post("/query")
43
52
  def query_endpoint(payload: QueryRequest):
44
53
  try:
45
- dataset = np.asarray(payload.dataset, dtype=float)
46
- query = np.asarray(payload.query, dtype=float)
54
+ dataset = np.asarray(payload.dataset, dtype=np.float64)
55
+ query = np.asarray(payload.query, dtype=np.float64)
47
56
  except ValueError as exc:
48
57
  raise HTTPException(status_code=400, detail="'dataset' e 'query' precisam ser numéricos.") from exc
49
58
 
@@ -0,0 +1,202 @@
1
+ import time
2
+ from typing import Tuple, Union
3
+ import numpy as np
4
+ from scipy.fftpack import dct, idct
5
+
6
+ # Importações condicionais para frameworks de terceiros (não força dependência rígida)
7
+ try:
8
+ import pandas as pd
9
+ HAS_PANDAS = True
10
+ except ImportError:
11
+ HAS_PANDAS = False
12
+
13
+ try:
14
+ import torch
15
+ HAS_TORCH = True
16
+ except ImportError:
17
+ HAS_TORCH = False
18
+
19
+
20
+ class HDMCompressor:
21
+ """Compressor e redutor de dimensionalidade adaptativo baseado na DCT-II.
22
+
23
+ Seleciona coeficientes por ordem decrescente de magnitude até atingir
24
+ o limiar de energia acumulada especificado (target_energy).
25
+ """
26
+
27
+ def __init__(self, target_energy: float = 0.999):
28
+ if not (isinstance(target_energy, (float, int)) and 0.0 < target_energy <= 1.0):
29
+ raise ValueError("target_energy deve ser um numero entre 0.0 (exclusivo) e 1.0 (inclusivo).")
30
+ self.target_energy = float(target_energy)
31
+
32
+ def _convert_input(self, X: Union[np.ndarray, "pd.DataFrame", "pd.Series", "torch.Tensor"]) -> Tuple[np.ndarray, str]:
33
+ """Converte entradas diversas (Pandas, PyTorch) para numpy.ndarray com seguranca."""
34
+ original_type = "numpy"
35
+
36
+ if HAS_TORCH and isinstance(X, torch.Tensor):
37
+ original_type = "torch"
38
+ X = X.detach().cpu().numpy()
39
+ elif HAS_PANDAS and isinstance(X, (pd.DataFrame, pd.Series)):
40
+ original_type = "pandas"
41
+ X = X.to_numpy()
42
+
43
+ if not isinstance(X, np.ndarray):
44
+ X = np.asarray(X)
45
+
46
+ return X, original_type
47
+
48
+ def fit_transform(
49
+ self, X: Union[np.ndarray, "pd.DataFrame", "pd.Series", "torch.Tensor"]
50
+ ) -> Tuple[np.ndarray, np.ndarray, float]:
51
+ """Aplica a DCT-II e projeta os vetores com base na energia acumulada.
52
+
53
+ Trata casos de borda como NaN, Inf e vetores nulos.
54
+
55
+ Parâmetros:
56
+ X: Matriz 2D (n_amostras, n_dimensoes) ou vetor 1D. Aceita NumPy, Pandas e PyTorch.
57
+
58
+ Retorna:
59
+ tuple: (X_reconstruido, k_por_linha, tempo_execucao_ms)
60
+ """
61
+ t0 = time.perf_counter()
62
+
63
+ # 1. Normalização de tipo de entrada
64
+ X_np, original_type = self._convert_input(X)
65
+
66
+ # 2. Validação de formato (dimensionalidade)
67
+ if X_np.ndim not in (1, 2):
68
+ raise ValueError(f"Entrada invalida. Esperado array 1D ou 2D, mas recebido ndim={X_np.ndim}.")
69
+
70
+ is_1d = X_np.ndim == 1
71
+ if is_1d:
72
+ X_np = X_np.reshape(1, -1)
73
+
74
+ # 3. Tratamento de NaN e Inf
75
+ if not np.isfinite(X_np).all():
76
+ raise ValueError("A matriz de entrada contem valores invalidos (NaN ou Inf). Limpe os dados antes de processar.")
77
+
78
+ # 4. Processamento da DCT-II nas linhas (axis=1)
79
+ coefs = dct(X_np, type=2, norm="ortho", axis=1)
80
+
81
+ # 5. Ordenação por magnitude decrescente por linha
82
+ abs_coefs = np.abs(coefs)
83
+ sorted_indices = np.argsort(-abs_coefs, axis=1)
84
+
85
+ rows = np.arange(X_np.shape[0])[:, None]
86
+ sorted_sq_coefs = coefs[rows, sorted_indices] ** 2
87
+
88
+ # 6. Cálculo da Energia Total por linha (Tratamento para Vetores Nulos)
89
+ total_energy = np.sum(coefs**2, axis=1, keepdims=True)
90
+ null_vectors_mask = total_energy.squeeze(axis=1) == 0.0
91
+
92
+ # Evita divisão por zero em vetores nulos
93
+ safe_total_energy = np.where(total_energy == 0.0, 1.0, total_energy)
94
+ cum_energy = np.cumsum(sorted_sq_coefs, axis=1) / safe_total_energy
95
+
96
+ # 7. Determinação adaptativa do parâmetro K por linha
97
+ mask_energy = cum_energy >= self.target_energy
98
+ k_per_row = np.argmax(mask_energy, axis=1) + 1
99
+
100
+ # Trata linhas que não atingem o limiar exacto ou são nulas
101
+ no_reach = ~np.any(mask_energy, axis=1)
102
+ k_per_row[no_reach] = X_np.shape[1]
103
+ k_per_row[null_vectors_mask] = 1 # Vetores nulos exigem apenas 1 componente (zerado)
104
+
105
+ # 8. Filtro dos coeficientes fora do Top-K
106
+ col_indices = np.arange(X_np.shape[1])[None, :]
107
+ mask_top_k = col_indices < k_per_row[:, None]
108
+
109
+ filtered_coefs_sorted = np.zeros_like(coefs)
110
+ filtered_coefs_sorted[mask_top_k] = coefs[rows, sorted_indices][mask_top_k]
111
+
112
+ # 9. Reordenação para o espaço de frequência original
113
+ filtered_coefs = np.zeros_like(coefs)
114
+ filtered_coefs[rows, sorted_indices] = filtered_coefs_sorted
115
+
116
+ # 10. Reconstrução vetorial via IDCT-II
117
+ X_reconstructed = idct(filtered_coefs, type=2, norm="ortho", axis=1)
118
+
119
+ t1 = time.perf_counter()
120
+ exec_time_ms = (t1 - t0) * 1000.0
121
+
122
+ if is_1d:
123
+ return X_reconstructed.squeeze(0), k_per_row[0], exec_time_ms
124
+
125
+ return X_reconstructed, k_per_row, exec_time_ms
126
+
127
+ def compress(
128
+ self, X: Union[np.ndarray, "pd.DataFrame", "pd.Series", "torch.Tensor"]
129
+ ) -> dict:
130
+ """Comprime a matriz/vetor retornando apenas os K coeficientes relevantes e seus indices.
131
+
132
+ Retorna:
133
+ dict: {
134
+ 'values': list de np.ndarray (coeficientes mantidos por linha),
135
+ 'indices': list de np.ndarray (indices originais dos coeficientes),
136
+ 'shape': tuple (formato original da matriz/vetor),
137
+ 'is_1d': bool
138
+ }
139
+ """
140
+ X_np, _ = self._convert_input(X)
141
+ is_1d = X_np.ndim == 1
142
+ if is_1d:
143
+ X_np = X_np.reshape(1, -1)
144
+
145
+ if not np.isfinite(X_np).all():
146
+ raise ValueError("A matriz de entrada contem valores invalidos (NaN ou Inf).")
147
+
148
+ # 1. DCT-II e ordenacao por magnitude
149
+ coefs = dct(X_np, type=2, norm="ortho", axis=1)
150
+ abs_coefs = np.abs(coefs)
151
+ sorted_indices = np.argsort(-abs_coefs, axis=1)
152
+
153
+ rows = np.arange(X_np.shape[0])[:, None]
154
+ sorted_sq_coefs = coefs[rows, sorted_indices] ** 2
155
+
156
+ # 2. Determinar K por linha com protecao para vetores nulos
157
+ total_energy = np.sum(coefs**2, axis=1, keepdims=True)
158
+ null_mask = total_energy.squeeze(axis=1) == 0.0
159
+ safe_total = np.where(total_energy == 0.0, 1.0, total_energy)
160
+ cum_energy = np.cumsum(sorted_sq_coefs, axis=1) / safe_total
161
+
162
+ mask_energy = cum_energy >= self.target_energy
163
+ k_per_row = np.argmax(mask_energy, axis=1) + 1
164
+ k_per_row[~np.any(mask_energy, axis=1)] = X_np.shape[1]
165
+ k_per_row[null_mask] = 1
166
+
167
+ # 3. Extrair apenas os K coeficientes e indices por linha
168
+ compressed_values = []
169
+ compressed_indices = []
170
+
171
+ for i in range(X_np.shape[0]):
172
+ k = k_per_row[i]
173
+ idx = sorted_indices[i, :k]
174
+ val = coefs[i, idx]
175
+ compressed_indices.append(idx.astype(np.int32))
176
+ compressed_values.append(val.astype(np.float32))
177
+
178
+ return {
179
+ "values": compressed_values,
180
+ "indices": compressed_indices,
181
+ "shape": X_np.shape,
182
+ "is_1d": is_1d,
183
+ }
184
+
185
+ def decompress(self, compressed_data: dict) -> np.ndarray:
186
+ """Reconstrui a matriz/vetor original a partir do dicionario comprimido."""
187
+ values = compressed_data["values"]
188
+ indices = compressed_data["indices"]
189
+ shape = compressed_data["shape"]
190
+ is_1d = compressed_data["is_1d"]
191
+
192
+ coefs = np.zeros(shape, dtype=np.float32)
193
+
194
+ for i in range(shape[0]):
195
+ coefs[i, indices[i]] = values[i]
196
+
197
+ X_reconstructed = idct(coefs, type=2, norm="ortho", axis=1)
198
+
199
+ if is_1d:
200
+ return X_reconstructed.squeeze(0)
201
+ return X_reconstructed
202
+
@@ -0,0 +1,19 @@
1
+ from .scanner import HDMScanner
2
+ from .kinematics import HDMKinematics
3
+ from .tracker import RobustMotionTracker, RobustMotionTracker as MotionNoiseTracker
4
+ from .core import hdm
5
+ from .api import app
6
+ from .tensor import TrajectoryMotionTensor
7
+ from .compressor import HDMCompressor
8
+
9
+ __version__ = "0.2.2"
10
+ __all__ = [
11
+ "HDMScanner",
12
+ "HDMKinematics",
13
+ "MotionNoiseTracker",
14
+ "RobustMotionTracker",
15
+ "hdm",
16
+ "app",
17
+ "TrajectoryMotionTensor",
18
+ "HDMCompressor"
19
+ ]
@@ -0,0 +1,135 @@
1
+ import numpy as np
2
+
3
+ class HDMScanner:
4
+ """
5
+ Scanner dimensional determinístico com suporte a projeções ortogonais
6
+ adaptativas (SVD/PCA), padronização de feições e modos espectrais.
7
+ """
8
+
9
+ def __init__(self, input_dim=512, latent_modes=32, method="adaptive", scale=True, seed=42, steps=None):
10
+ if int(input_dim) < 1:
11
+ raise ValueError("input_dim precisa ser >= 1.")
12
+ if int(latent_modes) < 1:
13
+ raise ValueError("latent_modes precisa ser >= 1.")
14
+ if method not in ("adaptive", "spectral", "random"):
15
+ raise ValueError("method deve ser 'adaptive', 'spectral' ou 'random'.")
16
+ self.input_dim = int(input_dim)
17
+ self.latent_modes = int(latent_modes)
18
+ self.method = method
19
+ self.scale = scale
20
+ self.seed = seed
21
+ self.steps = steps # mantido por compatibilidade com exemplos antigos
22
+ self.projection_matrix = None
23
+ self.mean_ = None
24
+ self.std_ = None
25
+
26
+ if self.method == "spectral":
27
+ self.projection_matrix = self._build_dct_basis(self.latent_modes, self.input_dim)
28
+ elif self.method == "random":
29
+ self.projection_matrix = self._build_random_basis(self.latent_modes, self.input_dim)
30
+
31
+ def _build_dct_basis(self, n_modes, d):
32
+ n = np.arange(d, dtype=np.float64)
33
+ basis = np.zeros((n_modes, d), dtype=np.float64)
34
+ for k in range(n_modes):
35
+ if k == 0:
36
+ basis[k, :] = 1.0 / np.sqrt(d)
37
+ else:
38
+ basis[k, :] = np.sqrt(2.0 / d) * np.cos((np.pi * (2.0 * n + 1.0) * k) / (2.0 * d))
39
+ return basis
40
+
41
+ def _build_random_basis(self, n_modes, d):
42
+ rng = np.random.default_rng(self.seed)
43
+ gaussian_matrix = rng.standard_normal((d, n_modes))
44
+ q, _ = np.linalg.qr(gaussian_matrix)
45
+ return q.T
46
+
47
+ def generate_dataset(self, n_samples=1, noise=0.05, drift=0.1):
48
+ """Gera dados sintéticos reproduzíveis para testes e exemplos.
49
+
50
+ Cada linha é uma amostra. ``noise`` controla o ruído gaussiano;
51
+ ``drift`` adiciona uma tendência gradual ao longo das amostras.
52
+ """
53
+ if int(n_samples) < 1:
54
+ raise ValueError("n_samples precisa ser >= 1.")
55
+ if noise < 0 or drift < 0:
56
+ raise ValueError("noise e drift precisam ser >= 0.")
57
+ rng = np.random.default_rng(self.seed)
58
+ data = rng.standard_normal((int(n_samples), self.input_dim))
59
+ if drift:
60
+ trend = np.linspace(0.0, float(drift), int(n_samples))[:, None]
61
+ direction = np.ones((1, self.input_dim), dtype=np.float64) / np.sqrt(self.input_dim)
62
+ data = data + trend * direction
63
+ if noise:
64
+ data = data + rng.normal(0.0, float(noise), size=data.shape)
65
+ return data
66
+
67
+ def fit(self, X):
68
+ X = np.asarray(X, dtype=np.float64)
69
+ X = np.atleast_2d(X)
70
+ if X.ndim != 2 or X.shape[0] == 0 or X.shape[1] == 0:
71
+ raise ValueError("X precisa ser uma matriz 2D não vazia.")
72
+ if not np.isfinite(X).all():
73
+ raise ValueError("X deve conter apenas valores finitos.")
74
+ self.input_dim = X.shape[1]
75
+
76
+ # Uma única amostra não permite estimar componentes principais.
77
+ # Use uma base ortogonal determinística sem centralizar pela amostra,
78
+ # pois isso zeraria completamente a assinatura.
79
+ if X.shape[0] == 1:
80
+ self.mean_ = np.zeros(self.input_dim, dtype=np.float64)
81
+ self.std_ = np.ones(self.input_dim, dtype=np.float64)
82
+ self.projection_matrix = self._build_random_basis(
83
+ min(self.latent_modes, self.input_dim), self.input_dim
84
+ )
85
+ return self
86
+
87
+ self.mean_ = np.mean(X, axis=0)
88
+ X_proc = X - self.mean_
89
+
90
+ if self.scale:
91
+ self.std_ = np.std(X_proc, axis=0)
92
+ self.std_[self.std_ == 0.0] = 1.0
93
+ X_proc = X_proc / self.std_
94
+ else:
95
+ self.std_ = np.ones(self.input_dim, dtype=np.float64)
96
+
97
+ _, _, Vh = np.linalg.svd(X_proc, full_matrices=False)
98
+ self.projection_matrix = Vh[: min(self.latent_modes, Vh.shape[0]), :]
99
+ return self
100
+
101
+ def transform(self, X, normalize=False):
102
+ X = np.asarray(X, dtype=np.float64)
103
+ X = np.atleast_2d(X)
104
+
105
+ if X.shape[1] != self.input_dim or self.projection_matrix is None:
106
+ self.fit(X)
107
+
108
+ X_proc = X - self.mean_ if self.mean_ is not None else X
109
+ if self.scale and self.std_ is not None:
110
+ X_proc = X_proc / self.std_
111
+
112
+ signatures = np.dot(X_proc, self.projection_matrix.T)
113
+
114
+ if normalize:
115
+ norms = np.linalg.norm(signatures, axis=1, keepdims=True)
116
+ norms[norms == 0] = 1.0
117
+ signatures = signatures / norms
118
+
119
+ return signatures if signatures.shape[0] > 1 else signatures[0]
120
+
121
+ def query(self, dataset, query_vector, k=5):
122
+ dataset_array = np.asarray(dataset, dtype=np.float64)
123
+ if dataset_array.ndim == 1:
124
+ dataset_array = dataset_array.reshape(1, -1)
125
+
126
+ query_sig = self.transform(query_vector)
127
+
128
+ if dataset_array.shape[1] != query_sig.shape[0]:
129
+ dataset_signatures = self.transform(dataset_array)
130
+ else:
131
+ dataset_signatures = dataset_array
132
+
133
+ distances = np.linalg.norm(dataset_signatures - query_sig, axis=1)
134
+ nearest = np.argsort(distances)[:k]
135
+ return nearest, distances[nearest]
@@ -0,0 +1,48 @@
1
+ import numpy as np
2
+
3
+ class TrajectoryMotionTensor:
4
+ """
5
+ Tensor de Trajetória no Espaço de Estados para Alta Dimensão.
6
+ Mede a coerência angular contínua e detecta anomalias dinâmicas.
7
+ """
8
+ def __init__(self, scanner=None):
9
+ self.scanner = scanner
10
+
11
+ def compute_coherence(self, trajectory_matrix, step_lag=1):
12
+ matriz = np.asarray(trajectory_matrix, dtype=np.float64)
13
+ if matriz.ndim != 2:
14
+ raise ValueError("A matriz de trajetória precisa ter 2 dimensões (N_passos, Dimensão).")
15
+
16
+ if matriz.shape[0] <= step_lag:
17
+ return {
18
+ "global_coherence": 0.0,
19
+ "instantaneous_profile": np.array([]),
20
+ "drift_instability": np.array([]),
21
+ "is_structured": False
22
+ }
23
+
24
+ x0 = matriz[:-step_lag]
25
+ x1 = matriz[step_lag:]
26
+
27
+ # Produto escalar normalizado
28
+ dot_products = np.sum(x0 * x1, axis=1)
29
+ normas = np.linalg.norm(x0, axis=1) * np.linalg.norm(x1, axis=1)
30
+
31
+ # Evita divisão por zero/valores insignificantes
32
+ valid_mask = normas > 1e-8
33
+ instantaneous_coherence = np.ones(len(dot_products))
34
+ instantaneous_coherence[valid_mask] = dot_products[valid_mask] / normas[valid_mask]
35
+
36
+ # Garante intervalo [-1.0, 1.0]
37
+ instantaneous_coherence = np.clip(instantaneous_coherence, -1.0, 1.0)
38
+ drift_instability = 1.0 - instantaneous_coherence
39
+
40
+ global_coherence = float(np.median(instantaneous_coherence)) # Uso de mediana para robustez a outliers
41
+
42
+ return {
43
+ "global_coherence": global_coherence,
44
+ "instantaneous_profile": instantaneous_coherence,
45
+ "drift_instability": drift_instability,
46
+ "is_structured": bool(global_coherence > 0.3) # Limiar adaptativo
47
+ }
48
+