
import mpmath  # for roots of unity
import numpy as np





class 							A__		:
      def __init__(      self    ,  __magic_name__=None    ,  __magic_name__=None      ):
       # Input as list
       lowerCamelCase		:	str							=      list(poly_a or [0]      )[:]
       lowerCamelCase		:	Union[str, Any]							=      list(poly_b or [0]      )[:]

       # Remove leading zero coefficients
       while self.polyA[-1] == 0:
        self.polyA.pop()
       lowerCamelCase		:	List[Any]							=      len(self.polyA      )

       while self.polyB[-1] == 0:
        self.polyB.pop()
       lowerCamelCase		:	Union[str, Any]							=      len(self.polyB      )

       # Add 0 to make lengths equal a power of 2
       lowerCamelCase		:	List[str]							=      int(
           2 ** np.ceil(np.loga(len(self.polyA      ) + len(self.polyB      ) - 1      )      )      )

       while len(self.polyA      ) < self.c_max_length:
        self.polyA.append(0      )
       while len(self.polyB      ) < self.c_max_length:
        self.polyB.append(0      )
       # A complex root used for the fourier transform
       lowerCamelCase		:	Optional[int]							=      complex(mpmath.root(x=1    ,  n=self.c_max_length    ,  k=1      )      )

       # The product
       lowerCamelCase		:	Union[str, Any]							=      self.__multiply()
      def 						UpperCamelCase__							(      self    ,  __magic_name__      ):
       lowerCamelCase		:	Optional[int]							=      [[x] for x in self.polyA] if which == """A""" else [[x] for x in self.polyB]
       # Corner case
       if len(__magic_name__      ) <= 1:
        return dft[0]
       #
       lowerCamelCase		:	List[Any]							=      self.c_max_length // 2
       while next_ncol > 0:
        lowerCamelCase		:	Optional[Any]							=      [[] for i in range(__magic_name__      )]
        lowerCamelCase		:	int							=      self.root**next_ncol

        # First half of next step
        lowerCamelCase		:	Tuple							=      1
        for j in range(self.c_max_length // (next_ncol * 2)      ):
         for i in range(__magic_name__      ):
          new_dft[i].append(dft[i][j] + current_root * dft[i + next_ncol][j]      )
         current_root *= root
        # Second half of next step
        lowerCamelCase		:	Optional[Any]							=      1
        for j in range(self.c_max_length // (next_ncol * 2)      ):
         for i in range(__magic_name__      ):
          new_dft[i].append(dft[i][j] - current_root * dft[i + next_ncol][j]      )
         current_root *= root
        # Update
        lowerCamelCase		:	List[str]							=      new_dft
        lowerCamelCase		:	Dict							=      next_ncol // 2
       return dft[0]
      def 						UpperCamelCase__							(      self      ):
       lowerCamelCase		:	str							=      self.__dft("""A"""      )
       lowerCamelCase		:	Optional[int]							=      self.__dft("""B"""      )
       lowerCamelCase		:	Optional[int]							=      [[dft_a[i] * dft_b[i] for i in range(self.c_max_length      )]]
       del dft_a
       del dft_b

       # Corner Case
       if len(inverce_c[0]      ) <= 1:
        return inverce_c[0]
       # Inverse DFT
       lowerCamelCase		:	str							=      2
       while next_ncol <= self.c_max_length:
        lowerCamelCase		:	Tuple							=      [[] for i in range(__magic_name__      )]
        lowerCamelCase		:	List[Any]							=      self.root ** (next_ncol // 2)
        lowerCamelCase		:	Optional[Any]							=      1
        # First half of next step
        for j in range(self.c_max_length // next_ncol      ):
         for i in range(next_ncol // 2      ):
          # Even positions
          new_inverse_c[i].append(
              (
                  inverce_c[i][j]
                  + inverce_c[i][j + self.c_max_length // next_ncol]
              )
              / 2      )
          # Odd positions
          new_inverse_c[i + next_ncol // 2].append(
              (
                  inverce_c[i][j]
                  - inverce_c[i][j + self.c_max_length // next_ncol]
              )
              / (2 * current_root)      )
         current_root *= root
        # Update
        lowerCamelCase		:	Tuple							=      new_inverse_c
        next_ncol *= 2
       # Unpack
       lowerCamelCase		:	int							=      [round(x[0].real    ,  8      ) + round(x[0].imag    ,  8      ) * 1j for x in inverce_c]

       # Remove leading 0's
       while inverce_c[-1] == 0:
        inverce_c.pop()
       return inverce_c






      def __str__(      self      ):
       lowerCamelCase		:	Optional[Any]							=      """A = """ + """ + """.join(
           F'''{coef}*x^{i}''' for coef, i in enumerate(self.polyA[: self.len_A]      )      )
       lowerCamelCase		:	Any							=      """B = """ + """ + """.join(
           F'''{coef}*x^{i}''' for coef, i in enumerate(self.polyB[: self.len_B]      )      )
       lowerCamelCase		:	List[Any]							=      """A*B = """ + """ + """.join(
           F'''{coef}*x^{i}''' for coef, i in enumerate(self.product      )      )

       return F'''{a}\n{b}\n{c}'''


# Unit tests
if __name__ == "__main__":
      import doctest

      doctest.testmod()






def     _a					(						lowerCamelCase							):

 if p < 2:
  raise ValueError("""p should not be less than 2!"""							)
 elif p == 2:
  return True

 lowerCamelCase		:	Any							=      4
 lowerCamelCase		:	List[str]							=      (1 << p) - 1
 for _ in range(p - 2							):
  lowerCamelCase		:	List[Any]							=      ((s * s) - 2) % m
 return s == 0


if __name__ == "__main__":
      print(lucas_lehmer_test(7))
      print(lucas_lehmer_test(1_1))




