Add shrinkage support with `solver="svd"` in `LinearDiscriminantAnalysis` and `QuadraticDiscriminantAnalysis`

### Describe the workflow you want to enable

Both Linear Discriminant Analysis (LDA) and Quadratic Discriminant Analysis (QDA) can be solved with the SVD solver. The SVD solver does not explicitly compute the covariance matrix, so covariance shrinkage is not supported when we set `solver="svd"`, as illustrated in the snippet below:

```python
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
import numpy as np

# Data that has zero variance in one dimension and needs regularization
X = np.random.randn(9, 2)
y = np.array([1, 1, 1, 1, 1, 2, 2, 2, 2])

solver = "svd"
clf = LinearDiscriminantAnalysis(solver=solver, shrinkage=0.5)
clf.fit(X, y)
```
```python
File ~/Packages/scikit-learn/scikit-learn/sklearn/discriminant_analysis.py:700, in LinearDiscriminantAnalysis.fit(self, X, y)
    698 if self.solver == "svd":
    699     if self.shrinkage is not None:
--> 700         raise NotImplementedError("shrinkage not supported with 'svd' solver.")
    701     if self.covariance_estimator is not None:
    702         raise ValueError(
    703             "covariance estimator "
    704             "is not supported "
    705             "with svd solver. Try another solver"
    706         )

NotImplementedError: shrinkage not supported with 'svd' solver.
```
Similar behavior for QDA is implemented in PR #32108.

However, it should be possible to implement shrinkage with the SVD solver that is mathematically equivalent to shrinkage with the other solvers, and it might be desirable to do so (https://github.com/scikit-learn/scikit-learn/pull/32108#discussion_r2454295132).


### Describe your proposed solution

While `solver="svd"` does not explicitly compute the covariance matrix, it relies on the singular values of the data matrix `X` of shape `(n_samples, n_features)`, denoted `S`. The i'th singular value `S[i]` is directly related to the i'th eigenvalue `lambda[i]` of the covariance matrix by the relation `lambda[i] = S[i]**2 / (n - 1)`, where `n` is the number of samples (see [here](https://github.com/scikit-learn/scikit-learn/blob/72d97bceec1af70d9b65bb49d12abdd5694e67f1/sklearn/discriminant_analysis.py#L1019) and [here](https://stats.stackexchange.com/questions/134282/relationship-between-svd-and-pca-how-to-use-svd-to-perform-pca)).

Shrinkage of the covariance matrix [as implemented](https://scikit-learn.org/stable/modules/generated/sklearn.covariance.ShrunkCovariance.html) by the parameter `shrinkage` is just a shrinking of the eigenvalues of the covariance towards the mean eigenvalue.

Given the above, support for the parameter `shrinkage` with `solver="svd"` can be implemented by appropriately shrinking the singular values `S` to match the shrinkage of the implicit eigenvalues. This should be pretty easy to implement.

One detail of this implementation is that when `n_samples < n_features`, then SVD only recovers `n_samples` number of singular values. Implicitly, the rest of the singular values are 0, corresponding to the rank-defficient covariance matrix. To implement shrinkage as suggested here, we would have to pad the vector `S` with zeros up to a length of `n_features` in this case.

### Describe alternatives you've considered, if relevant

_No response_

### Additional context

_No response_

COMMENT:
Hi, I’m interested in this issue and would like to work on it. Could you please assign it to me? Thank you!

Labels: New Feature