Gradient Boosting: Tree splitting criterion`"friedman_mse"` isn't different from normal `"mse"`

### Describe the bug

In `sklearn/tree/_criterion.pyx`, criteria `"friedman_mse"` (class `FriedmanMSE(MSE)`) and `"squared_error"` (class `MSE`) are mathematically equivalent, they use different but equivalent formulas. This is confusing, and I think that:
- `"friedman_mse"` criterion should be deprecated then removed.
- the class should be removed

Because `"friedman_mse"` and `"squared_error"` are mathematically equivalent they produce the same trees/forests (up to float precision errors), as shown by the reproducer below.

Also, I tried removing all the code from `FriedmanMSE` class (leaving only the inheritance `FriedmanMSE(MSE)`) and all test passes from `sklearn/tree` and `sklearn/ensemble` except `test_huber_exact_backward_compat` which is sensitive to float rounding errors.
I also tried the other-way around (copy-pasting code from `FriedmanMSE(MSE)` in `MSE`) and except for one bug for which I'll open a separate issue, it worked as well.


Maths (from ChatGPT, but I carefully double-checked it):

<img width="1151" height="565" alt="image" src="https://github.com/user-attachments/assets/7523b114-9c7b-4a20-abeb-dcb2c6d158fc" />

Proof:

<details>

<img width="1271" height="857" alt="image" src="https://github.com/user-attachments/assets/83a92ec6-0f5e-4387-a9d3-fb1b397b0302" />

</details>



### Steps/Code to Reproduce


```Python
import numpy as np
from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor


params_list = [
    {
        'random_state': 0,
        'max_leaf_nodes': max_leaf_nodes,
        'max_depth': max_depth,
        'ccp_alpha': ccp_alpha,
    }
    for max_depth in [None, 1, 2, 3, 5, 10]
    for max_leaf_nodes in [None, 3, 6, 10, 20, 50, 100]
    for ccp_alpha in [0, 0.005, 0.01]
]

for Reg in [DecisionTreeRegressor, RandomForestRegressor, GradientBoostingRegressor]:
    print(Reg)
    for params in params_list:
        n = np.random.choice([10, 100, 1000, 10_000])
        d = np.random.choice([1, 2, 3, 10])
        if Reg in [GradientBoostingRegressor, RandomForestRegressor]:
            params = {**params, 'n_estimators': 10}
        X = np.random.rand(n, 1)
        X_test = np.random.rand(n, 1)
        y = np.random.rand(n) + X.sum(axis=1)

        for w  in [None, np.random.rand(n), np.random.pareto(1, size=n)]:
            tree_mse = Reg(criterion="squared_error", **params)
            tree_friedman = Reg(criterion="friedman_mse",  **params)

            assert np.allclose(
                tree_mse.fit(X, y, sample_weight=w).predict(X_test),
                tree_friedman.fit(X, y, sample_weight=w).predict(X_test)
            )
            if Reg is DecisionTreeRegressor:
                assert np.allclose(tree_mse.tree_.impurity, tree_friedman.tree_.impurity)
```

### Expected Results

You would expect different criteria to give different results and hence this code to raise.

### Actual Results

Doesn't raise.

### Versions

```shell
System:
    python: 3.12.11 (main, Aug 18 2025, 19:19:11) [Clang 20.1.4 ]
executable: /home/arthur/dev-perso/scikit-learn/sklearn-env/bin/python
   machine: Linux-6.14.0-35-generic-x86_64-with-glibc2.39

Python dependencies:
      sklearn: 1.8.dev0
          pip: None
   setuptools: 80.9.0
        numpy: 2.3.4
        scipy: 1.16.2
       Cython: 3.1.5
       pandas: 2.3.3
   matplotlib: 3.10.7
       joblib: 1.5.2
threadpoolctl: 3.6.0

Built with OpenMP: True

threadpoolctl info:
       user_api: blas
   internal_api: openblas
    num_threads: 16
         prefix: libscipy_openblas
       filepath: /home/arthur/dev-perso/scikit-learn/sklearn-env/lib/python3.12/site-packages/numpy.libs/libscipy_openblas64_-8fb3d286.so
        version: 0.3.30
threading_layer: pthreads
   architecture: Haswell

       user_api: blas
   internal_api: openblas
    num_threads: 16
         prefix: libscipy_openblas
       filepath: /home/arthur/dev-perso/scikit-learn/sklearn-env/lib/python3.12/site-packages/scipy.libs/libscipy_openblas-b75cc656.so
        version: 0.3.29.dev
threading_layer: pthreads
   architecture: Haswell

       user_api: openmp
   internal_api: openmp
    num_threads: 16
         prefix: libgomp
       filepath: /usr/lib/x86_64-linux-gnu/libgomp.so.1.0.0
        version: None
```

COMMENT:
And on a more theoretical plan, I think I proved the name "friedman_mse" just has no meaningful sense. Scikit-learn uses "friedman_mse" to designate the use of the Eq 35 in the paper:

<img width="700" height="150" alt="Image" src="https://github.com/user-attachments/assets/bcff7625-3584-4f9e-a601-fa880e38d147" />

.

And my derivations prove this $i^2(R_l, R_r) = SSE(R_{parent}) - SSE(R_l) - SSE(R_r)$ which is precisely what the "squared_error" criterion computes in scikit-learn.

Also, note that the paper just introduces this formula as the "least-square improvement criteria", nothing more, not some kind of special squared error. Then it discusses the impact of weights in this formula indeed.

> If we implemented the correct weights (=unit weights) for "friedman_mse" in scikit-learn is a different matter...

I don't know, but this is just about the `w` in `tree.fit(X, y, w)` in the GBT code, not about the "friedman_mse" criterion.

Maybe it makes sense to keep `criterion` for GBT, but for now, there is just not difference between the two, so I would say it's better to remove it until we maybe figure how to correctly implement the friedman's paper (but not the "friedman_mse", maybe the "friedman_weighting_scheme"?).

Labels: API, Needs Decision, module:tree