




'''simple docstring'''




from __future__ import annotations





def      a_							(      __snake_case							:			str   ,       __snake_case							:			list[str] | None = None   ,       __snake_case							:			dict[str, float] | None = None   ,       __snake_case							:			bool = False   ,       )							->						tuple[int, float, str]:



       """simple docstring"""
       lowerCamelCase_							=cipher_alphabet or [chr(__snake_case   ) for i in range(97   ,       123   )]

       # If the argument is None or the user provided an empty dictionary
       if not frequencies_dict:
              # Frequencies of letters in the english language (how much they show up)
              lowerCamelCase_							={
                  '''a''': 0.0_8_4_9_7,
                  '''b''': 0.0_1_4_9_2,
                  '''c''': 0.0_2_2_0_2,
                  '''d''': 0.0_4_2_5_3,
                  '''e''': 0.1_1_1_6_2,
                  '''f''': 0.0_2_2_2_8,
                  '''g''': 0.0_2_0_1_5,
                  '''h''': 0.0_6_0_9_4,
                  '''i''': 0.0_7_5_4_6,
                  '''j''': 0.0_0_1_5_3,
                  '''k''': 0.0_1_2_9_2,
                  '''l''': 0.0_4_0_2_5,
                  '''m''': 0.0_2_4_0_6,
                  '''n''': 0.0_6_7_4_9,
                  '''o''': 0.0_7_5_0_7,
                  '''p''': 0.0_1_9_2_9,
                  '''q''': 0.0_0_0_9_5,
                  '''r''': 0.0_7_5_8_7,
                  '''s''': 0.0_6_3_2_7,
                  '''t''': 0.0_9_3_5_6,
                  '''u''': 0.0_2_7_5_8,
                  '''v''': 0.0_0_9_7_8,
                  '''w''': 0.0_2_5_6_0,
                  '''x''': 0.0_0_1_5_0,
                  '''y''': 0.0_1_9_9_4,
                  '''z''': 0.0_0_0_7_7,
              }
       else:
              # Custom frequencies dictionary
              lowerCamelCase_							=frequencies_dict

       if not case_sensitive:
              lowerCamelCase_							=ciphertext.lower()

       # Chi squared statistic values
       lowerCamelCase_							={}

       # cycle through all of the shifts
       for shift in range(len(__snake_case   )   ):
              lowerCamelCase_							=''''''

              # decrypt the message with the shift
              for letter in ciphertext:
                     try:
                            # Try to index the letter in the alphabet
                            lowerCamelCase_							=(alphabet_letters.index(letter.lower()   ) - shift) % len(
                                __snake_case   )
                            decrypted_with_shift += (
                                alphabet_letters[new_key].upper()
                                if case_sensitive and letter.isupper()
                                else alphabet_letters[new_key]
                            )
                     except ValueError:
                            # Append the character if it isn't in the alphabet
                            decrypted_with_shift += letter

              lowerCamelCase_							=0.0

              # Loop through each letter in the decoded message with the shift
              for letter in decrypted_with_shift:
                     if case_sensitive:
                            lowerCamelCase_							=letter.lower()
                            if letter in frequencies:
                                   # Get the amount of times the letter occurs in the message
                                   lowerCamelCase_							=decrypted_with_shift.lower().count(__snake_case   )

                                   # Get the excepcted amount of times the letter should appear based
                                   # on letter frequencies
                                   lowerCamelCase_							=frequencies[letter] * occurrences

                                   # Complete the chi squared statistic formula
                                   lowerCamelCase_							=((occurrences - expected) ** 2) / expected

                                   # Add the margin of error to the total chi squared statistic
                                   chi_squared_statistic += chi_letter_value
                     else:
                            if letter.lower() in frequencies:
                                   # Get the amount of times the letter occurs in the message
                                   lowerCamelCase_							=decrypted_with_shift.count(__snake_case   )

                                   # Get the excepcted amount of times the letter should appear based
                                   # on letter frequencies
                                   lowerCamelCase_							=frequencies[letter] * occurrences

                                   # Complete the chi squared statistic formula
                                   lowerCamelCase_							=((occurrences - expected) ** 2) / expected

                                   # Add the margin of error to the total chi squared statistic
                                   chi_squared_statistic += chi_letter_value

        # Add the data to the chi_squared_statistic_values dictionary
              lowerCamelCase_							=(
                  chi_squared_statistic,
                  decrypted_with_shift,
              )

       # Get the most likely cipher by finding the cipher with the smallest chi squared
       # statistic
       def chi_squared_statistic_values_sorting_key(__snake_case							:			int   ) -> tuple[float, str]:
              return chi_squared_statistic_values[key]

       lowerCamelCase_							=min(
           __snake_case   ,       key=__snake_case   ,       )

       # Get all the data from the most likely cipher (key, decoded message)
       (
           (
           lowerCamelCase_						
       ),      (
           lowerCamelCase_						
       ),      						
       )							=chi_squared_statistic_values[most_likely_cipher]

       # Return the data on the most likely shift
       return (
           most_likely_cipher,
           most_likely_cipher_chi_squared_value,
           decoded_most_likely_cipher,
       )











import numpy as np
from PIL import Image



def _a				(	lowerCamelCase:   np.ndarray					,				lowerCamelCase:   int					,				lowerCamelCase:   int )	->						np.ndarray:







      '''simple docstring'''






      __A          =				np.array(lowerCamelCase )
      if arr.shape[0] != arr.shape[1]:
            raise ValueError('''The input array is not a square matrix''' )
      __A          =				0
      __A          =				0
      __A          =				0
      __A          =				0

      # compute the shape of the output matrix
      __A          =				(arr.shape[0] - size) // stride + 1
      # initialize the output matrix with zeros of shape maxpool_shape
      __A          =				np.zeros((maxpool_shape, maxpool_shape) )

      while i < arr.shape[0]:
            if i + size > arr.shape[0]:
                  # if the end of the matrix is reached, break
                  break
            while j < arr.shape[1]:
                  # if the end of the matrix is reached, break
                  if j + size > arr.shape[1]:
                        break
                  # compute the maximum of the pooling matrix
                  __A          =				np.max(arr[i : i + size, j : j + size] )
                  # shift the pooling matrix by stride of column pixels
                  j += stride
                  mat_j += 1

            # shift the pooling matrix by stride of row pixels
            i += stride
            mat_i += 1

            # reset the column index to 0
            __A          =				0
            __A          =				0

      return updated_arr



def _a				(	lowerCamelCase:   np.ndarray					,				lowerCamelCase:   int					,				lowerCamelCase:   int )	->						np.ndarray:







      '''simple docstring'''






      __A          =				np.array(lowerCamelCase )
      if arr.shape[0] != arr.shape[1]:
            raise ValueError('''The input array is not a square matrix''' )
      __A          =				0
      __A          =				0
      __A          =				0
      __A          =				0

      # compute the shape of the output matrix
      __A          =				(arr.shape[0] - size) // stride + 1
      # initialize the output matrix with zeros of shape avgpool_shape
      __A          =				np.zeros((avgpool_shape, avgpool_shape) )

      while i < arr.shape[0]:
            # if the end of the matrix is reached, break
            if i + size > arr.shape[0]:
                  break
            while j < arr.shape[1]:
                  # if the end of the matrix is reached, break
                  if j + size > arr.shape[1]:
                        break
                  # compute the average of the pooling matrix
                  __A          =				int(np.average(arr[i : i + size, j : j + size] ) )
                  # shift the pooling matrix by stride of column pixels
                  j += stride
                  mat_j += 1

            # shift the pooling matrix by stride of row pixels
            i += stride
            mat_i += 1
            # reset the column index to 0
            __A          =				0
            __A          =				0

      return updated_arr


# Main Function
if __name__ == "__main__":
       from doctest import testmod

       testmod(name='avgpooling', verbose=True)

       # Loading the image
       snake_case__					:							Optional[Any]													=     Image.open('path_to_image')

       # Converting the image to numpy array and maxpooling, displaying the result
       # Ensure that the image is a square matrix

       Image.fromarray(maxpooling(np.array(image), size=3, stride=2)).show()

       # Converting the image to numpy array and averagepooling, displaying the result
       # Ensure that the image is a square matrix

       Image.fromarray(avgpooling(np.array(image), size=3, stride=2)).show()





