



from timeit import timeit

UpperCAmelCase_		 =					{
    """MALAYALAM""": True,
    """String""": False,
    """rotor""": True,
    """level""": True,
    """A""": True,
    """BB""": True,
    """ABC""": False,
    """amanaplanacanalpanama""": True,  # "a man a plan a canal panama"
}
# Ensure our test data is valid
assert all((key == key[::-1]) is value for key, value in test_data.items())

def 	SCREAMING_SNAKE_CASE_							(	_snake_case	:Any				)  ->     Tuple:
   _A      =       0
   _A      =       len(_snake_case				) - 1
   while start_i < end_i:
      if s[start_i] == s[end_i]:
         start_i += 1
         end_i -= 1
      else:
         return False
   return True

def 	SCREAMING_SNAKE_CASE_							(	_snake_case	:Optional[Any]				)  ->     Optional[int]:
   _A      =       len(_snake_case				) // 2
   _A      =       len(_snake_case				)

   # We need to traverse till half of the length of string
   # as we can get access of the i'th last element from
   # i'th index.
   # eg: [0,1,2,3,4,5] => 4th index can be accessed
   # with the help of 1st index (i==n-i-1)
   # where n is length of string
   return all(s[i] == s[n - i - 1] for i in range(_snake_case				)				)

def 	SCREAMING_SNAKE_CASE_							(	_snake_case	:Any				)  ->     Optional[int]:
   if len(_snake_case				) <= 2:
      return True
   if s[0] == s[len(_snake_case				) - 1]:
      return is_palindrome_recursive(s[1:-1]				)
   else:
      return False

def 	SCREAMING_SNAKE_CASE_							(	_snake_case	:Optional[Any]				)  ->     int:
   return s == s[::-1]

def 	SCREAMING_SNAKE_CASE_							(	_snake_case	:str				)  ->     Any:
   _A      =       F'''all({name}(key) is value for key, value in test_data.items())'''
   _A      =       F'''from __main__ import test_data, {name}'''
   _A      =       500_000
   _A      =       timeit(stmt=_snake_case	,   setup=_snake_case	,   number=_snake_case				)
   print(F'''{name:<35} finished {number:,} runs in {result:.5f} seconds'''				)


if __name__ == "__main__":
   for key, value in test_data.items():
      assert is_palindrome(key) is is_palindrome_recursive(key)
      assert is_palindrome(key) is is_palindrome_slice(key)
      print(f'{key:21} {value}')
   print("""a man a plan a canal panama""")

   # finished 500,000 runs in 0.46793 seconds
   benchmark_function("""is_palindrome_slice""")
   # finished 500,000 runs in 0.85234 seconds
   benchmark_function("""is_palindrome""")
   # finished 500,000 runs in 1.32028 seconds
   benchmark_function("""is_palindrome_recursive""")
   # finished 500,000 runs in 2.08679 seconds
   benchmark_function("""is_palindrome_traversal""")






import logging

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

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



def 			_A	(      SCREAMING_SNAKE_CASE      ):
	return input_array.reshape((input_array.size, 1)      )



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

	return covariance_sum / features.shape[1]



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

	return covariance_sum / features.shape[1]



def 			_A	(      SCREAMING_SNAKE_CASE	,SCREAMING_SNAKE_CASE      ):

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

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



def 			_A	(      SCREAMING_SNAKE_CASE	,SCREAMING_SNAKE_CASE	,SCREAMING_SNAKE_CASE	,SCREAMING_SNAKE_CASE      ):
	assert classes > dimensions

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

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



def 			_A	(      ):
	# Create dummy dataset with 2 classes and 3 features
	UpperCAmelCase__:	List[str]									= np.array([[1, 2, 3, 4, 5], [2, 3, 4, 5, 6], [3, 4, 5, 6, 7]]      )
	UpperCAmelCase__:	Optional[int]									= np.array([0, 0, 0, 1, 1]      )
	UpperCAmelCase__:	List[Any]									= 2
	UpperCAmelCase__:	Union[str, Any]									= 2

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



def 			_A	(      ):
	UpperCAmelCase__:	Optional[Any]									= np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]      )
	UpperCAmelCase__:	Optional[int]									= 2
	UpperCAmelCase__:	Union[str, Any]									= np.array([[6.92_82_03_23, 8.66_02_54_04, 10.39_23_04_85], [3.0, 3.0, 3.0]]      )

	with pytest.raises(SCREAMING_SNAKE_CASE      ) as error_info:
		UpperCAmelCase__:	Any									= principal_component_analysis(SCREAMING_SNAKE_CASE	,SCREAMING_SNAKE_CASE      )
		if not np.allclose(SCREAMING_SNAKE_CASE	,SCREAMING_SNAKE_CASE      ):
			raise AssertionError
		assert error_info.type is AssertionError


if __name__ == "__main__":
					import doctest

					doctest.testmod()