



import numpy as np

import datasets


lowerCAmelCase__					  =  '''
Compute the Mahalanobis Distance

Mahalonobis distance is the distance between a point and a distribution.
And not between two distinct points. It is effectively a multivariate equivalent of the Euclidean distance.
It was introduced by Prof. P. C. Mahalanobis in 1936
and has been used in various statistical applications ever since
[source: https://www.machinelearningplus.com/statistics/mahalanobis-distance/]
'''

lowerCAmelCase__					  =  '''\
@article{de2000mahalanobis,
  title={The mahalanobis distance},
  author={De Maesschalck, Roy and Jouan-Rimbaud, Delphine and Massart, D{\'e}sir{\'e} L},
  journal={Chemometrics and intelligent laboratory systems},
  volume={50},
  number={1},
  pages={1--18},
  year={2000},
  publisher={Elsevier}
}
'''

lowerCAmelCase__					  =  '''
Args:
    X: List of datapoints to be compared with the `reference_distribution`.
    reference_distribution: List of datapoints from the reference distribution we want to compare to.
Returns:
    mahalanobis: The Mahalonobis distance for each datapoint in `X`.
Examples:

    >>> mahalanobis_metric = datasets.load_metric("mahalanobis")
    >>> results = mahalanobis_metric.compute(reference_distribution=[[0, 1], [1, 0]], X=[[0, 1]])
    >>> print(results)
    {\'mahalanobis\': array([0.5])}
'''

@datasets.utils.file_utils.add_start_docstrings(_DESCRIPTION    ,      _KWARGS_DESCRIPTION      )
class 				snake_case__(datasets.Metric      ):

					"""simple docstring"""






					def 			snake_case					(							self :     List[str]					):
									return datasets.MetricInfo(
									    description=_DESCRIPTION				,       citation=_CITATION				,       inputs_description=_KWARGS_DESCRIPTION				,       features=datasets.Features(
									        {
									            "X": datasets.Sequence(datasets.Value("float"				,       id="sequence"					)				,       id="X"					),
									        }					)				,       )







					def 			snake_case					(							self :     str				,       SCREAMING_SNAKE_CASE :     Any				,       SCREAMING_SNAKE_CASE :     Tuple					):
									# convert to numpy arrays
									lowercase__					:   Union[str, Any]													=					np.array(SCREAMING_SNAKE_CASE					)
									lowercase__					:   List[str]													=					np.array(SCREAMING_SNAKE_CASE					)

									# Assert that arrays are 2D
									if len(X.shape					) != 2:
													raise ValueError("Expected `X` to be a 2D vector"					)
									if len(reference_distribution.shape					) != 2:
													raise ValueError("Expected `reference_distribution` to be a 2D vector"					)
									if reference_distribution.shape[0] < 2:
													raise ValueError(
													    "Expected `reference_distribution` to be a 2D vector with more than one element in the first dimension"					)

									# Get mahalanobis distance for each prediction
									lowercase__					:   int													=					X - np.mean(SCREAMING_SNAKE_CASE					)
									lowercase__					:   int													=					np.cov(reference_distribution.T					)
									try:
													lowercase__					:   Dict													=					np.linalg.inv(SCREAMING_SNAKE_CASE					)
									except np.linalg.LinAlgError:
													lowercase__					:   str													=					np.linalg.pinv(SCREAMING_SNAKE_CASE					)
									lowercase__					:   str													=					np.dot(SCREAMING_SNAKE_CASE				,       SCREAMING_SNAKE_CASE					)
									lowercase__					:   Tuple													=					np.dot(SCREAMING_SNAKE_CASE				,       X_minus_mu.T					).diagonal()

									return {"mahalanobis": mahal_dist}









from collections.abc import Iterator, MutableMapping
from dataclasses import dataclass
from typing import Generic, TypeVar

lowerCAmelCase__					  =  TypeVar('''KEY''')
lowerCAmelCase__					  =  TypeVar('''VAL''')

@dataclass(frozen=_UpperCamelCase    ,      slots=_UpperCamelCase      )
class 				snake_case__(Generic[KEY, VAL]      ):

					"""simple docstring"""






					lowercase_								=		42
					lowercase_								=		42






class 				snake_case__(_Item      ):

					"""simple docstring"""






					def __init__(							self :     List[str]					):
									super().__init__(SCREAMING_SNAKE_CASE				,       SCREAMING_SNAKE_CASE					)







					def __bool__(							self :     Tuple					):
									return False






lowerCAmelCase__					  =  _DeletedItem()

class 				snake_case__(MutableMapping[KEY, VAL]      ):

					"""simple docstring"""






					def __init__(							self :     Any				,       SCREAMING_SNAKE_CASE :     int = 8				,       SCREAMING_SNAKE_CASE :     float = 0.75					):
									lowercase__					:   Any													=					initial_block_size
									lowercase__					:   list[_Item | None]													=					[None] * initial_block_size
									assert 0.0 < capacity_factor < 1.0
									lowercase__					:   Dict													=					capacity_factor
									lowercase__					:   Optional[int]													=					0







					def 			snake_case					(							self :     Optional[Any]				,       SCREAMING_SNAKE_CASE :     KEY					):
									return hash(SCREAMING_SNAKE_CASE					) % len(self._buckets					)







					def 			snake_case					(							self :     Optional[int]				,       SCREAMING_SNAKE_CASE :     int					):
									return (ind + 1) % len(self._buckets					)







					def 			snake_case					(							self :     Tuple				,       SCREAMING_SNAKE_CASE :     int				,       SCREAMING_SNAKE_CASE :     KEY				,       SCREAMING_SNAKE_CASE :     VAL					):
									lowercase__					:   Tuple													=					self._buckets[ind]
									if not stored:
													lowercase__					:   int													=					_Item(SCREAMING_SNAKE_CASE				,       SCREAMING_SNAKE_CASE					)
													self._len += 1
													return True
									elif stored.key == key:
													lowercase__					:   str													=					_Item(SCREAMING_SNAKE_CASE				,       SCREAMING_SNAKE_CASE					)
													return True
									else:
													return False







					def 			snake_case					(							self :     str					):
									lowercase__					:   str													=					len(self._buckets					) * self._capacity_factor
									return len(self					) >= int(SCREAMING_SNAKE_CASE					)







					def 			snake_case					(							self :     List[str]					):
									if len(self._buckets					) <= self._initial_block_size:
													return False
									lowercase__					:   Optional[Any]													=					len(self._buckets					) * self._capacity_factor / 2
									return len(self					) < limit







					def 			snake_case					(							self :     List[Any]				,       SCREAMING_SNAKE_CASE :     int					):
									lowercase__					:   Tuple													=					self._buckets
									lowercase__					:   Optional[int]													=					[None] * new_size
									lowercase__					:   int													=					0
									for item in old_buckets:
													if item:
																	self._add_item(item.key				,       item.val					)







					def 			snake_case					(							self :     int					):
									self._resize(len(self._buckets					) * 2					)







					def 			snake_case					(							self :     Optional[Any]					):
									self._resize(len(self._buckets					) // 2					)







					def 			snake_case					(							self :     List[Any]				,       SCREAMING_SNAKE_CASE :     KEY					):
									lowercase__					:   Tuple													=					self._get_bucket_index(SCREAMING_SNAKE_CASE					)
									for _ in range(len(self._buckets					)					):
													yield ind
													lowercase__					:   Union[str, Any]													=					self._get_next_ind(SCREAMING_SNAKE_CASE					)







					def 			snake_case					(							self :     str				,       SCREAMING_SNAKE_CASE :     KEY				,       SCREAMING_SNAKE_CASE :     VAL					):
									for ind in self._iterate_buckets(SCREAMING_SNAKE_CASE					):
													if self._try_set(SCREAMING_SNAKE_CASE				,       SCREAMING_SNAKE_CASE				,       SCREAMING_SNAKE_CASE					):
																	break







					def __setitem__(							self :     List[str]				,       SCREAMING_SNAKE_CASE :     KEY				,       SCREAMING_SNAKE_CASE :     VAL					):
									if self._is_full():
													self._size_up()

									self._add_item(SCREAMING_SNAKE_CASE				,       SCREAMING_SNAKE_CASE					)







					def __delitem__(							self :     int				,       SCREAMING_SNAKE_CASE :     KEY					):
									for ind in self._iterate_buckets(SCREAMING_SNAKE_CASE					):
													lowercase__					:   Union[str, Any]													=					self._buckets[ind]
													if item is None:
																	raise KeyError(SCREAMING_SNAKE_CASE					)
													if item is _deleted:
																	continue
													if item.key == key:
																	lowercase__					:   Optional[int]													=					_deleted
																	self._len -= 1
																	break
									if self._is_sparse():
													self._size_down()







					def __getitem__(							self :     Tuple				,       SCREAMING_SNAKE_CASE :     KEY					):
									for ind in self._iterate_buckets(SCREAMING_SNAKE_CASE					):
													lowercase__					:   Any													=					self._buckets[ind]
													if item is None:
																	break
													if item is _deleted:
																	continue
													if item.key == key:
																	return item.val
									raise KeyError(SCREAMING_SNAKE_CASE					)







					def __len__(							self :     Optional[Any]					):
									return self._len







					def __iter__(							self :     List[str]					):
									yield from (item.key for item in self._buckets if item)







					def __repr__(							self :     str					):
									lowercase__					:   int													=					" ,".join(
									    f"""{item.key}: {item.val}""" for item in self._buckets if item					)
									return f"""HashMap({val_string})"""




