# Requirements Document

## Introduction

The `GeneralizedProcrustesAnalysis` class already declares an `n_jobs` parameter but does not use it for parallel computation. This specification defines the requirements for activating `n_jobs` to parallelize per-specimen operations during GPA alignment, following the established `sklearn.utils.parallel.Parallel`/`delayed` pattern used by `EllipticFourierAnalysis` and `SphericalHarmonicAnalysis` in the same project.

## Requirements

### Requirement 1: Parallel Procrustes Alignment (Shape Mode)

**Objective:** As a researcher, I want GPA shape alignment to parallelize per-specimen Procrustes fitting across multiple cores, so that large specimen collections align faster.

#### Acceptance Criteria

1. When `n_jobs` is not None and `scaling=True` and no semilandmarks are specified, `GeneralizedProcrustesAnalysis` shall use `sklearn.utils.parallel.Parallel` with `delayed` to parallelize the per-specimen Procrustes alignment within each iteration of `_transform_shape`.
2. When `n_jobs=None`, `GeneralizedProcrustesAnalysis` shall execute sequentially with behavior identical to the current implementation.
3. When `n_jobs=1`, `GeneralizedProcrustesAnalysis` shall execute sequentially (single-process) via `Parallel(n_jobs=1)`.
4. The `GeneralizedProcrustesAnalysis` shall produce numerically identical alignment results (mean shape `mu_` and transformed output) regardless of the `n_jobs` value.

### Requirement 2: Parallel Procrustes Alignment (Size-and-Shape Mode)

**Objective:** As a researcher, I want GPA size-and-shape alignment to also benefit from `n_jobs` parallelization, so that both GPA modes are consistently parallelized.

#### Acceptance Criteria

1. When `n_jobs` is not None and `scaling=False`, `GeneralizedProcrustesAnalysis` shall use `Parallel`/`delayed` to parallelize the per-specimen orthogonal Procrustes rotation within each iteration of `_transform_size_and_shape`.
2. The `GeneralizedProcrustesAnalysis` shall produce numerically identical results regardless of the `n_jobs` value in size-and-shape mode.

### Requirement 3: Parallel Semilandmark Sliding

**Objective:** As a researcher, I want semilandmark sliding to be parallelized across specimens, so that GPA with semilandmarks on large datasets is faster.

#### Acceptance Criteria

1. When `n_jobs` is not None and semilandmarks are specified via `curves`, `GeneralizedProcrustesAnalysis` shall use `Parallel`/`delayed` to parallelize the per-specimen sliding and re-projection in `_slide_semilandmarks`.
2. When `n_jobs` is not None and semilandmarks are specified, `GeneralizedProcrustesAnalysis` shall also parallelize the per-specimen orthogonal Procrustes rotation step within the semilandmark GPA loop.
3. The `GeneralizedProcrustesAnalysis` shall produce numerically identical semilandmark sliding results regardless of the `n_jobs` value.

### Requirement 4: API Consistency with Existing Classes

**Objective:** As a developer, I want the `n_jobs` implementation to follow the same pattern as other ktch classes, so that the codebase remains consistent and maintainable.

#### Acceptance Criteria

1. `GeneralizedProcrustesAnalysis` shall import `Parallel` and `delayed` from `sklearn.utils.parallel`.
2. `GeneralizedProcrustesAnalysis` shall pass `n_jobs=self.n_jobs` to the `Parallel` constructor, following the same pattern as `EllipticFourierAnalysis`.
3. When `n_jobs=None`, `GeneralizedProcrustesAnalysis` shall default to sklearn's standard behavior (single-process execution).

### Requirement 5: Testing

**Objective:** As a developer, I want tests that verify parallel execution produces correct results, so that parallelization does not introduce regressions.

#### Acceptance Criteria

1. The test suite shall include parametrized tests over `n_jobs` values (at minimum `None`, `1`, and a value > 1) for shape mode without semilandmarks.
2. The test suite shall include parametrized tests over `n_jobs` values for shape mode with semilandmarks (curve sliding).
3. The test suite shall verify that aligned results are numerically close (within floating-point tolerance) across all `n_jobs` values.
4. The test suite shall follow the project's test co-location pattern at `ktch/landmark/tests/test_procrustes_analysis.py`.
