FEAST-py 0.1.7__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.
@@ -0,0 +1,711 @@
1
+ import anndata as ad
2
+ import numpy as np
3
+ from typing import Union, List, Dict, Optional, Any
4
+ import warnings
5
+
6
+ # Import core simulation functions
7
+ from .simulator import simulate_single_slice, SpatialSimulator
8
+ # from .parameter_cloud_interpolation import (
9
+ # batch_interpolate_parameter_clouds,
10
+ # interpolate_slice_with_statistical_modeling,
11
+ # interpolate_parameter_clouds_with_continuous_ot
12
+ # )
13
+
14
+ # from .continuous_ot_interpolation import (
15
+ # interpolate_with_continuous_ot,
16
+ # interpolate_with_trajectory_ot,
17
+ # validate_interpolation_quality
18
+ # )
19
+
20
+ # Import specialized simulators
21
+ from ..alignment.alignment_simulator import (
22
+ AlignmentSimulator,
23
+ simulate_alignment_rotation,
24
+ simulate_alignment_warp,
25
+ generate_alignment_benchmark_suite
26
+ )
27
+
28
+ from ..deconvolution.deconvolution_simulator import (
29
+ DeconvolutionSimulator,
30
+ simulate_deconvolution_from_single_cells,
31
+ create_deconvolution_benchmark_suite
32
+ )
33
+
34
+ from ..deconvolution.generate_deconvolution import (
35
+ create_deconvolution_benchmark_data
36
+ )
37
+
38
+ from ..deconvolution.deconvolution_simulator import (
39
+ DeconvolutionSimulator,
40
+ simulate_deconvolution_from_single_cells,
41
+ create_deconvolution_benchmark_suite
42
+ )
43
+
44
+
45
+ class FEAST:
46
+ """
47
+ Unified FEAST API for all spatial transcriptomics simulation tasks.
48
+
49
+ This class provides a single entry point for:
50
+ - Single slice simulation
51
+ - Alignment simulation
52
+ - Deconvolution simulation
53
+ - Multi-slice reconstruction
54
+
55
+ The simulator automatically detects whether you're working with single or
56
+ multiple slices and provides appropriate methods.
57
+ """
58
+
59
+ def __init__(self, adata: Union[ad.AnnData, List[ad.AnnData]], verbose: bool = True):
60
+ """
61
+ Initialize FEAST with spatial transcriptomics data.
62
+
63
+ Parameters:
64
+ -----------
65
+ adata : AnnData or List[AnnData]
66
+ Single AnnData object for single slice operations, or list of
67
+ AnnData objects for multi-slice reconstruction
68
+ verbose : bool
69
+ Whether to print progress messages
70
+ """
71
+ self.verbose = verbose
72
+ self.is_multi_slice = isinstance(adata, list)
73
+
74
+ if self.is_multi_slice:
75
+ self.adata_list = adata
76
+ self.n_slices = len(adata)
77
+ if self.verbose:
78
+ print(f"✓ FEAST initialized with {self.n_slices} slices")
79
+ for i, slice_data in enumerate(adata):
80
+ print(f" Slice {i}: {slice_data.shape}")
81
+ else:
82
+ self.adata = adata
83
+ if self.verbose:
84
+ print(f"✓ FEAST initialized with single slice: {adata.shape}")
85
+
86
+ # Initialize specialized simulators (lazy loading)
87
+ self._core_simulator = None
88
+ self._alignment_simulator = None
89
+ self._deconvolution_simulator = None
90
+ self._deconvolution_simulator = None
91
+
92
+ def _get_core_simulator(self):
93
+ """Lazy initialization of core simulator."""
94
+ if self._core_simulator is None:
95
+ if self.is_multi_slice:
96
+ warnings.warn("Core simulator requires single slice. Using first slice.")
97
+ self._core_simulator = SpatialSimulator(self.adata_list[0])
98
+ else:
99
+ self._core_simulator = SpatialSimulator(self.adata)
100
+ return self._core_simulator
101
+
102
+ def _get_alignment_simulator(self):
103
+ """Lazy initialization of alignment simulator."""
104
+ if self._alignment_simulator is None:
105
+ if self.is_multi_slice:
106
+ warnings.warn("Alignment simulator requires single slice. Using first slice.")
107
+ data_to_use = self.adata_list[0]
108
+ else:
109
+ data_to_use = self.adata
110
+ self._alignment_simulator = AlignmentSimulator(data_to_use, verbose=self.verbose)
111
+ return self._alignment_simulator
112
+
113
+ def _get_deconvolution_simulator(self):
114
+ """Lazy initialization of deconvolution simulator."""
115
+ if self._deconvolution_simulator is None:
116
+ self._deconvolution_simulator = DeconvolutionSimulator(verbose=self.verbose)
117
+ return self._deconvolution_simulator
118
+
119
+ def _get_deconvolution_simulator(self):
120
+ """Lazy initialization of deconvolution simulator."""
121
+ if self._deconvolution_simulator is None:
122
+ self._deconvolution_simulator = DeconvolutionSimulator(verbose=self.verbose)
123
+ return self._deconvolution_simulator
124
+
125
+ # ===============================
126
+ # SINGLE SLICE SIMULATION METHODS
127
+ # ===============================
128
+
129
+ def simulate_single_slice(self,
130
+ sigma: float = 1.0,
131
+ follower_sigma_factor: float = 0.1,
132
+ visualize_fits: bool = False,
133
+ num_simulation_cores: int = 12,
134
+ verbose: Optional[bool] = None,
135
+ clip_overshoot_factor: float = 0.1,
136
+ use_real_stats_directly: bool = False,
137
+ annotation_key: Optional[str] = None,
138
+ use_heuristic_search: bool = False,
139
+ min_accepted_error: float = 0.5,
140
+ assignment_weights: Optional[Dict] = None,
141
+ screening_pool_size: int = 100,
142
+ top_n_to_fully_evaluate: int = 10,
143
+ n_jobs: int = -1,
144
+ alteration_config: Optional[Any] = None,
145
+ boundary_multiplier: float = 1.1,
146
+ **kwargs) -> ad.AnnData:
147
+ """
148
+ Generate a single simulated spatial transcriptomics slice.
149
+
150
+ Parameters:
151
+ -----------
152
+ sigma : float, default=1.0
153
+ Spatial smoothness parameter for Gene-Spatial Relevance Based Assignment (G-SRBA).
154
+ - sigma=0: Perfect pattern preservation (zero spatial change)
155
+ - sigma=0.5-1.5: "Gentle" mode, introduces subtle, local variations
156
+ - sigma>2.0: "Exploratory" mode, introduces more significant changes
157
+ follower_sigma_factor : float, default=0.1
158
+ Factor for follower gene spatial smoothness (legacy parameter, now uses correlation-guided interpolation)
159
+ visualize_fits : bool, default=False
160
+ Whether to show fitting visualization plots
161
+ num_simulation_cores : int, default=12
162
+ Number of cores for parallel processing during simulation
163
+ verbose : bool, optional
164
+ Override default verbosity setting
165
+ clip_overshoot_factor : float, default=0.1
166
+ Factor for clipping expression overshoot during simulation
167
+ use_real_stats_directly : bool, default=False
168
+ Whether to use real statistics directly instead of parameter cloud fitting
169
+ annotation_key : str, optional
170
+ Key in adata.obs for annotation-based simulation
171
+ use_heuristic_search : bool, default=False
172
+ Whether to use heuristic search for parameter assignment
173
+ min_accepted_error : float, default=0.5
174
+ Minimum accepted error threshold for heuristic search
175
+ assignment_weights : Dict, optional
176
+ Weights for parameter assignment {'mean': 3.0, 'variance': 1.0, 'zero_prop': 1.0}
177
+ screening_pool_size : int, default=100
178
+ Size of screening pool for heuristic search
179
+ top_n_to_fully_evaluate : int, default=10
180
+ Number of top candidates to fully evaluate in heuristic search
181
+ n_jobs : int, default=-1
182
+ Number of parallel jobs (-1 uses all available cores)
183
+ alteration_config : AlterationConfig, optional
184
+ Configuration for marginal distribution alterations
185
+ boundary_multiplier : float, default=1.1
186
+ Multiplier for maximum count boundary constraint (1.1 = 110% of reference max)
187
+ **kwargs
188
+ Additional parameters passed to simulate_single_slice
189
+
190
+ Returns:
191
+ --------
192
+ AnnData
193
+ Simulated spatial transcriptomics data
194
+ """
195
+ if self.is_multi_slice:
196
+ warnings.warn("Single slice simulation with multi-slice input. Using first slice.")
197
+ adata_to_use = self.adata_list[0]
198
+ else:
199
+ adata_to_use = self.adata
200
+
201
+
202
+ if verbose is None:
203
+ verbose = self.verbose
204
+
205
+ return simulate_single_slice(
206
+ adata_to_use,
207
+ sigma=sigma,
208
+ follower_sigma_factor=follower_sigma_factor,
209
+ visualize_fits=visualize_fits,
210
+ num_simulation_cores=num_simulation_cores,
211
+ verbose=verbose,
212
+ clip_overshoot_factor=clip_overshoot_factor,
213
+ use_real_stats_directly=use_real_stats_directly,
214
+ annotation_key=annotation_key,
215
+ use_heuristic_search=use_heuristic_search,
216
+ min_accepted_error=min_accepted_error,
217
+ assignment_weights=assignment_weights,
218
+ screening_pool_size=screening_pool_size,
219
+ top_n_to_fully_evaluate=top_n_to_fully_evaluate,
220
+ n_jobs=n_jobs,
221
+ alteration_config=alteration_config,
222
+ boundary_multiplier=boundary_multiplier,
223
+ **kwargs
224
+ )
225
+
226
+ # ===============================
227
+ # ALIGNMENT SIMULATION METHODS
228
+ # ===============================
229
+
230
+ def simulate_alignment(self,
231
+ transformation_type: str = 'rotation',
232
+ rotation_angle: float = 0,
233
+ warp_strength: float = 0,
234
+ data_type: str = 'imaging',
235
+ filter_edge_spots: bool = True,
236
+ edge_margin_ratio: float = 0.03,
237
+ fit_params: Optional[Dict] = None,
238
+ expression_params: Optional[Dict] = None,
239
+ sigma: float = 0,
240
+ follower_sigma_factor: float = 0,
241
+ visualize_fits: bool = False,
242
+ num_simulation_cores: int = 12,
243
+ clip_overshoot_factor: float = 0.1,
244
+ use_real_stats_directly: bool = False,
245
+ annotation_key: Optional[str] = None,
246
+ use_heuristic_search: bool = False,
247
+ min_accepted_error: float = 0.5,
248
+ assignment_weights: Optional[Dict] = None,
249
+ screening_pool_size: int = 100,
250
+ top_n_to_fully_evaluate: int = 10,
251
+ n_jobs: int = -1,
252
+ alteration_config: Optional[Any] = None,
253
+ boundary_multiplier: float = 1.1,
254
+ verbose: Optional[bool] = None,
255
+ **kwargs) -> tuple:
256
+ """
257
+ Generate alignment simulation data with spatial transformations.
258
+
259
+ Parameters:
260
+ -----------
261
+ transformation_type : str, default='rotation'
262
+ Type of transformation ('rotation', 'warp', 'cut_move')
263
+ rotation_angle : float, default=45.0
264
+ Rotation angle in degrees (for rotation transformation)
265
+ warp_strength : float, default=0.3
266
+ Warping strength (for TPS warping)
267
+ data_type : str, default='imaging'
268
+ Data type for transformation ('imaging', 'sequencing')
269
+ fit_params : Dict, optional
270
+ Parameters for parameter fitting (merged into simulation parameters)
271
+ expression_params : Dict, optional
272
+ Parameters for expression generation (merged into simulation parameters)
273
+
274
+ # Single slice simulation parameters (same as simulate_single_slice):
275
+ sigma : float, default=1.0
276
+ Spatial smoothness parameter for G-SRBA
277
+ follower_sigma_factor : float, default=0.1
278
+ Factor for follower gene spatial smoothness
279
+ visualize_fits : bool, default=False
280
+ Whether to show fitting visualization plots
281
+ num_simulation_cores : int, default=12
282
+ Number of cores for parallel processing
283
+ clip_overshoot_factor : float, default=0.1
284
+ Factor for clipping expression overshoot
285
+ use_real_stats_directly : bool, default=False
286
+ Whether to use real statistics directly instead of parameter cloud fitting
287
+ annotation_key : str, optional
288
+ Key in adata.obs for annotation-based simulation
289
+ use_heuristic_search : bool, default=False
290
+ Whether to use heuristic search for parameter assignment
291
+ min_accepted_error : float, default=0.5
292
+ Minimum accepted error threshold for heuristic search
293
+ assignment_weights : Dict, optional
294
+ Weights for parameter assignment {'mean': 3.0, 'variance': 1.0, 'zero_prop': 1.0}
295
+ screening_pool_size : int, default=100
296
+ Size of screening pool for heuristic search
297
+ top_n_to_fully_evaluate : int, default=10
298
+ Number of top candidates to fully evaluate
299
+ n_jobs : int, default=-1
300
+ Number of parallel jobs (-1 uses all available cores)
301
+ alteration_config : AlterationConfig, optional
302
+ Configuration for marginal distribution alterations
303
+ boundary_multiplier : float, default=1.1
304
+ Multiplier for maximum count boundary constraint
305
+ verbose : bool, optional
306
+ Override default verbosity setting
307
+ **kwargs
308
+ Additional transformation parameters
309
+
310
+ Returns:
311
+ --------
312
+ tuple
313
+ (original_data, transformed_data) as AnnData objects
314
+ """
315
+ if self.is_multi_slice:
316
+ warnings.warn("Alignment simulation with multi-slice input. Using first slice.")
317
+ adata_to_use = self.adata_list[0]
318
+ else:
319
+ adata_to_use = self.adata
320
+
321
+ if verbose is None:
322
+ verbose = self.verbose
323
+
324
+ # Merge all simulation parameters
325
+ simulation_params = {
326
+ 'sigma': sigma,
327
+ 'follower_sigma_factor': follower_sigma_factor,
328
+ 'visualize_fits': visualize_fits,
329
+ 'num_simulation_cores': num_simulation_cores,
330
+ 'clip_overshoot_factor': clip_overshoot_factor,
331
+ 'use_real_stats_directly': use_real_stats_directly,
332
+ 'annotation_key': annotation_key,
333
+ 'use_heuristic_search': use_heuristic_search,
334
+ 'min_accepted_error': min_accepted_error,
335
+ 'assignment_weights': assignment_weights,
336
+ 'screening_pool_size': screening_pool_size,
337
+ 'top_n_to_fully_evaluate': top_n_to_fully_evaluate,
338
+ 'n_jobs': n_jobs,
339
+ 'alteration_config': alteration_config,
340
+ 'boundary_multiplier': boundary_multiplier,
341
+ 'verbose': verbose,
342
+ }
343
+
344
+ # Override with fit_params and expression_params if provided
345
+ if fit_params:
346
+ simulation_params.update(fit_params)
347
+ if expression_params:
348
+ simulation_params.update(expression_params)
349
+
350
+ # Additional kwargs
351
+ simulation_params.update(kwargs)
352
+
353
+ if transformation_type == 'rotation':
354
+ return simulate_alignment_rotation(
355
+ adata_to_use,
356
+ rotation_angle=rotation_angle,
357
+ data_type=data_type,
358
+ filter_edge_spots=filter_edge_spots,
359
+ edge_margin_ratio=edge_margin_ratio,
360
+ fit_params=simulation_params,
361
+ expression_params={}, # Already merged above
362
+ **kwargs
363
+ )
364
+ elif transformation_type == 'warp':
365
+ return simulate_alignment_warp(
366
+ adata_to_use,
367
+ distort_level=warp_strength,
368
+ filter_edge_spots=filter_edge_spots,
369
+ edge_margin_ratio=edge_margin_ratio,
370
+ fit_params=simulation_params,
371
+ expression_params={}, # Already merged above
372
+ **kwargs
373
+ )
374
+ else:
375
+ raise ValueError(f"Unsupported transformation type: {transformation_type}")
376
+
377
+ def simulate_alignment_benchmark(self,
378
+ transformations: Optional[List[str]] = None,
379
+ parameters: Optional[Dict] = None,
380
+ data_types: Optional[List[str]] = None) -> Dict[str, tuple]:
381
+ """
382
+ Generate comprehensive alignment benchmark suite.
383
+
384
+ Parameters:
385
+ -----------
386
+ transformations : List[str], optional
387
+ List of transformations to test
388
+ parameters : Dict, optional
389
+ Parameters for each transformation type
390
+ data_types : List[str], optional
391
+ Data types to test
392
+
393
+ Returns:
394
+ --------
395
+ Dict[str, tuple]
396
+ Dictionary mapping scenario names to (original, transformed) data pairs
397
+ """
398
+ if self.is_multi_slice:
399
+ warnings.warn("Alignment benchmark with multi-slice input. Using first slice.")
400
+ adata_to_use = self.adata_list[0]
401
+ else:
402
+ adata_to_use = self.adata
403
+
404
+ return generate_alignment_benchmark_suite(
405
+ adata_to_use,
406
+ transformations=transformations,
407
+ parameters=parameters,
408
+ data_types=data_types
409
+ )
410
+
411
+
412
+ def simulate_deconvolution(self,
413
+ cell_type_key: str,
414
+ downsampling_factor: float = 0.25,
415
+ cells_per_spot: int = 50,
416
+ aggregation_method: str = 'sum',
417
+ fractional_rounding: str = 'probabilistic',
418
+ use_ot_assignment: bool = True,
419
+ verbose: Optional[bool] = None) -> ad.AnnData:
420
+ """
421
+ Generate deconvolution simulation data using vine copula + spot marginals approach.
422
+
423
+ This method implements the sophisticated simulation approach:
424
+ 1. Preserves vine copula relationships from real single cell data
425
+ 2. Derives marginal distributions from aggregated spots (cells combined into spots)
426
+ 3. Uses probabilistic fractional rounding (0.5 → 50% chance of 1, 50% chance of 0)
427
+ 4. Applies optimal transport for gene assignment following current simulator methodology
428
+ 5. Uses downsampling_factor to determine realistic number of spots to simulate
429
+
430
+ Parameters:
431
+ -----------
432
+ cell_type_key : str
433
+ Key in adata.obs containing cell type annotations (assumes single-cell input)
434
+ downsampling_factor : float, default=0.25
435
+ Factor to determine number of spots relative to single cells (0.25 = 4x fewer spots than cells)
436
+ cells_per_spot : int, default=50
437
+ Number of cells to aggregate per spot for marginal distribution fitting
438
+ aggregation_method : str, default='sum'
439
+ Method to aggregate cells into spots ('sum', 'mean')
440
+ fractional_rounding : str, default='probabilistic'
441
+ How to handle fractional counts:
442
+ - 'probabilistic': 0.5 → 50% chance of 1, 50% chance of 0
443
+ - 'round': standard rounding
444
+ - 'floor': round down
445
+ use_ot_assignment : bool, default=True
446
+ Whether to use optimal transport for gene assignment (following current simulator)
447
+ verbose : bool, optional
448
+ Override default verbosity setting
449
+
450
+ Returns:
451
+ --------
452
+ AnnData
453
+ Simulated ST data with realistic spot-level expression and ground truth cell type proportions
454
+ """
455
+ if self.is_multi_slice:
456
+ warnings.warn("Deconvolution simulation with multi-slice input. Using first slice.")
457
+ adata_to_use = self.adata_list[0]
458
+ else:
459
+ adata_to_use = self.adata
460
+
461
+ if verbose is None:
462
+ verbose = self.verbose
463
+
464
+ # Calculate number of spots based on downsampling factor
465
+ n_cells = adata_to_use.shape[0]
466
+ n_spots = int(n_cells * downsampling_factor)
467
+
468
+ if verbose:
469
+ print(f"Deconvolution simulation: {n_cells} cells → {n_spots} spots (factor: {downsampling_factor})")
470
+
471
+ return simulate_deconvolution_from_single_cells(
472
+ adata_to_use,
473
+ cell_type_key=cell_type_key,
474
+ n_spots=n_spots,
475
+ cells_per_spot=cells_per_spot,
476
+ aggregation_method=aggregation_method,
477
+ fractional_rounding=fractional_rounding,
478
+ verbose=verbose
479
+ )
480
+
481
+ def create_deconvolution_benchmark(self,
482
+ cell_type_key: str,
483
+ downsampling_factor: float = 0.25,
484
+ grid_type: str = 'hexagonal',
485
+ alpha: float = 0.01,
486
+ verbose: Optional[bool] = None) -> ad.AnnData:
487
+ """
488
+ Create deconvolution benchmark data using fast spatial downsampling.
489
+
490
+ This method creates lower-resolution spatial transcriptomics data with ground truth
491
+ cell type proportions by aggregating spots from existing high-resolution ST data.
492
+ This is fast but just rearranges existing data rather than simulating new data.
493
+
494
+ Parameters:
495
+ -----------
496
+ cell_type_key : str
497
+ Key in adata.obs containing cell type annotations
498
+ downsampling_factor : float, default=0.25
499
+ Factor to reduce spatial resolution (0.25 = 4x fewer spots, 0.1 = 10x fewer spots)
500
+ grid_type : str, default='hexagonal'
501
+ Type of grid for downsampled spots ('hexagonal', 'square', 'kmeans')
502
+ alpha : float, default=0.01
503
+ Alpha shape parameter for tissue boundary detection
504
+ verbose : bool, optional
505
+ Override default verbosity setting
506
+
507
+ Returns:
508
+ --------
509
+ AnnData
510
+ Downsampled ST data with ground truth cell type proportions in .obsm['cell_type_proportions']
511
+ """
512
+ if self.is_multi_slice:
513
+ warnings.warn("Deconvolution benchmark with multi-slice input. Using first slice.")
514
+ adata_to_use = self.adata_list[0]
515
+ else:
516
+ adata_to_use = self.adata
517
+
518
+ if verbose is None:
519
+ verbose = self.verbose
520
+
521
+ return create_deconvolution_benchmark_data(
522
+ adata_to_use,
523
+ downsampling_factor=downsampling_factor,
524
+ grid_type=grid_type,
525
+ cell_type_key=cell_type_key,
526
+ alpha=alpha
527
+ )
528
+
529
+ def simulate_deconvolution_benchmark(self,
530
+ cell_type_key: Optional[str] = None,
531
+ downsampling_factors: List[float] = [0.1, 0.25, 0.5],
532
+ grid_types: List[str] = ['hexagonal', 'square', 'kmeans'],
533
+ alpha: float = 0.01,
534
+ verbose: Optional[bool] = None) -> Dict[str, ad.AnnData]:
535
+ """
536
+ Generate comprehensive deconvolution benchmark suite.
537
+
538
+ Creates multiple spatial resolution scenarios for testing deconvolution algorithms.
539
+
540
+ Parameters:
541
+ -----------
542
+ cell_type_key : str, optional
543
+ Key for cell type annotations (for ground truth)
544
+ downsampling_factors : List[float]
545
+ Different resolution reduction factors to test
546
+ grid_types : List[str]
547
+ Different spatial grid types to test
548
+ alpha : float
549
+ Alpha shape parameter for tissue boundary detection
550
+ verbose : bool, optional
551
+ Override default verbosity setting
552
+
553
+ Returns:
554
+ --------
555
+ Dict[str, AnnData]
556
+ Dictionary mapping scenario names to benchmark datasets
557
+ """
558
+ if self.is_multi_slice:
559
+ warnings.warn("Deconvolution benchmark with multi-slice input. Using first slice.")
560
+ adata_to_use = self.adata_list[0]
561
+ else:
562
+ adata_to_use = self.adata
563
+
564
+ if verbose is None:
565
+ verbose = self.verbose
566
+
567
+ return create_deconvolution_benchmark_suite(
568
+ adata_to_use,
569
+ cell_type_key=cell_type_key,
570
+ downsampling_factors=downsampling_factors,
571
+ grid_types=grid_types,
572
+ alpha=alpha,
573
+ verbose=verbose
574
+ )
575
+
576
+ # ===============================
577
+ # DECONVOLUTION SIMULATION METHODS
578
+ # ===============================
579
+
580
+ def simulate_deconvolution(self,
581
+ downsampling_factor: float = 0.25,
582
+ grid_type: str = 'hexagonal',
583
+ cell_type_key: Optional[str] = None,
584
+ alpha: float = 0.01,
585
+ # Single slice simulation parameters
586
+ sigma: float = 1.0,
587
+ visualize_fits: bool = False,
588
+ use_heuristic_search: bool = False,
589
+ alteration_config: Optional[Any] = None,
590
+ boundary_multiplier: float = 1.1,
591
+ verbose: Optional[bool] = None,
592
+ **simulation_kwargs) -> ad.AnnData:
593
+ """
594
+ Generate deconvolution simulation using two-stage approach:
595
+ 1. High-quality single slice simulation
596
+ 2. Spatial aggregation to create deconvolution data
597
+
598
+ This method combines the robust single slice simulation with spatial
599
+ downsampling to create realistic deconvolution benchmark data.
600
+
601
+ Parameters:
602
+ -----------
603
+ downsampling_factor : float, default=0.25
604
+ Factor to reduce spatial resolution (0.25 = 4x fewer spots)
605
+ grid_type : str, default='hexagonal'
606
+ Type of spatial grid ('hexagonal', 'square', 'kmeans')
607
+ cell_type_key : str, optional
608
+ Key in adata.obs for cell type annotations (ground truth)
609
+ alpha : float, default=0.01
610
+ Alpha parameter for tissue boundary detection
611
+
612
+ Single Slice Simulation Parameters:
613
+ ----------------------------------
614
+ sigma : float, default=1.0
615
+ Spatial smoothness parameter for G-SRBA algorithm
616
+ visualize_fits : bool, default=False
617
+ Whether to show parameter fitting visualizations
618
+ use_heuristic_search : bool, default=False
619
+ Whether to use heuristic parameter assignment
620
+ alteration_config : AlterationConfig, optional
621
+ Configuration for marginal distribution alterations
622
+ boundary_multiplier : float, default=1.1
623
+ Multiplier for maximum count boundary constraint
624
+ verbose : bool, optional
625
+ Override default verbosity setting
626
+ **simulation_kwargs
627
+ Additional parameters passed to simulate_single_slice
628
+
629
+ Returns:
630
+ --------
631
+ AnnData
632
+ Deconvolution simulation data with spatial aggregation
633
+ """
634
+ if self.is_multi_slice:
635
+ raise ValueError("Deconvolution simulation requires single slice input data")
636
+
637
+ if verbose is None:
638
+ verbose = self.verbose
639
+
640
+ simulator = self._get_deconvolution_simulator()
641
+
642
+ return simulator.simulate_deconvolution_data(
643
+ reference_adata=self.reference_adata,
644
+ downsampling_factor=downsampling_factor,
645
+ grid_type=grid_type,
646
+ alpha=alpha,
647
+ cell_type_key=cell_type_key,
648
+ sigma=sigma,
649
+ visualize_fits=visualize_fits,
650
+ use_heuristic_search=use_heuristic_search,
651
+ alteration_config=alteration_config,
652
+ boundary_multiplier=boundary_multiplier,
653
+ verbose=verbose,
654
+ **simulation_kwargs
655
+ )
656
+
657
+ def simulate_deconvolution_benchmark(self,
658
+ cell_type_key: Optional[str] = None,
659
+ downsampling_factors: List[float] = [0.1, 0.25, 0.5],
660
+ grid_types: List[str] = ['hexagonal', 'square'],
661
+ sigma_values: List[float] = [0.5, 1.0, 1.5],
662
+ alpha: float = 0.01,
663
+ verbose: Optional[bool] = None,
664
+ **simulation_kwargs) -> Dict[str, ad.AnnData]:
665
+ """
666
+ Create comprehensive deconvolution benchmark suite.
667
+
668
+ Generates multiple deconvolution scenarios by combining different
669
+ spatial aggregation parameters with single slice simulation parameters.
670
+
671
+ Parameters:
672
+ -----------
673
+ cell_type_key : str, optional
674
+ Key for cell type annotations in reference data
675
+ downsampling_factors : List[float]
676
+ Different resolution reduction factors to test
677
+ grid_types : List[str]
678
+ Different spatial grid types to test
679
+ sigma_values : List[float]
680
+ Different spatial smoothness values for single slice simulation
681
+ alpha : float, default=0.01
682
+ Alpha parameter for tissue boundary detection
683
+ verbose : bool, optional
684
+ Override default verbosity setting
685
+ **simulation_kwargs
686
+ Additional parameters for single slice simulation
687
+
688
+ Returns:
689
+ --------
690
+ Dict[str, AnnData]
691
+ Dictionary of benchmark datasets with descriptive keys
692
+ """
693
+ if self.is_multi_slice:
694
+ raise ValueError("Deconvolution benchmark requires single slice input data")
695
+
696
+ if verbose is None:
697
+ verbose = self.verbose
698
+
699
+ simulator = self._get_deconvolution_simulator()
700
+
701
+ return simulator.create_deconvolution_benchmark_suite(
702
+ reference_adata=self.reference_adata,
703
+ downsampling_factors=downsampling_factors,
704
+ grid_types=grid_types,
705
+ cell_type_key=cell_type_key,
706
+ sigma_values=sigma_values,
707
+ alpha=alpha,
708
+ **simulation_kwargs
709
+ )
710
+
711
+