





"""simple docstring"""






from manim import *




class 					__lowercase      (      _UpperCamelCase				):







					'''simple docstring'''




					def 			_lowerCamelCase		(    self  ):
									__a			:    Dict      							=	Rectangle(height=0.5						,      width=0.5  )
									__a			:    List[str]      							=	Rectangle(height=0.4_6						,      width=0.4_6  ).set_stroke(width=0  )

									__a			:    str      							=	[mem.copy() for i in range(6  )]
									__a			:    Dict      							=	[mem.copy() for i in range(6  )]
									__a			:    Dict      							=	VGroup(*_UpperCAmelCase  ).arrange(_UpperCAmelCase						,      buff=0  )
									__a			:    List[Any]      							=	VGroup(*_UpperCAmelCase  ).arrange(_UpperCAmelCase						,      buff=0  )
									__a			:    Optional[Any]      							=	VGroup(_UpperCAmelCase						,      _UpperCAmelCase  ).arrange(_UpperCAmelCase						,      buff=0  )
									__a			:    Any      							=	Text('''CPU'''						,      font_size=24  )
									__a			:    Optional[Any]      							=	Group(_UpperCAmelCase						,      _UpperCAmelCase  ).arrange(_UpperCAmelCase						,      buff=0.5						,      aligned_edge=_UpperCAmelCase  )
									cpu.move_to([-2.5, -0.5, 0]  )
									self.add(_UpperCAmelCase  )

									__a			:    List[Any]      							=	[mem.copy() for i in range(1  )]
									__a			:    Optional[Any]      							=	VGroup(*_UpperCAmelCase  ).arrange(_UpperCAmelCase						,      buff=0  )
									__a			:    Optional[Any]      							=	Text('''GPU'''						,      font_size=24  )
									__a			:    int      							=	Group(_UpperCAmelCase						,      _UpperCAmelCase  ).arrange(_UpperCAmelCase						,      buff=0.5						,      aligned_edge=_UpperCAmelCase  )
									gpu.align_to(_UpperCAmelCase						,      _UpperCAmelCase  )
									gpu.set_x(gpu.get_x() - 1  )

									self.add(_UpperCAmelCase  )

									__a			:    List[str]      							=	[mem.copy() for i in range(6  )]
									__a			:    List[Any]      							=	VGroup(*_UpperCAmelCase  ).arrange(_UpperCAmelCase						,      buff=0  )

									__a			:    Optional[int]      							=	Text('''Model'''						,      font_size=24  )
									__a			:    Optional[int]      							=	Group(_UpperCAmelCase						,      _UpperCAmelCase  ).arrange(_UpperCAmelCase						,      buff=0.5						,      aligned_edge=_UpperCAmelCase  )
									model.move_to([3, -1.0, 0]  )

									self.play(
									    Create(_UpperCAmelCase						,      run_time=1  )						,      Create(_UpperCAmelCase						,      run_time=1  )						,      Create(_UpperCAmelCase						,      run_time=1  )						,      )

									__a			:    Optional[int]      							=	MarkupText(
									    f"""First, an empty model skeleton is loaded\ninto <span fgcolor='{YELLOW}'>memory</span> without using much RAM."""						,      font_size=24						,      )

									__a			:    str      							=	Square(side_length=2.2  )
									key.move_to([-5, 2, 0]  )

									__a			:    str      							=	MarkupText(
									    f"""<b>Key:</b>\n\n<span fgcolor='{YELLOW}'>●</span> Empty Model"""						,      font_size=18						,      )

									key_text.move_to([-5, 2.4, 0]  )

									step_a.move_to([2, 2, 0]  )
									self.play(Write(_UpperCAmelCase						,      run_time=2.5  )						,      Write(_UpperCAmelCase  )						,      Write(_UpperCAmelCase  )  )

									self.add(_UpperCAmelCase  )

									__a			:    int      							=	[]
									__a			:    Optional[int]      							=	[]
									__a			:    str      							=	[]
									for i, rect in enumerate(_UpperCAmelCase  ):
													__a			:    str      							=	Rectangle(height=0.4_6						,      width=0.4_6  ).set_stroke(width=0.0  ).set_fill(_UpperCAmelCase						,      opacity=0.7  )
													cpu_target.move_to(_UpperCAmelCase  )
													cpu_target.generate_target()
													__a			:    Tuple      							=	0.4_6 / 4
													__a			:    Union[str, Any]      							=	0.4_6 / 3

													if i == 0:
																	cpu_target.target.next_to(cpu_left_col_base[0].get_corner(DOWN + LEFT  )						,      buff=0.0_2						,      direction=_UpperCAmelCase  )
																	cpu_target.target.set_x(cpu_target.target.get_x() + 0.1  )
													elif i == 3:
																	cpu_target.target.next_to(cpu_targs[0].target						,      direction=_UpperCAmelCase						,      buff=0.0  )
													else:
																	cpu_target.target.next_to(cpu_targs[i - 1].target						,      direction=_UpperCAmelCase						,      buff=0.0  )
													cpu_targs.append(_UpperCAmelCase  )

													first_animations.append(rect.animate(run_time=0.5  ).set_stroke(_UpperCAmelCase  )  )
													second_animations.append(MoveToTarget(_UpperCAmelCase						,      run_time=1.5  )  )

									self.play(*_UpperCAmelCase  )
									self.play(*_UpperCAmelCase  )

									self.wait()





import numpy as np
import qiskit


def 		lowerCamelCase__       (						_A = 8	,      _A = None				):







	'''simple docstring'''





	snake_case_						       =	np.random.default_rng(seed=_A				)

	# Roughly 25% of the qubits will contribute to the key.
	# So we take more than we need.
	snake_case_						       =	6 * key_len
	# Measurement basis for Alice's qubits.
	snake_case_						       =	rng.integers(2	,      size=_A				)
	# The set of states Alice will prepare.
	snake_case_						       =	rng.integers(2	,      size=_A				)
	# Measurement basis for Bob's qubits.
	snake_case_						       =	rng.integers(2	,      size=_A				)

	# Quantum Circuit to simulate BB84
	snake_case_						       =	qiskit.QuantumCircuit(_A	,      name="BB84"				)

	# Alice prepares her qubits according to rules above.
	for index, _ in enumerate(_A				):
		if alice_state[index] == 1:
			bbaa_circ.x(_A				)
		if alice_basis[index] == 1:
			bbaa_circ.h(_A				)
	bbaa_circ.barrier()

	# Bob measures the received qubits according to rules above.
	for index, _ in enumerate(_A				):
		if bob_basis[index] == 1:
			bbaa_circ.h(_A				)

	bbaa_circ.barrier()
	bbaa_circ.measure_all()

	# Simulate the quantum circuit.
	snake_case_						       =	qiskit.Aer.get_backend("aer_simulator"				)
	# We only need to run one shot because the key is unique.
	# Multiple shots will produce the same key.
	snake_case_						       =	qiskit.execute(_A	,      _A	,      shots=1	,      seed_simulator=_A				)
	# Returns the result of measurement.
	snake_case_						       =	job.result().get_counts(_A				).most_frequent()

	# Extracting the generated key from the simulation results.
	# Only keep measurement results where Alice and Bob chose the same basis.
	snake_case_						       =	"".join(
	    [
	        result_bit
	        for alice_basis_bit, bob_basis_bit, result_bit in zip(
	            _A	,      _A	,      _A				)
	        if alice_basis_bit == bob_basis_bit
	    ]				)

	# Get final key. Pad with 0 if too short, otherwise truncate.
	snake_case_						       =	gen_key[:key_len] if len(_A				) >= key_len else gen_key.ljust(_A	,      "0"				)
	return key


if __name__ == "__main__":
		print(f'''The generated key is : {bbaa(8, seed=0)}''')
		from doctest import testmod

		testmod()
