Issue 1:
Describe the bug

When trying to compute AgglomerativeClustering with affinity='precomputed', linkage='ward' I get the following error:

ValueError: precomputed was provided as affinity. Ward can only work with euclidean distances.

I think this is intended. What is the reason behind it?

Steps/Code to Reproduce

from sklearn.cluster import AgglomerativeClustering
from sklearn.metrics.pairwise import euclidean_distances
import numpy as np

X = np.random.normal(size=(2,4))
dist=euclidean_distances(X)
cluster_dist = AgglomerativeClustering(n_clusters=2, affinity='precomputed', linkage='ward')
results_dist = cluster_dist.fit(dist)

Expected Results

The resulting clusters

Actual Results

---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Input In [122], in <module>
2 dist=euclidean_distances(X)
3 cluster_dist = AgglomerativeClustering(n_clusters=n_cluster, affinity='precomputed', linkage='ward')
----> 4 results_dist = cluster_dist.fit(dist)

File ~/Documents/technical/xai_cats_dogs/xai_cats_dogs_venv/lib/python3.9/site-packages/sklearn/cluster/_agglomerative.py:918, in AgglomerativeClustering.fit(self, X, y)
900 """Fit the hierarchical clustering from features, or distance matrix.
901
902 Parameters
(...)
915 Returns the fitted instance.
916 """
917 X = self._validate_data(X, ensure_min_samples=2, estimator=self)
--> 918 return self._fit(X)

File ~/Documents/technical/xai_cats_dogs/xai_cats_dogs_venv/lib/python3.9/site-packages/sklearn/cluster/_agglomerative.py:955, in AgglomerativeClustering._fit(self, X)
950 raise ValueError(
951 "compute_full_tree must be True if distance_threshold is set."
952 )
954 if self.linkage == "ward" and self.affinity != "euclidean":
--> 955 raise ValueError(
956 "%s was provided as affinity. Ward can only "
957 "work with euclidean distances." % (self.affinity,)
958 )
960 if self.linkage not in _TREE_BUILDERS:
961 raise ValueError(
962 "Unknown linkage type %s. Valid options are %s"
963 % (self.linkage, _TREE_BUILDERS.keys())
964 )

ValueError: precomputed was provided as affinity. Ward can only work with euclidean distances.

Versions

System:
python: 3.9.7 (default, Oct 13 2021, 06:45:31) [Clang 13.0.0 (clang-1300.0.29.3)]
executable: /Users/cristianpachon/Documents/technical/xai_cats_dogs/xai_cats_dogs_venv/bin/python
machine: macOS-11.4-x86_64-i386-64bit

Python dependencies:
pip: 21.3.1
setuptools: 60.5.0
sklearn: 1.0.2
numpy: 1.22.2
scipy: 1.8.0
Cython: None
pandas: 1.4.1
matplotlib: 3.5.1
joblib: 1.1.0
threadpoolctl: 3.1.0

Built with OpenMP: True

Issue 2:
Description

Precomputed distances are treated as "unsupported" by AgglomerativeClustering, regardless of the provenance. (e.g. sklearn.metrics.euclidean_distances)

This restriction makes it impossible to pass a off-memory (e.g. memory mapped) precomputed distance matrix, even if it is valid Euclidean distance.

Steps/Code to Reproduce

import numpy as np

from sklearn.metrics import euclidean_distances
from sklearn.cluster import AgglomerativeClustering

X = np.array([[1, 2], [1, 4], [1, 0],[4, 2], [4, 4], [4, 0]])
c = AgglomerativeClustering(affinity='precomputed')
c.fit(euclidean_distances(X))

Expected Results

This probably a bit complicated, as there is no reliable way to determine if the distance matrix actually contains Euclidean distances or is complete nonsense. As precomputed matrices are a somewhat advanced feature, simply relaxing the requirements and assuming users won't pass in invalid distances might be good enough, but that's a decision to be made by the maintainers.

If the matrix was generated from sklearn.metrics, it might be possible to mark a provenance hint somewhere in the object, while it does feel a bit hacky.

Actual Results

In [21]: c.fit(euclidean_distances(X))
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-21-38e0d7bfcae1> in <module>
----> 1 c.fit(euclidean_distances(X))

~/anaconda3/lib/python3.7/site-packages/sklearn/cluster/hierarchical.py in fit(self, X, y)
823 raise ValueError("%s was provided as affinity. Ward can only "
824 "work with euclidean distances." %
--> 825 (self.affinity, ))
826
827 if self.linkage not in _TREE_BUILDERS:

ValueError: precomputed was provided as affinity. Ward can only work with euclidean distances.

Versions

System:

python: 3.7.3 (default, Mar 27 2019, 22:11:17) [GCC 7.3.0]

executable: /home/user/anaconda3/bin/python

machine: Linux-5.0.0-31-generic-x86_64-with-debian-buster-sid

Python deps:

pip: 19.1.1

setuptools: 41.4.0

sklearn: 0.21.3

numpy: 1.16.2

scipy: 1.2.1

Cython: 0.29.12

pandas: 0.24.2

This affects all platforms.