AOT-biomaps 2.1.3__py3-none-any.whl → 2.9.233__py3-none-any.whl

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.

Potentially problematic release.


This version of AOT-biomaps might be problematic. Click here for more details.

Files changed (50) hide show
  1. AOT_biomaps/AOT_Acoustic/AcousticEnums.py +64 -0
  2. AOT_biomaps/AOT_Acoustic/AcousticTools.py +221 -0
  3. AOT_biomaps/AOT_Acoustic/FocusedWave.py +244 -0
  4. AOT_biomaps/AOT_Acoustic/IrregularWave.py +66 -0
  5. AOT_biomaps/AOT_Acoustic/PlaneWave.py +43 -0
  6. AOT_biomaps/AOT_Acoustic/StructuredWave.py +392 -0
  7. AOT_biomaps/AOT_Acoustic/__init__.py +15 -0
  8. AOT_biomaps/AOT_Acoustic/_mainAcoustic.py +978 -0
  9. AOT_biomaps/AOT_Experiment/Focus.py +55 -0
  10. AOT_biomaps/AOT_Experiment/Tomography.py +505 -0
  11. AOT_biomaps/AOT_Experiment/__init__.py +9 -0
  12. AOT_biomaps/AOT_Experiment/_mainExperiment.py +532 -0
  13. AOT_biomaps/AOT_Optic/Absorber.py +24 -0
  14. AOT_biomaps/AOT_Optic/Laser.py +70 -0
  15. AOT_biomaps/AOT_Optic/OpticEnums.py +17 -0
  16. AOT_biomaps/AOT_Optic/__init__.py +10 -0
  17. AOT_biomaps/AOT_Optic/_mainOptic.py +204 -0
  18. AOT_biomaps/AOT_Recon/AOT_Optimizers/DEPIERRO.py +191 -0
  19. AOT_biomaps/AOT_Recon/AOT_Optimizers/LS.py +106 -0
  20. AOT_biomaps/AOT_Recon/AOT_Optimizers/MAPEM.py +456 -0
  21. AOT_biomaps/AOT_Recon/AOT_Optimizers/MLEM.py +333 -0
  22. AOT_biomaps/AOT_Recon/AOT_Optimizers/PDHG.py +221 -0
  23. AOT_biomaps/AOT_Recon/AOT_Optimizers/__init__.py +5 -0
  24. AOT_biomaps/AOT_Recon/AOT_PotentialFunctions/Huber.py +90 -0
  25. AOT_biomaps/AOT_Recon/AOT_PotentialFunctions/Quadratic.py +86 -0
  26. AOT_biomaps/AOT_Recon/AOT_PotentialFunctions/RelativeDifferences.py +59 -0
  27. AOT_biomaps/AOT_Recon/AOT_PotentialFunctions/__init__.py +3 -0
  28. AOT_biomaps/AOT_Recon/AlgebraicRecon.py +1023 -0
  29. AOT_biomaps/AOT_Recon/AnalyticRecon.py +154 -0
  30. AOT_biomaps/AOT_Recon/BayesianRecon.py +230 -0
  31. AOT_biomaps/AOT_Recon/DeepLearningRecon.py +35 -0
  32. AOT_biomaps/AOT_Recon/PrimalDualRecon.py +210 -0
  33. AOT_biomaps/AOT_Recon/ReconEnums.py +375 -0
  34. AOT_biomaps/AOT_Recon/ReconTools.py +273 -0
  35. AOT_biomaps/AOT_Recon/__init__.py +11 -0
  36. AOT_biomaps/AOT_Recon/_mainRecon.py +288 -0
  37. AOT_biomaps/Config.py +95 -0
  38. AOT_biomaps/Settings.py +45 -13
  39. AOT_biomaps/__init__.py +271 -18
  40. aot_biomaps-2.9.233.dist-info/METADATA +22 -0
  41. aot_biomaps-2.9.233.dist-info/RECORD +43 -0
  42. {AOT_biomaps-2.1.3.dist-info → aot_biomaps-2.9.233.dist-info}/WHEEL +1 -1
  43. AOT_biomaps/AOT_Acoustic.py +0 -1881
  44. AOT_biomaps/AOT_Experiment.py +0 -541
  45. AOT_biomaps/AOT_Optic.py +0 -219
  46. AOT_biomaps/AOT_Reconstruction.py +0 -1416
  47. AOT_biomaps/config.py +0 -54
  48. AOT_biomaps-2.1.3.dist-info/METADATA +0 -20
  49. AOT_biomaps-2.1.3.dist-info/RECORD +0 -11
  50. {AOT_biomaps-2.1.3.dist-info → aot_biomaps-2.9.233.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,456 @@
1
+ from AOT_biomaps.AOT_Recon.ReconEnums import PotentialType
2
+ from AOT_biomaps.AOT_Recon.AOT_PotentialFunctions.Quadratic import _Omega_QUADRATIC_CPU, _Omega_QUADRATIC_GPU
3
+ from AOT_biomaps.AOT_Recon.AOT_PotentialFunctions.RelativeDifferences import _Omega_RELATIVE_DIFFERENCE_CPU, _Omega_RELATIVE_DIFFERENCE_GPU
4
+ from AOT_biomaps.AOT_Recon.AOT_PotentialFunctions.Huber import _Omega_HUBER_PIECEWISE_CPU, _Omega_HUBER_PIECEWISE_GPU
5
+ from AOT_biomaps.AOT_Recon.ReconTools import _build_adjacency_sparse, check_gpu_memory, calculate_memory_requirement
6
+ from AOT_biomaps.Config import config
7
+
8
+ import warnings
9
+ import numpy as np
10
+ import torch
11
+ from tqdm import trange
12
+
13
+ def MAPEM(
14
+ SMatrix,
15
+ y,
16
+ Omega,
17
+ beta,
18
+ delta=None,
19
+ gamma=None,
20
+ sigma=None,
21
+ numIterations=100,
22
+ isSavingEachIteration=True,
23
+ withTumor=True,
24
+ device=None,
25
+ max_saves=5000,
26
+ show_logs=True):
27
+ """
28
+ This method implements the MAPEM algorithm using either CPU or single-GPU PyTorch acceleration.
29
+ Multi-GPU and Multi-CPU modes are not implemented for this algorithm.
30
+ """
31
+ try:
32
+ tumor_str = "WITH" if withTumor else "WITHOUT"
33
+ # Auto-select device and method
34
+ if device is None:
35
+ if torch.cuda.is_available() and check_gpu_memory(config.select_best_gpu(), calculate_memory_requirement(SMatrix, y), show_logs=show_logs):
36
+ device = torch.device(f"cuda:{config.select_best_gpu()}")
37
+ use_gpu = True
38
+ else:
39
+ device = torch.device("cpu")
40
+ use_gpu = False
41
+ else:
42
+ use_gpu = device.type == "cuda"
43
+ # Dispatch to the appropriate implementation
44
+ if use_gpu:
45
+ return _MAPEM_GPU(SMatrix, y, Omega, beta, delta, gamma, sigma, numIterations, isSavingEachIteration, tumor_str, device, max_saves, show_logs=True)
46
+ else:
47
+ return _MAPEM_CPU(SMatrix, y, Omega, beta, delta, gamma, sigma, numIterations, isSavingEachIteration, tumor_str, max_saves, show_logs=True)
48
+ except Exception as e:
49
+ print(f"Error in MLEM: {type(e).__name__}: {e}")
50
+ return None, None
51
+
52
+ def MAPEM_STOP(
53
+ SMatrix,
54
+ y,
55
+ Omega,
56
+ beta,
57
+ delta=None,
58
+ gamma=None,
59
+ sigma=None,
60
+ numIterations=100,
61
+ isSavingEachIteration=True,
62
+ withTumor=True,
63
+ device=None,
64
+ max_saves=5000,
65
+ show_logs=True):
66
+ """
67
+ This method implements the MAPEM_STOP algorithm using either CPU or single-GPU PyTorch acceleration.
68
+ Multi-GPU and Multi-CPU modes are not implemented for this algorithm.
69
+ """
70
+ try:
71
+ tumor_str = "WITH" if withTumor else "WITHOUT"
72
+ # Auto-select device and method
73
+ if device is None:
74
+ if torch.cuda.is_available() and check_gpu_memory(config.select_best_gpu(), calculate_memory_requirement(SMatrix, y), show_logs=show_logs):
75
+ device = torch.device(f"cuda:{config.select_best_gpu()}")
76
+ use_gpu = True
77
+ else:
78
+ device = torch.device("cpu")
79
+ use_gpu = False
80
+ else:
81
+ use_gpu = device.type == "cuda"
82
+ # Dispatch to the appropriate implementation
83
+ if use_gpu:
84
+ return _MAPEM_GPU_STOP(SMatrix, y, Omega, beta, delta, gamma, sigma, numIterations, isSavingEachIteration, tumor_str, device, max_saves, show_logs=True)
85
+ else:
86
+ return _MAPEM_CPU_STOP(SMatrix, y, Omega, beta, delta, gamma, sigma, numIterations, isSavingEachIteration, tumor_str, max_saves, show_logs=True)
87
+ except Exception as e:
88
+ print(f"Error in MLEM: {type(e).__name__}: {e}")
89
+ return None, None
90
+
91
+
92
+ def _MAPEM_CPU_STOP(SMatrix, y, Omega, beta, delta, gamma, sigma, numIterations, isSavingEachIteration, tumor_str, max_saves, show_logs=True):
93
+ """
94
+ MAPEM version CPU simple - sans GPU - torch uniquement
95
+ """
96
+ try:
97
+ if not isinstance(Omega, PotentialType):
98
+ raise TypeError(f"Omega must be of type PotentialType, got {type(Omega)}")
99
+ if Omega == PotentialType.HUBER_PIECEWISE:
100
+ if delta is None:
101
+ raise ValueError("delta must be specified for HUBER_PIECEWISE potential type.")
102
+ if beta is None:
103
+ raise ValueError("beta must be specified for HUBER_PIECEWISE potential type.")
104
+ elif Omega == PotentialType.RELATIVE_DIFFERENCE:
105
+ if gamma is None:
106
+ raise ValueError("gamma must be specified for RELATIVE_DIFFERENCE potential type.")
107
+ if beta is None:
108
+ raise ValueError("beta must be specified for RELATIVE_DIFFERENCE potential type.")
109
+ elif Omega == PotentialType.QUADRATIC:
110
+ if sigma is None:
111
+ raise ValueError("sigma must be specified for QUADRATIC potential type.")
112
+ if beta is None:
113
+ raise ValueError("beta must be specified for QUADRATIC potential type.")
114
+ else:
115
+ raise ValueError(f"Unknown potential type: {Omega}")
116
+
117
+ SMatrix = torch.tensor(SMatrix, dtype=torch.float32)
118
+ y_tensor = torch.tensor(y, dtype=torch.float32)
119
+ T, Z, X, N = SMatrix.shape
120
+ A_flat = SMatrix.permute(0, 3, 1, 2).reshape(T * N, Z * X)
121
+ y_flat = y_tensor.reshape(-1)
122
+ I_0 = torch.ones((Z, X), dtype=torch.float32)
123
+ theta_list = [I_0]
124
+ results = [I_0.numpy()]
125
+ saved_indices = [0]
126
+ normalization_factor = SMatrix.sum(dim=(0, 3)).reshape(-1)
127
+ adj_index, adj_values = _build_adjacency_sparse(Z, X)
128
+
129
+ # Calculate save indices
130
+ if numIterations <= max_saves:
131
+ save_indices = list(range(numIterations))
132
+ else:
133
+ step = numIterations // max_saves
134
+ save_indices = list(range(0, numIterations, step))
135
+ if save_indices[-1] != numIterations - 1:
136
+ save_indices.append(numIterations - 1)
137
+
138
+ if Omega == PotentialType.HUBER_PIECEWISE:
139
+ description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse HUBER β:{beta:.4f}, δ:{delta:.4f}) + STOP condition (penalized log-likelihood) ---- {tumor_str} TUMOR ---- processing on single CPU ----"
140
+ elif Omega == PotentialType.RELATIVE_DIFFERENCE:
141
+ description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse RD β:{beta:.4f}, γ:{gamma:.4f}) + STOP condition (penalized log-likelihood) ---- {tumor_str} TUMOR ---- processing on single CPU ----"
142
+ elif Omega == PotentialType.QUADRATIC:
143
+ description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse QUADRATIC β:{beta:.4f}, σ:{sigma:.4f}) + STOP condition (penalized log-likelihood) ---- {tumor_str} TUMOR ---- processing on single CPU ----"
144
+
145
+ iterator = trange(numIterations, desc=description) if show_logs else range(numIterations)
146
+ for it in iterator:
147
+ theta_p = theta_list[-1]
148
+ theta_p_flat = theta_p.reshape(-1)
149
+ q_flat = A_flat @ theta_p_flat
150
+ e_flat = (y_flat - q_flat) / (q_flat + torch.finfo(torch.float32).tiny)
151
+ c_flat = A_flat.T @ e_flat
152
+ if Omega == PotentialType.HUBER_PIECEWISE:
153
+ grad_U, hess_U, U_value = _Omega_HUBER_PIECEWISE_CPU(theta_p_flat, adj_index, adj_values, delta=delta)
154
+ elif Omega == PotentialType.RELATIVE_DIFFERENCE:
155
+ grad_U, hess_U, U_value = _Omega_RELATIVE_DIFFERENCE_CPU(theta_p_flat, adj_index, adj_values, gamma=gamma)
156
+ elif Omega == PotentialType.QUADRATIC:
157
+ grad_U, hess_U, U_value = _Omega_QUADRATIC_CPU(theta_p_flat, adj_index, adj_values, sigma=sigma)
158
+ denom = normalization_factor + theta_p_flat * beta * hess_U
159
+ num = theta_p_flat * (c_flat - beta * grad_U)
160
+ theta_next_flat = theta_p_flat + num / (denom + torch.finfo(torch.float32).tiny)
161
+ theta_next_flat = torch.clamp(theta_next_flat, min=0)
162
+ theta_next = theta_next_flat.reshape(Z, X)
163
+ theta_list[-1] = theta_next
164
+ if isSavingEachIteration and it in save_indices:
165
+ results.append(theta_next.numpy())
166
+ saved_indices.append(it+1)
167
+ log_likelihood = (y_flat * torch.log(q_flat + 1e-8) - (q_flat + 1e-8)).sum()
168
+ penalized_log_likelihood = log_likelihood - beta * U_value
169
+ if (it + 1) % 100 == 0:
170
+ print(f"Iter {it+1}: logL={log_likelihood:.3e}, U={U_value:.3e}, penalized logL={penalized_log_likelihood:.3e}")
171
+
172
+ if isSavingEachIteration:
173
+ return results, saved_indices
174
+ else:
175
+ return results[-1], None
176
+ except Exception as e:
177
+ print(f"An error occurred in _MAPEM_CPU_STOP: {e}")
178
+ return None, None
179
+
180
+ def _MAPEM_GPU_STOP(SMatrix, y, Omega, beta, delta, gamma, sigma, numIterations, isSavingEachIteration, tumor_str, device, max_saves, show_logs=True):
181
+ """
182
+ Maximum A Posteriori (MAP) estimation for Bayesian reconstruction.
183
+ This method computes the MAP estimate of the parameters given the data.
184
+ """
185
+ try:
186
+ if not isinstance(Omega, PotentialType):
187
+ raise TypeError(f"Omega must be of type PotentialType, got {type(Omega)}")
188
+ if Omega == PotentialType.HUBER_PIECEWISE:
189
+ if delta is None:
190
+ raise ValueError("delta must be specified for HUBER_PIECEWISE potential type.")
191
+ if beta is None:
192
+ raise ValueError("beta must be specified for HUBER_PIECEWISE potential type.")
193
+ elif Omega == PotentialType.RELATIVE_DIFFERENCE:
194
+ if gamma is None:
195
+ raise ValueError("gamma must be specified for RELATIVE_DIFFERENCE potential type.")
196
+ if beta is None:
197
+ raise ValueError("beta must be specified for RELATIVE_DIFFERENCE potential type.")
198
+ elif Omega == PotentialType.QUADRATIC:
199
+ if sigma is None:
200
+ raise ValueError("sigma must be specified for QUADRATIC potential type.")
201
+ if beta is None:
202
+ raise ValueError("beta must be specified for QUADRATIC potential type.")
203
+ else:
204
+ raise ValueError(f"Unknown potential type: {Omega}")
205
+
206
+ A_matrix_torch = torch.tensor(SMatrix, dtype=torch.float32).to(device)
207
+ y_torch = torch.tensor(y, dtype=torch.float32).to(device)
208
+ T, Z, X, N = SMatrix.shape
209
+ J = Z * X
210
+ A_flat = A_matrix_torch.permute(0, 3, 1, 2).reshape(T * N, Z * X)
211
+ y_flat = y_torch.reshape(-1)
212
+ I_0 = torch.ones((Z, X), dtype=torch.float32, device=device)
213
+ matrix_theta_torch = [I_0]
214
+ matrix_theta_from_gpu_MAPEM = [I_0.cpu().numpy()]
215
+ saved_indices = [0]
216
+ normalization_factor = A_matrix_torch.sum(dim=(0, 3))
217
+ normalization_factor_flat = normalization_factor.reshape(-1)
218
+ previous = -np.inf
219
+ nb_false_successive = 0
220
+ adj_index, adj_values = _build_adjacency_sparse(Z, X, device=device)
221
+
222
+ # Calculate save indices
223
+ if numIterations <= max_saves:
224
+ save_indices = list(range(numIterations))
225
+ else:
226
+ step = numIterations // max_saves
227
+ save_indices = list(range(0, numIterations, step))
228
+ if save_indices[-1] != numIterations - 1:
229
+ save_indices.append(numIterations - 1)
230
+
231
+ if Omega == PotentialType.HUBER_PIECEWISE:
232
+ description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse HUBER β:{beta:.4f}, δ:{delta:.4f}) + STOP condition (penalized log-likelihood) ---- {tumor_str} TUMOR ---- processing on single GPU no.{torch.cuda.current_device()} ----"
233
+ elif Omega == PotentialType.RELATIVE_DIFFERENCE:
234
+ description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse RD β:{beta:.4f}, γ:{gamma:.4f}) + STOP condition (penalized log-likelihood) ---- {tumor_str} TUMOR ---- processing on single GPU no.{torch.cuda.current_device()} ----"
235
+ elif Omega == PotentialType.QUADRATIC:
236
+ description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse QUADRATIC β:{beta:.4f}, σ:{sigma:.4f}) + STOP condition (penalized log-likelihood) ---- {tumor_str} TUMOR ---- processing on single GPU no.{torch.cuda.current_device()} ----"
237
+
238
+ iterator = trange(numIterations, desc=description) if show_logs else range(numIterations)
239
+ for it in iterator:
240
+ theta_p = matrix_theta_torch[-1]
241
+ theta_p_flat = theta_p.reshape(-1)
242
+ q_flat = A_flat @ theta_p_flat
243
+ e_flat = (y_flat - q_flat) / (q_flat + torch.finfo(torch.float32).tiny)
244
+ c_flat = A_flat.T @ e_flat
245
+ if Omega == PotentialType.HUBER_PIECEWISE:
246
+ grad_U, hess_U, U_value = _Omega_HUBER_PIECEWISE_GPU(theta_p_flat, adj_index, adj_values, device=device, delta=delta)
247
+ elif Omega == PotentialType.RELATIVE_DIFFERENCE:
248
+ grad_U, hess_U, U_value = _Omega_RELATIVE_DIFFERENCE_GPU(theta_p_flat, adj_index, adj_values, device=device, gamma=gamma)
249
+ elif Omega == PotentialType.QUADRATIC:
250
+ grad_U, hess_U, U_value = _Omega_QUADRATIC_GPU(theta_p_flat, adj_index, adj_values, device=device, sigma=sigma)
251
+ else:
252
+ raise ValueError(f"Unknown potential type: {Omega}")
253
+ denom = normalization_factor_flat + theta_p_flat * beta * hess_U
254
+ num = theta_p_flat * (c_flat - beta * grad_U)
255
+ theta_p_plus_1_flat = theta_p_flat + num / (denom + torch.finfo(torch.float32).tiny)
256
+ theta_p_plus_1_flat = torch.clamp(theta_p_plus_1_flat, min=0)
257
+ theta_next = theta_p_plus_1_flat.reshape(Z, X)
258
+ matrix_theta_torch[-1] = theta_next
259
+ if isSavingEachIteration and it in save_indices:
260
+ matrix_theta_from_gpu_MAPEM.append(theta_next.cpu().numpy())
261
+ saved_indices.append(it+1)
262
+ log_likelihood = (y_flat * (torch.log(q_flat + torch.finfo(torch.float32).tiny)) - (q_flat + torch.finfo(torch.float32).tiny)).sum()
263
+ penalized_log_likelihood = log_likelihood - beta * U_value
264
+ if it == 0 or (it + 1) % 100 == 0:
265
+ current = penalized_log_likelihood.item()
266
+ if current <= previous:
267
+ nb_false_successive += 1
268
+ else:
269
+ nb_false_successive = 0
270
+ print(f"Iter {it + 1}: lnL without term ln(m_i !) inside={log_likelihood.item():.8e}, Gibbs energy function U={U_value.item():.4e}, penalized lnL without term ln(m_i !) inside={penalized_log_likelihood.item():.8e}, p lnL (current {current:.8e} - previous {previous:.8e} > 0)={(current - previous > 0)}, nb_false_successive={nb_false_successive}")
271
+ previous = current
272
+
273
+ del A_matrix_torch, y_torch, A_flat, y_flat, I_0, normalization_factor, normalization_factor_flat
274
+ torch.cuda.empty_cache()
275
+ if isSavingEachIteration:
276
+ return matrix_theta_from_gpu_MAPEM, saved_indices
277
+ else:
278
+ return matrix_theta_from_gpu_MAPEM[-1], None
279
+ except Exception as e:
280
+ print(f"An error occurred in _MAPEM_GPU_STOP: {e}")
281
+ del A_matrix_torch, y_torch, A_flat, y_flat, I_0, normalization_factor, normalization_factor_flat
282
+ torch.cuda.empty_cache()
283
+ return None, None
284
+
285
+ def _MAPEM_CPU(SMatrix, y, Omega, beta, delta, gamma, sigma, numIterations, isSavingEachIteration, tumor_str, max_saves, show_logs=True):
286
+ try:
287
+ if not isinstance(Omega, PotentialType):
288
+ raise TypeError(f"Omega must be of type PotentialType, got {type(Omega)}")
289
+ if Omega == PotentialType.HUBER_PIECEWISE:
290
+ if delta is None:
291
+ raise ValueError("delta must be specified for HUBER_PIECEWISE potential type.")
292
+ if beta is None:
293
+ raise ValueError("beta must be specified for HUBER_PIECEWISE potential type.")
294
+ elif Omega == PotentialType.RELATIVE_DIFFERENCE:
295
+ if gamma is None:
296
+ raise ValueError("gamma must be specified for RELATIVE_DIFFERENCE potential type.")
297
+ if beta is None:
298
+ raise ValueError("beta must be specified for RELATIVE_DIFFERENCE potential type.")
299
+ elif Omega == PotentialType.QUADRATIC:
300
+ if sigma is None:
301
+ raise ValueError("sigma must be specified for QUADRATIC potential type.")
302
+ if beta is None:
303
+ raise ValueError("beta must be specified for QUADRATIC potential type.")
304
+ else:
305
+ raise ValueError(f"Unknown potential type: {Omega}")
306
+
307
+ T, Z, X, N = SMatrix.shape
308
+ A_flat = np.transpose(SMatrix, (0, 3, 1, 2)).reshape(T * N, Z * X)
309
+ y_flat = y.reshape(-1)
310
+ theta_0 = np.ones((Z, X), dtype=np.float32)
311
+ matrix_theta_np = [theta_0]
312
+ I_reconMatrix = [theta_0.copy()]
313
+ saved_indices = [0]
314
+ normalization_factor = SMatrix.sum(axis=(0, 3))
315
+ normalization_factor_flat = normalization_factor.reshape(-1)
316
+ adj_index, adj_values = _build_adjacency_sparse(Z, X)
317
+
318
+ # Calculate save indices
319
+ if numIterations <= max_saves:
320
+ save_indices = list(range(numIterations))
321
+ else:
322
+ step = numIterations // max_saves
323
+ save_indices = list(range(0, numIterations, step))
324
+ if save_indices[-1] != numIterations - 1:
325
+ save_indices.append(numIterations - 1)
326
+
327
+ if Omega == PotentialType.HUBER_PIECEWISE:
328
+ description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse HUBER β:{beta:.4f}, δ:{delta:.4f}) ---- {tumor_str} TUMOR ---- processing on single CPU ----"
329
+ elif Omega == PotentialType.RELATIVE_DIFFERENCE:
330
+ description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse RD β:{beta:.4f}, γ:{gamma:.4f}) ---- {tumor_str} TUMOR ---- processing on single CPU ----"
331
+ elif Omega == PotentialType.QUADRATIC:
332
+ description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse QUADRATIC β:{beta:.4f}, σ:{sigma:.4f}) ---- {tumor_str} TUMOR ---- processing on single CPU ----"
333
+
334
+ iterator = trange(numIterations, desc=description) if show_logs else range(numIterations)
335
+ for it in iterator:
336
+ theta_p = matrix_theta_np[-1]
337
+ theta_p_flat = theta_p.reshape(-1)
338
+ q_flat = A_flat @ theta_p_flat
339
+ e_flat = (y_flat - q_flat) / (q_flat + np.finfo(np.float32).tiny)
340
+ c_flat = A_flat.T @ e_flat
341
+ if Omega == PotentialType.HUBER_PIECEWISE:
342
+ grad_U, hess_U, _ = _Omega_HUBER_PIECEWISE_CPU(theta_p_flat, adj_index, adj_values, delta=delta)
343
+ elif Omega == PotentialType.RELATIVE_DIFFERENCE:
344
+ grad_U, hess_U, _ = _Omega_RELATIVE_DIFFERENCE_CPU(theta_p_flat, adj_index, adj_values, gamma=gamma)
345
+ elif Omega == PotentialType.QUADRATIC:
346
+ grad_U, hess_U, _ = _Omega_QUADRATIC_CPU(theta_p_flat, adj_index, adj_values, sigma=sigma)
347
+ denom = normalization_factor_flat + theta_p_flat * beta * hess_U
348
+ num = theta_p_flat * (c_flat - beta * grad_U)
349
+ theta_p_plus_1_flat = theta_p_flat + num / (denom + np.finfo(np.float32).tiny)
350
+ theta_p_plus_1_flat = np.clip(theta_p_plus_1_flat, 0, None)
351
+ theta_next = theta_p_plus_1_flat.reshape(Z, X)
352
+ matrix_theta_np.append(theta_next)
353
+ if isSavingEachIteration and it in save_indices:
354
+ I_reconMatrix.append(theta_next.copy())
355
+ saved_indices.append(it+1)
356
+
357
+ if isSavingEachIteration:
358
+ return I_reconMatrix, saved_indices
359
+ else:
360
+ return I_reconMatrix[-1], None
361
+ except Exception as e:
362
+ print(f"An error occurred in _MAPEM_CPU: {e}")
363
+ return None, None
364
+
365
+ def _MAPEM_GPU(SMatrix, y, Omega, beta, delta, gamma, sigma, numIterations, isSavingEachIteration, tumor_str, device, max_saves, show_logs=True):
366
+ """
367
+ Maximum A Posteriori (MAP) estimation for Bayesian reconstruction using GPU.
368
+ This method computes the MAP estimate of the parameters given the data.
369
+ """
370
+ try:
371
+ if not isinstance(Omega, PotentialType):
372
+ raise TypeError(f"Omega must be of type PotentialType, got {type(Omega)}")
373
+ if Omega == PotentialType.HUBER_PIECEWISE:
374
+ if delta is None:
375
+ raise ValueError("delta must be specified for HUBER_PIECEWISE potential type.")
376
+ if beta is None:
377
+ raise ValueError("beta must be specified for HUBER_PIECEWISE potential type.")
378
+ elif Omega == PotentialType.RELATIVE_DIFFERENCE:
379
+ if gamma is None:
380
+ raise ValueError("gamma must be specified for RELATIVE_DIFFERENCE potential type.")
381
+ if beta is None:
382
+ raise ValueError("beta must be specified for RELATIVE_DIFFERENCE potential type.")
383
+ elif Omega == PotentialType.QUADRATIC:
384
+ if sigma is None:
385
+ raise ValueError("sigma must be specified for QUADRATIC potential type.")
386
+ if beta is None:
387
+ raise ValueError("beta must be specified for QUADRATIC potential type.")
388
+ else:
389
+ raise ValueError(f"Unknown potential type: {Omega}")
390
+
391
+ A_matrix_torch = torch.tensor(SMatrix, dtype=torch.float32).to(device)
392
+ y_torch = torch.tensor(y, dtype=torch.float32).to(device)
393
+ T, Z, X, N = SMatrix.shape
394
+ J = Z * X
395
+ A_flat = A_matrix_torch.permute(0, 3, 1, 2).reshape(T * N, Z * X)
396
+ y_flat = y_torch.reshape(-1)
397
+ theta_0 = torch.ones((Z, X), dtype=torch.float32, device=device)
398
+ matrix_theta_torch = [theta_0]
399
+ I_reconMatrix = [theta_0.cpu().numpy()]
400
+ saved_indices = [0]
401
+ normalization_factor = A_matrix_torch.sum(dim=(0, 3))
402
+ normalization_factor_flat = normalization_factor.reshape(-1)
403
+ adj_index, adj_values = _build_adjacency_sparse(Z, X, device=device)
404
+
405
+ # Calculate save indices
406
+ if numIterations <= max_saves:
407
+ save_indices = list(range(numIterations))
408
+ else:
409
+ step = numIterations // max_saves
410
+ save_indices = list(range(0, numIterations, step))
411
+ if save_indices[-1] != numIterations - 1:
412
+ save_indices.append(numIterations - 1)
413
+
414
+ if Omega == PotentialType.HUBER_PIECEWISE:
415
+ description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse HUBER β:{beta:.4f}, δ:{delta:.4f}) ---- {tumor_str} TUMOR ---- processing on single GPU no.{torch.cuda.current_device()} ----"
416
+ elif Omega == PotentialType.RELATIVE_DIFFERENCE:
417
+ description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse RD β:{beta:.4f}, γ:{gamma:.4f}) ---- {tumor_str} TUMOR ---- processing on single GPU no.{torch.cuda.current_device()} ----"
418
+ elif Omega == PotentialType.QUADRATIC:
419
+ description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse QUADRATIC σ:{sigma:.4f}) ---- {tumor_str} TUMOR ---- processing on single GPU no.{torch.cuda.current_device()} ----"
420
+
421
+ iterator = trange(numIterations, desc=description) if show_logs else range(numIterations)
422
+ for it in iterator:
423
+ theta_p = matrix_theta_torch[-1]
424
+ theta_p_flat = theta_p.reshape(-1)
425
+ q_flat = A_flat @ theta_p_flat
426
+ e_flat = (y_flat - q_flat) / (q_flat + torch.finfo(torch.float32).tiny)
427
+ c_flat = A_flat.T @ e_flat
428
+ if Omega == PotentialType.HUBER_PIECEWISE:
429
+ grad_U, hess_U, _ = _Omega_HUBER_PIECEWISE_GPU(theta_p_flat, adj_index, adj_values, device=device, delta=delta)
430
+ elif Omega == PotentialType.RELATIVE_DIFFERENCE:
431
+ grad_U, hess_U, _ = _Omega_RELATIVE_DIFFERENCE_GPU(theta_p_flat, adj_index, adj_values, device=device, gamma=gamma)
432
+ elif Omega == PotentialType.QUADRATIC:
433
+ grad_U, hess_U, _ = _Omega_QUADRATIC_GPU(theta_p_flat, adj_index, adj_values, device=device, sigma=sigma)
434
+ else:
435
+ raise ValueError(f"Unknown potential type: {Omega}")
436
+ denom = normalization_factor_flat + theta_p_flat * beta * hess_U
437
+ num = theta_p_flat * (c_flat - beta * grad_U)
438
+ theta_p_plus_1_flat = theta_p_flat + num / (denom + torch.finfo(torch.float32).tiny)
439
+ theta_p_plus_1_flat = torch.clamp(theta_p_plus_1_flat, min=0)
440
+ theta_next = theta_p_plus_1_flat.reshape(Z, X)
441
+ matrix_theta_torch.append(theta_next)
442
+ if isSavingEachIteration and it in save_indices:
443
+ I_reconMatrix.append(theta_next.cpu().numpy())
444
+ saved_indices.append(it+1)
445
+
446
+ del A_matrix_torch, y_torch, A_flat, y_flat, theta_0, normalization_factor, normalization_factor_flat
447
+ torch.cuda.empty_cache()
448
+ if isSavingEachIteration:
449
+ return I_reconMatrix, saved_indices
450
+ else:
451
+ return I_reconMatrix[-1], None
452
+ except Exception as e:
453
+ print(f"An error occurred in _MAPEM_GPU: {e}")
454
+ del A_matrix_torch, y_torch, A_flat, y_flat, theta_0, normalization_factor, normalization_factor_flat
455
+ torch.cuda.empty_cache()
456
+ return None, None