

from typing import Any

def 			lowerCamelCase__			(       _a				,      _a				,      _a				,      _a				,      _a				,      ):
	_validation(
	    __lowerCAmelCase				,      __lowerCAmelCase				,      __lowerCAmelCase				,      __lowerCAmelCase				,      __lowerCAmelCase				,      )
	# Creates data structures and fill initial step
	SCREAMING_SNAKE_CASE :   Union[str, Any]					  =							{}
	SCREAMING_SNAKE_CASE :   Optional[int]					  =							{}
	for state in states_space:
		SCREAMING_SNAKE_CASE :   str					  =							observations_space[0]
		SCREAMING_SNAKE_CASE :   Tuple					  =							(
		    initial_probabilities[state] * emission_probabilities[state][observation]
		)
		SCREAMING_SNAKE_CASE :   Optional[int]					  =							None

	# Fills the data structure with the probabilities of
	# different transitions and pointers to previous states
	for o in range(1				,      len(__lowerCAmelCase)):
		SCREAMING_SNAKE_CASE :   Any					  =							observations_space[o]
		SCREAMING_SNAKE_CASE :   Optional[Any]					  =							observations_space[o - 1]
		for state in states_space:
			# Calculates the argmax for probability function
			SCREAMING_SNAKE_CASE :   Any					  =							""
			SCREAMING_SNAKE_CASE :   List[Any]					  =							-1
			for k_state in states_space:
				SCREAMING_SNAKE_CASE :   List[str]					  =							(
				    probabilities[(k_state, prior_observation)]
				    * transition_probabilities[k_state][state]
				    * emission_probabilities[state][observation]
				)
				if probability > max_probability:
					SCREAMING_SNAKE_CASE :   int					  =							probability
					SCREAMING_SNAKE_CASE :   List[str]					  =							k_state

				# Update probabilities and pointers dicts
			SCREAMING_SNAKE_CASE :   Any					  =							(
			    probabilities[(arg_max, prior_observation)]
			    * transition_probabilities[arg_max][state]
			    * emission_probabilities[state][observation]
			)

			SCREAMING_SNAKE_CASE :   Tuple					  =							arg_max

    # The final observation
	SCREAMING_SNAKE_CASE :   int					  =							observations_space[len(__lowerCAmelCase) - 1]

	# argmax for given final observation
	SCREAMING_SNAKE_CASE :   Union[str, Any]					  =							""
	SCREAMING_SNAKE_CASE :   List[str]					  =							-1
	for k_state in states_space:
		SCREAMING_SNAKE_CASE :   List[str]					  =							probabilities[(k_state, final_observation)]
		if probability > max_probability:
			SCREAMING_SNAKE_CASE :   List[Any]					  =							probability
			SCREAMING_SNAKE_CASE :   Tuple					  =							k_state
	SCREAMING_SNAKE_CASE :   Any					  =							arg_max

	# Process pointers backwards
	SCREAMING_SNAKE_CASE :   Tuple					  =							last_state
	SCREAMING_SNAKE_CASE :   Optional[int]					  =							[]
	for o in range(len(__lowerCAmelCase) - 1				,      -1				,      -1):
		result.append(__lowerCAmelCase)
		SCREAMING_SNAKE_CASE :   Optional[int]					  =							pointers[previous, observations_space[o]]
	result.reverse()

	return result

def 			lowerCamelCase__			(       _a				,      _a				,      _a				,      _a				,      _a				,      ):
	_validate_not_empty(
	    __lowerCAmelCase				,      __lowerCAmelCase				,      __lowerCAmelCase				,      __lowerCAmelCase				,      __lowerCAmelCase				,      )
	_validate_lists(__lowerCAmelCase				,      __lowerCAmelCase)
	_validate_dicts(
	    __lowerCAmelCase				,      __lowerCAmelCase				,      __lowerCAmelCase)

def 			lowerCamelCase__			(       _a				,      _a				,      _a				,      _a				,      _a				,      ):
	if not all(
	    [
	        observations_space,
	        states_space,
	        initial_probabilities,
	        transition_probabilities,
	        emission_probabilities,
	    ]):
		raise ValueError("There's an empty parameter")

def 			lowerCamelCase__			(       _a				,      _a):
	_validate_list(__lowerCAmelCase				,      "observations_space")
	_validate_list(__lowerCAmelCase				,      "states_space")

def 			lowerCamelCase__			(       _a				,      _a):
	if not isinstance(_object				,      __lowerCAmelCase):
		SCREAMING_SNAKE_CASE :   Union[str, Any]					  =							f"{var_name} must be a list"
		raise ValueError(__lowerCAmelCase)
	else:
		for x in _object:
			if not isinstance(__lowerCAmelCase				,      __lowerCAmelCase):
				SCREAMING_SNAKE_CASE :   Optional[Any]					  =							f"{var_name} must be a list of strings"
				raise ValueError(__lowerCAmelCase)

def 			lowerCamelCase__			(       _a				,      _a				,      _a				,      ):
	_validate_dict(__lowerCAmelCase				,      "initial_probabilities"				,      __lowerCAmelCase)
	_validate_nested_dict(__lowerCAmelCase				,      "transition_probabilities")
	_validate_nested_dict(__lowerCAmelCase				,      "emission_probabilities")

def 			lowerCamelCase__			(       _a				,      _a):
	_validate_dict(_object				,      __lowerCAmelCase				,      __lowerCAmelCase)
	for x in _object.values():
		_validate_dict(__lowerCAmelCase				,      __lowerCAmelCase				,      __lowerCAmelCase				,      __lowerCAmelCase)

def 			lowerCamelCase__			(       _a				,      _a				,      _a				,      _a = False):
	if not isinstance(_object				,      __lowerCAmelCase):
		SCREAMING_SNAKE_CASE :   Union[str, Any]					  =							f"{var_name} must be a dict"
		raise ValueError(__lowerCAmelCase)
	if not all(isinstance(__lowerCAmelCase				,      __lowerCAmelCase) for x in _object):
		SCREAMING_SNAKE_CASE :   List[Any]					  =							f"{var_name} all keys must be strings"
		raise ValueError(__lowerCAmelCase)
	if not all(isinstance(__lowerCAmelCase				,      __lowerCAmelCase) for x in _object.values()):
		SCREAMING_SNAKE_CASE :   Union[str, Any]					  =							"nested dictionary " if nested else ""
		SCREAMING_SNAKE_CASE :   int					  =							f"{var_name} {nested_text}all values must be {value_type.__name__}"
		raise ValueError(__lowerCAmelCase)


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

			testmod()






'''simple docstring'''




from __future__ import annotations

_SCREAMING_SNAKE_CASE							     =			1.6021E-19  # units = C





def 	__lowerCamelCase			(      __lowerCAmelCase       :							float      ,    __lowerCAmelCase       :							float      ,    __lowerCAmelCase       :							float      ,    )		->  tuple[str, float]:
   if (conductivity, electron_conc, mobility).count(0		) != 1:
      raise ValueError("""You cannot supply more or less than 2 values"""		)
   elif conductivity < 0:
      raise ValueError("""Conductivity cannot be negative"""		)
   elif electron_conc < 0:
      raise ValueError("""Electron concentration cannot be negative"""		)
   elif mobility < 0:
      raise ValueError("""mobility cannot be negative"""		)
   elif conductivity == 0:
      return (
          "conductivity",
          mobility * electron_conc * ELECTRON_CHARGE,
      )
   elif electron_conc == 0:
      return (
          "electron_conc",
          conductivity / (mobility * ELECTRON_CHARGE),
      )
   else:
      return (
          "mobility",
          conductivity / (electron_conc * ELECTRON_CHARGE),
      )


if __name__ == "__main__":
 import doctest

 doctest.testmod()

