# Contributing

## Contributing to ultrasound-metrics

We welcome contributions from the community! This guide explains how to contribute to the project.

## Development Setup

1. **Fork and clone the repository:**
   ```bash
   git clone https://github.com/yourusername/ultrasound-metrics.git
   cd ultrasound-metrics
   ```

2. **Install development dependencies:**
   ```bash
   make install
   ```

## Contributing Workflow

### 1. Create a Feature Branch
```bash
git checkout -b feature/your-feature-name
```

### 2. Make Your Changes
- Follow the coding standards (see below)
- Add tests for new functionality
- Update documentation as needed

### 3. Test Your Changes
```bash
# Run linting
make check

# Run tests
make test

# Build documentation
make docs
```

### 4. Submit a Pull Request
- Push your branch to your fork
- Create a pull request with a clear description
- Link any relevant issues

## Coding Standards

### Type Annotations
All public functions should have complete type annotations:

```python
from jaxtyping import Float, Complex, jaxtyped
from beartype import beartype as typechecker

@jaxtyped(typechecker=typechecker)
def new_metric(
    data: Complex[ArrayAPIObj, "elements *dims"],
    param: float = 1.0,
) -> Float[ArrayAPIObj, "*dims"]:
    """Clear docstring with parameters and returns sections."""
```

If you're not sure how to use [`jaxtyping`](https://docs.kidger.site/jaxtyping/),
feel free to open a draft PR and tag a maintainer for help.

### Array API Compliance
- Use `array_namespace()` to detect backend
- Implement using Array API standard functions when possible
- Avoid backend-specific operations
- See [array_api_design.md](concepts/array_api_design.md) for more context

```python
from array_api_compat import array_namespace

def new_metric(data):
    xp = array_namespace(data)
    # Use xp.* operations for backend compatibility
    return xp.mean(xp.abs(data)**2)
```

## Documentation

### Docstring Format
Use NumPy-style docstrings:

```python
def coherence_factor(channel_images, power_based=True):
    """Compute the coherence factor of beamformed ultrasound data.

    The coherence factor measures the degree of coherence between signals
    received from different elements.

    Parameters
    ----------
    channel_images : array_like, shape (receive_elements, *img_dims)
        Complex-valued beamformed data before summation across receive elements.
    power_based : bool, optional
        If True, uses power-based coherence. Default is True.

    Returns
    -------
    coherence : array_like, shape (*img_dims)
        Coherence factor values ranging from 0 to 1.

    References
    ----------
    .. [1] Hollman, K. W., et al. (1999). Coherence factor of speckle from
           a multi-row probe. IEEE Ultrasonics Symposium.
    """
```

### Mathematical Formulations
Try to include precise mathematical descriptions:

```python
def gcnr(values_inside, values_outside):
    """Compute the Generalized Contrast-to-Noise Ratio.

    The GCNR is defined as:

    .. math::
        GCNR = 1 - \\sum_x \\min\\{f_1(x), f_2(x)\\}

    where f_1 and f_2 are the normalized histograms of the inside
    and outside regions, respectively.
    """
```

These will get rendered in the API documentation.

### References
Include literature references for published metrics.

e.g.
```python
"""
    Reference:
    ----------
    A. Rodriguez-Molares, O. M. Hoel Rindal, J. D'hooge, S. -E. Måsøy, A. Austeng
    and H. Torp, "The Generalized Contrast-to-Noise Ratio," 2018 IEEE International
    Ultrasonics Symposium (IUS), Kobe, Japan, 2018, pp. 1-4,
    doi: 10.1109/ULTSYM.2018.8580101.
""""
```

## Testing

### Test Structure
- Place tests in `tests/` directory matching source structure
- Use pytest for all testing
- Test edge cases (empty arrays, single values, 0-values, etc.)
- Test across multiple backends when applicable
- Compare against reference implementations when avaialble

### Backend Testing
For now, we use the `scipy.conftest` backend iterator to test all installed array backends.
It provides the `skip_xp_backends` option to skip unsupported array libraries.

```python
import pytest
from scipy.conftest import array_api_compatible, skip_xp_backends  # noqa: F401

from ultrasound_metrics.metrics.gcnr import gcnr

@pytest.mark.skip_xp_backends("array_api_strict", reason="Array-API v2024.12 does not define histogram.")
@pytest.mark.usefixtures("skip_xp_backends")
@array_api_compatible
def test_gcnr_synthetic_data(xp):
    """Test gCNR calculation with synthetic data simulating a hypoechoic lesion."""
    n_samples = 1000
    # ...
```

### Test Categories
- **Unit tests**: Individual function behavior
- **Backend tests**: Consistency across array libraries
- **Performance tests**: optionally show GPU acceleration
