


from __future__ import annotations

from pprint import pformat
from typing import Generic, TypeVar

UpperCAmelCase					:  List[str]			=						TypeVar("T")







class     __lowercase    (				Generic[T]   ):



		"""simple docstring"""

		def __init__(      self						,	A = True     )   ->      None:







					'''simple docstring'''







					lowerCamelCase  						=   {}  # dictionary of lists
					lowerCamelCase  						=   directed







		def  __A					(      self						,	A						,	A     )   ->      GraphAdjacencyList[T]:







					'''simple docstring'''







					if not self.directed:  # For undirected graphs
								# if both source vertex and destination vertex are both present in the
								# adjacency list, add destination vertex to source vertex list of adjacent
								# vertices and add source vertex to destination vertex list of adjacent
								# vertices.
								if source_vertex in self.adj_list and destination_vertex in self.adj_list:
											self.adj_list[source_vertex].append(__UpperCAmelCase     )
											self.adj_list[destination_vertex].append(__UpperCAmelCase     )
								# if only source vertex is present in adjacency list, add destination vertex
								# to source vertex list of adjacent vertices, then create a new vertex with
								# destination vertex as key and assign a list containing the source vertex
								# as it's first adjacent vertex.
								elif source_vertex in self.adj_list:
											self.adj_list[source_vertex].append(__UpperCAmelCase     )
											lowerCamelCase  						=   [source_vertex]
								# if only destination vertex is present in adjacency list, add source vertex
								# to destination vertex list of adjacent vertices, then create a new vertex
								# with source vertex as key and assign a list containing the source vertex
								# as it's first adjacent vertex.
								elif destination_vertex in self.adj_list:
											self.adj_list[destination_vertex].append(__UpperCAmelCase     )
											lowerCamelCase  						=   [destination_vertex]
								# if both source vertex and destination vertex are not present in adjacency
								# list, create a new vertex with source vertex as key and assign a list
								# containing the destination vertex as it's first adjacent vertex also
								# create a new vertex with destination vertex as key and assign a list
								# containing the source vertex as it's first adjacent vertex.
								else:
											lowerCamelCase  						=   [destination_vertex]
											lowerCamelCase  						=   [source_vertex]
					else:  # For directed graphs
								# if both source vertex and destination vertex are present in adjacency
								# list, add destination vertex to source vertex list of adjacent vertices.
								if source_vertex in self.adj_list and destination_vertex in self.adj_list:
											self.adj_list[source_vertex].append(__UpperCAmelCase     )
								# if only source vertex is present in adjacency list, add destination
								# vertex to source vertex list of adjacent vertices and create a new vertex
								# with destination vertex as key, which has no adjacent vertex
								elif source_vertex in self.adj_list:
											self.adj_list[source_vertex].append(__UpperCAmelCase     )
											lowerCamelCase  						=   []
								# if only destination vertex is present in adjacency list, create a new
								# vertex with source vertex as key and assign a list containing destination
								# vertex as first adjacent vertex
								elif destination_vertex in self.adj_list:
											lowerCamelCase  						=   [destination_vertex]
								# if both source vertex and destination vertex are not present in adjacency
								# list, create a new vertex with source vertex as key and a list containing
								# destination vertex as it's first adjacent vertex. Then create a new vertex
								# with destination vertex as key, which has no adjacent vertex
								else:
											lowerCamelCase  						=   [destination_vertex]
											lowerCamelCase  						=   []

					return self







		def __repr__(      self     )   ->      str:







					'''simple docstring'''







					return pformat(self.adj_list     )






'''simple docstring'''





from __future__ import annotations

import math
from collections import Counter
from string import ascii_lowercase
def    _SCREAMING_SNAKE_CASE  (       UpperCamelCase			):



    """simple docstring"""





    lowerCAmelCase__      ,   lowerCAmelCase__ :  List[str]							      =					analyze_text(UpperCamelCase			)
    lowerCAmelCase__ :  Optional[int]							      =					list(""" """ + ascii_lowercase			)
    # what is our total sum of probabilities.
    lowerCAmelCase__ :  List[Any]							      =					sum(single_char_strings.values()			)

    # one length string
    lowerCAmelCase__ :  Optional[int]							      =					0
    # for each alpha we go in our dict and if it is in it we calculate entropy
    for ch in my_alphas:
        if ch in single_char_strings:
            lowerCAmelCase__ :  List[Any]							      =					single_char_strings[ch]
            lowerCAmelCase__ :  List[Any]							      =					my_str / all_sum
            my_fir_sum += prob * math.loga(UpperCamelCase			)  # entropy formula.

    # print entropy
    print(f"""{round(-1 * my_fir_sum			):.1f}"""			)

    # two len string
    lowerCAmelCase__ :  Dict							      =					sum(two_char_strings.values()			)
    lowerCAmelCase__ :  int							      =					0
    # for each alpha (two in size) calculate entropy.
    for cha in my_alphas:
        for cha in my_alphas:
            lowerCAmelCase__ :  Union[str, Any]							      =					cha + cha
            if sequence in two_char_strings:
                lowerCAmelCase__ :  Dict							      =					two_char_strings[sequence]
                lowerCAmelCase__ :  Tuple							      =					int(UpperCamelCase			) / all_sum
                my_sec_sum += prob * math.loga(UpperCamelCase			)

    # print second entropy
    print(f"""{round(-1 * my_sec_sum			):.1f}"""			)

    # print the difference between them
    print(f"""{round((-1 * my_sec_sum) - (-1 * my_fir_sum)			):.1f}"""			)
def    _SCREAMING_SNAKE_CASE  (       UpperCamelCase			):



    """simple docstring"""





    lowerCAmelCase__ :  Optional[Any]							      =					Counter()  # type: ignore
    lowerCAmelCase__ :  Tuple							      =					Counter()  # type: ignore
    single_char_strings[text[-1]] += 1

    # first case when we have space at start.
    two_char_strings[" " + text[0]] += 1
    for i in range(0							,    len(UpperCamelCase			) - 1			):
        single_char_strings[text[i]] += 1
        two_char_strings[text[i : i + 2]] += 1
    return single_char_strings, two_char_strings
def    _SCREAMING_SNAKE_CASE  (       ):



    """simple docstring"""





    import doctest

    doctest.testmod()
    # text = (
    #     "Had repulsive dashwoods suspicion sincerity but advantage now him. Remark "
    #     "easily garret nor nay. Civil those mrs enjoy shy fat merry. You greatest "
    #     "jointure saw horrible. He private he on be imagine suppose. Fertile "
    #     "beloved evident through no service elderly is. Blind there if every no so "
    #     "at. Own neglected you preferred way sincerity delivered his attempted. To "
    #     "of message cottage windows do besides against uncivil.  Delightful "
    #     "unreserved impossible few estimating men favourable see entreaties. She "
    #     "propriety immediate was improving. He or entrance humoured likewise "
    #     "moderate. Much nor game son say feel. Fat make met can must form into "
    #     "gate. Me we offending prevailed discovery. "
    # )

    # calculate_prob(text)


if __name__ == "__main__":
 main()


