
from __future__ import annotations

from collections.abc import Callable
from typing import Generic, TypeVar

SCREAMING_SNAKE_CASE__							=				TypeVar("""T""")
SCREAMING_SNAKE_CASE__							=				TypeVar("""U""")
class 	A__   (						Generic[T, U]				):





							def __init__( self  :   int     , _UpperCAmelCase  :   List[str]     , _UpperCAmelCase  :   List[Any]				)						->		Dict:



											"""simple docstring"""


											__lowercase								=					key
											__lowercase								=					val
											__lowercase								=					None
											__lowercase								=					None





							def __repr__( self  :   Optional[Any]				)						->		str:



											"""simple docstring"""


											return (
											    f"""Node: key: {self.key}, val: {self.val}, """
											    f"""has next: {bool(self.next				)}, has prev: {bool(self.prev				)}"""
											)






class 	A__   (						Generic[T, U]				):





							def __init__( self  :   int				)						->		None:



											"""simple docstring"""


											__lowercase								=					DoubleLinkedListNode(lowercase_     , lowercase_				)
											__lowercase								=					DoubleLinkedListNode(lowercase_     , lowercase_				)
											__lowercase		,					__lowercase								=					self.rear, self.head





							def __repr__( self  :   Tuple				)						->		str:



											"""simple docstring"""


											__lowercase								=					['DoubleLinkedList']
											__lowercase								=					self.head
											while node.next is not None:
															rep.append(str(lowercase_				)				)
															__lowercase								=					node.next
											rep.append(str(self.rear				)				)
											return ",\n    ".join(lowercase_				)





							def 			a__ ( self  :   Any     , _UpperCAmelCase  :   int				)						->		None:



											"""simple docstring"""


											__lowercase								=					self.rear.prev

											# All nodes other than self.head are guaranteed to have non-None previous
											assert previous is not None

											__lowercase								=					node
											__lowercase								=					previous
											__lowercase								=					node
											__lowercase								=					self.rear





							def 			a__ ( self  :   Tuple     , _UpperCAmelCase  :   Tuple				)						->		DoubleLinkedListNode[T, U] | None:



											"""simple docstring"""


											if node.prev is None or node.next is None:
															return None

											__lowercase								=					node.next
											__lowercase								=					node.prev
											__lowercase								=					None
											__lowercase								=					None
											return node






class 	A__   (						Generic[T, U]				):
							lowerCAmelCase__		:						dict[Callable[[T], U], LRUCache[T, U]]    			=							{}





							def __init__( self  :   List[Any]     , _UpperCAmelCase  :   Union[str, Any]				)						->		List[str]:



											"""simple docstring"""


											__lowercase								=					DoubleLinkedList()
											__lowercase								=					capacity
											__lowercase								=					0
											__lowercase								=					0
											__lowercase								=					0
											__lowercase								=					{}





							def __repr__( self  :   Union[str, Any]				)						->		str:



											"""simple docstring"""


											return (
											    f"""CacheInfo(hits={self.hits}, misses={self.miss}, """
											    f"""capacity={self.capacity}, current size={self.num_keys})"""
											)





							def __contains__( self  :   List[Any]     , _UpperCAmelCase  :   Union[str, Any]				)						->		bool:



											"""simple docstring"""


											return key in self.cache





							def 			a__ ( self  :   str     , _UpperCAmelCase  :   Union[str, Any]				)						->		U | None:



											"""simple docstring"""


											if key in self.cache:
															self.hits += 1
															__lowercase								=					self.cache[key]
															__lowercase								=					self.list.remove(self.cache[key]				)
															assert node == value_node

															# node is guaranteed not None because it is in self.cache
															assert node is not None
															self.list.add(lowercase_				)
															return node.val
											self.miss += 1
											return None





							def 			a__ ( self  :   Any     , _UpperCAmelCase  :   Optional[int]     , _UpperCAmelCase  :   Union[str, Any]				)						->		None:



											"""simple docstring"""


											if key not in self.cache:
															if self.num_keys >= self.capacity:
																			# delete first node (oldest) when over capacity
																			__lowercase								=					self.list.head.next

																			# guaranteed to have a non-None first node when num_keys > 0
																			# explain to type checker via assertions
																			assert first_node is not None
																			assert first_node.key is not None
																			assert (
																			    self.list.remove(lowercase_				) is not None
																			)  # node guaranteed to be in list assert node.key is not None

																			del self.cache[first_node.key]
																			self.num_keys -= 1
															__lowercase								=					DoubleLinkedListNode(lowercase_     , lowercase_				)
															self.list.add(self.cache[key]				)
															self.num_keys += 1

											else:
															# bump node to the end of the list, update value
															__lowercase								=					self.list.remove(self.cache[key]				)
															assert node is not None  # node guaranteed to be in list
															__lowercase								=					value
															self.list.add(lowercase_				)





							@classmethod
							def 			a__ ( cls  :   Any     , _UpperCAmelCase  :   List[Any] = 1_28				)						->		Callable[[Callable[[T], U]], Callable[..., U]]:



											"""simple docstring"""


											def cache_decorator_inner(_UpperCAmelCase  :   List[str]				) -> Callable[..., U]:
															def cache_decorator_wrapper(*_UpperCAmelCase  :   Any				) -> U:
																			if func not in cls.decorator_function_to_instance_map:
																							__lowercase								=					LRUCache(lowercase_				)

																			__lowercase								=					cls.decorator_function_to_instance_map[func].get(args[0]				)
																			if result is None:
																							__lowercase								=					func(*lowercase_				)
																							cls.decorator_function_to_instance_map[func].put(args[0]     , lowercase_				)
																			return result

															def cache_info() -> LRUCache[T, U]:
																			return cls.decorator_function_to_instance_map[func]

															setattr(lowercase_     , 'cache_info'     , lowercase_				)  # noqa: B010

															return cache_decorator_wrapper

											return cache_decorator_inner


if __name__ == "__main__":
							import doctest

							doctest.testmod()








from __future__ import annotations




def 			UpperCAmelCase__				(			_A      : float	,      _A      : float	,      _A      : float	,      ):





  '''simple docstring'''







  if (electron_conc, hole_conc, intrinsic_conc).count(0							) != 1:
    raise ValueError('''You cannot supply more or less than 2 values'''							)
  elif electron_conc < 0:
    raise ValueError('''Electron concentration cannot be negative in a semiconductor'''							)
  elif hole_conc < 0:
    raise ValueError('''Hole concentration cannot be negative in a semiconductor'''							)
  elif intrinsic_conc < 0:
    raise ValueError(
        '''Intrinsic concentration cannot be negative in a semiconductor'''							)
  elif electron_conc == 0:
    return (
        "electron_conc",
        intrinsic_conc**2 / hole_conc,
    )
  elif hole_conc == 0:
    return (
        "hole_conc",
        intrinsic_conc**2 / electron_conc,
    )
  elif intrinsic_conc == 0:
    return (
        "intrinsic_conc",
        (electron_conc * hole_conc) ** 0.5,
    )
  else:
    return (-1, -1)


if __name__ == "__main__":
       import doctest

       doctest.testmod()
