'''simple docstring'''




import logging

import numpy as np
import pytest
from scipy.linalg import eigh

logging.basicConfig(level=logging.INFO, format="""%(message)s""")

def 	UpperCamelCase_							(					_UpperCAmelCase  :      np.ndarray    )    ->    np.ndarray:


       """simple docstring"""







       return input_array.reshape((input_array.size, 1)    )

def 	UpperCamelCase_							(					_UpperCAmelCase  :      np.ndarray			,	_UpperCAmelCase  :      np.ndarray			,	_UpperCAmelCase  :      int    )    ->    np.ndarray:


       """simple docstring"""







       _UpperCAmelCase     :  Dict							      =    np.nan
       for i in range(_UpperCAmelCase    ):
              _UpperCAmelCase     :  Union[str, Any]							      =    features[:, labels == i]
              _UpperCAmelCase     :  Dict							      =    data.mean(1    )
              # Centralize the data of class i
              _UpperCAmelCase     :  Any							      =    data - column_reshape(_UpperCAmelCase    )
              if i > 0:
                     # If covariance_sum is not None
                     covariance_sum += np.dot(_UpperCAmelCase			,	centered_data.T    )
              else:
                     # If covariance_sum is np.nan (i.e. first loop)
                     _UpperCAmelCase     :  Tuple							      =    np.dot(_UpperCAmelCase			,	centered_data.T    )

       return covariance_sum / features.shape[1]

def 	UpperCamelCase_							(					_UpperCAmelCase  :      np.ndarray			,	_UpperCAmelCase  :      np.ndarray			,	_UpperCAmelCase  :      int    )    ->    np.ndarray:


       """simple docstring"""







       _UpperCAmelCase     :  Any							      =    features.mean(1    )
       _UpperCAmelCase     :  Tuple							      =    np.nan
       for i in range(_UpperCAmelCase    ):
              _UpperCAmelCase     :  int							      =    features[:, labels == i]
              _UpperCAmelCase     :  Dict							      =    data.shape[1]
              _UpperCAmelCase     :  Dict							      =    data.mean(1    )
              if i > 0:
                     # If covariance_sum is not None
                     covariance_sum += device_data * np.dot(
                         column_reshape(_UpperCAmelCase    ) - column_reshape(_UpperCAmelCase    )			,	(column_reshape(_UpperCAmelCase    ) - column_reshape(_UpperCAmelCase    )).T			,	)
              else:
                     # If covariance_sum is np.nan (i.e. first loop)
                     _UpperCAmelCase     :  int							      =    device_data * np.dot(
                         column_reshape(_UpperCAmelCase    ) - column_reshape(_UpperCAmelCase    )			,	(column_reshape(_UpperCAmelCase    ) - column_reshape(_UpperCAmelCase    )).T			,	)

       return covariance_sum / features.shape[1]

def 	UpperCamelCase_							(					_UpperCAmelCase  :      np.ndarray			,	_UpperCAmelCase  :      int    )    ->    np.ndarray:


       """simple docstring"""







       if features.any():
              _UpperCAmelCase     :  Any							      =    features.mean(1    )
              # Center the dataset
              _UpperCAmelCase     :  Tuple							      =    features - np.reshape(_UpperCAmelCase			,	(data_mean.size, 1)    )
              _UpperCAmelCase     :  List[str]							      =    np.dot(_UpperCAmelCase			,	centered_data.T    ) / features.shape[1]
              _UpperCAmelCase      ,  _UpperCAmelCase     :  Union[str, Any]							      =    np.linalg.eigh(_UpperCAmelCase    )
              # Take all the columns in the reverse order (-1), and then takes only the first
              _UpperCAmelCase     :  Tuple							      =    eigenvectors[:, ::-1][:, 0:dimensions]
              # Project the database on the new space
              _UpperCAmelCase     :  List[Any]							      =    np.dot(filtered_eigenvectors.T			,	_UpperCAmelCase    )
              logging.info("Principal Component Analysis computed"    )

              return projected_data
       else:
              logging.basicConfig(level=logging.ERROR			,	format="%(message)s"			,	force=_UpperCAmelCase    )
              logging.error("Dataset empty"    )
              raise AssertionError

def 	UpperCamelCase_							(					_UpperCAmelCase  :      np.ndarray			,	_UpperCAmelCase  :      np.ndarray			,	_UpperCAmelCase  :      int			,	_UpperCAmelCase  :      int    )    ->    np.ndarray:


       """simple docstring"""







       assert classes > dimensions

       # Check if features have been already loaded
       if features.any:
              _UpperCAmelCase      ,  _UpperCAmelCase     :  str							      =    eigh(
                  covariance_between_classes(_UpperCAmelCase			,	_UpperCAmelCase			,	_UpperCAmelCase    )			,	covariance_within_classes(_UpperCAmelCase			,	_UpperCAmelCase			,	_UpperCAmelCase    )			,	)
              _UpperCAmelCase     :  Any							      =    eigenvectors[:, ::-1][:, :dimensions]
              _UpperCAmelCase      ,  _UpperCAmelCase      ,  _UpperCAmelCase     :  List[Any]							      =    np.linalg.svd(_UpperCAmelCase    )
              _UpperCAmelCase     :  Union[str, Any]							      =    svd_matrix[:, 0:dimensions]
              _UpperCAmelCase     :  List[str]							      =    np.dot(filtered_svd_matrix.T			,	_UpperCAmelCase    )
              logging.info("Linear Discriminant Analysis computed"    )

              return projected_data
       else:
              logging.basicConfig(level=logging.ERROR			,	format="%(message)s"			,	force=_UpperCAmelCase    )
              logging.error("Dataset empty"    )
              raise AssertionError

def 	UpperCamelCase_							(					)    ->    None:


       """simple docstring"""







       _UpperCAmelCase     :  Dict							      =    np.array([[1, 2, 3, 4, 5], [2, 3, 4, 5, 6], [3, 4, 5, 6, 7]]    )
       _UpperCAmelCase     :  Dict							      =    np.array([0, 0, 0, 1, 1]    )
       _UpperCAmelCase     :  Tuple							      =    2
       _UpperCAmelCase     :  int							      =    2

       # Assert that the function raises an AssertionError if dimensions > classes
       with pytest.raises(_UpperCAmelCase    ) as error_info:
              _UpperCAmelCase     :  Any							      =    linear_discriminant_analysis(
                  _UpperCAmelCase			,	_UpperCAmelCase			,	_UpperCAmelCase			,	_UpperCAmelCase    )
              if isinstance(_UpperCAmelCase			,	np.ndarray    ):
                     raise AssertionError(
                         "Did not raise AssertionError for dimensions > classes"    )
              assert error_info.type is AssertionError

def 	UpperCamelCase_							(					)    ->    None:


       """simple docstring"""







       _UpperCAmelCase     :  Optional[int]							      =    np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]    )
       _UpperCAmelCase     :  Optional[int]							      =    2
       _UpperCAmelCase     :  List[Any]							      =    np.array([[6.9_2_8_2_0_3_2_3, 8.6_6_0_2_5_4_0_4, 1_0.3_9_2_3_0_4_8_5], [3.0, 3.0, 3.0]]    )

       with pytest.raises(_UpperCAmelCase    ) as error_info:
              _UpperCAmelCase     :  Optional[Any]							      =    principal_component_analysis(_UpperCAmelCase			,	_UpperCAmelCase    )
              if not np.allclose(_UpperCAmelCase			,	_UpperCAmelCase    ):
                     raise AssertionError
              assert error_info.type is AssertionError


if __name__ == "__main__":
  import doctest

  doctest.testmod()


'''simple docstring'''




__SCREAMING_SNAKE_CASE       :     Dict     =  8.3_1_4_4_6_2  # Unit - J mol-1 K-1

def 	UpperCamelCase_							(					_UpperCAmelCase  :      float			,	_UpperCAmelCase  :      float			,	_UpperCAmelCase  :      float    )    ->    float:


       """simple docstring"""







       if moles < 0 or kelvin < 0 or volume < 0:
              raise ValueError("Invalid inputs. Enter positive value."    )
       return moles * kelvin * UNIVERSAL_GAS_CONSTANT / volume

def 	UpperCamelCase_							(					_UpperCAmelCase  :      float			,	_UpperCAmelCase  :      float			,	_UpperCAmelCase  :      float    )    ->    float:


       """simple docstring"""







       if moles < 0 or kelvin < 0 or pressure < 0:
              raise ValueError("Invalid inputs. Enter positive value."    )
       return moles * kelvin * UNIVERSAL_GAS_CONSTANT / pressure


if __name__ == "__main__":
  from doctest import testmod

  testmod()

