

import json
import os
import shutil
import tempfile
import unittest
from multiprocessing import get_context
from pathlib import Path

import datasets
import numpy as np
from datasets import load_dataset
from parameterized import parameterized

from transformers import AutoProcessor
from transformers.models.wavaveca import WavaVecaCTCTokenizer, WavaVecaFeatureExtractor
from transformers.models.wavaveca.tokenization_wavaveca import VOCAB_FILES_NAMES
from transformers.testing_utils import require_pyctcdecode, require_torch, require_torchaudio, slow
from transformers.utils import FEATURE_EXTRACTOR_NAME, is_pyctcdecode_available, is_torch_available

from ..wavaveca.test_feature_extraction_wavaveca import floats_list


if is_pyctcdecode_available():
					from huggingface_hub import snapshot_download
					from pyctcdecode import BeamSearchDecoderCTC

					from transformers.models.wavaveca_with_lm import WavaVecaProcessorWithLM
					from transformers.models.wavaveca_with_lm.processing_wavaveca_with_lm import WavaVecaDecoderWithLMOutput

if is_torch_available():
					from transformers import WavaVecaForCTC





@require_pyctcdecode
class 	snake_case_   (		unittest.TestCase					):







			'''simple docstring'''

			def 				snake_case__(     self :				Optional[Any]							)      ->int:
									snake_case_   =	'''| <pad> <unk> <s> </s> a b c d e f g h i j k'''.split()
									snake_case_   =	dict(zip(_UpperCamelCase							,   range(len(_UpperCamelCase							)							)							)							)

									snake_case_   =	{
									    '''unk_token''': '''<unk>''',
									    '''bos_token''': '''<s>''',
									    '''eos_token''': '''</s>''',
									}
									snake_case_   =	{
									    '''feature_size''': 1,
									    '''padding_value''': 0.0,
									    '''sampling_rate''': 1_6_0_0_0,
									    '''return_attention_mask''': False,
									    '''do_normalize''': True,
									}

									snake_case_   =	tempfile.mkdtemp()
									snake_case_   =	os.path.join(self.tmpdirname							,   VOCAB_FILES_NAMES['''vocab_file''']							)
									snake_case_   =	os.path.join(self.tmpdirname							,   _UpperCamelCase							)
									with open(self.vocab_file							,   '''w'''							,   encoding='''utf-8'''							) as fp:
															fp.write(json.dumps(_UpperCamelCase							) + '''\n'''							)

									with open(self.feature_extraction_file							,   '''w'''							,   encoding='''utf-8'''							) as fp:
															fp.write(json.dumps(_UpperCamelCase							) + '''\n'''							)

									# load decoder from hub
									snake_case_   =	'''hf-internal-testing/ngram-beam-search-decoder'''







			def 				snake_case__(     self :				Union[str, Any]							,   **_UpperCamelCase :				Optional[int]							)      ->List[Any]:
									snake_case_   =	self.add_kwargs_tokens_map.copy()
									kwargs.update(_UpperCamelCase							)
									return WavaVecaCTCTokenizer.from_pretrained(self.tmpdirname							,   **_UpperCamelCase							)







			def 				snake_case__(     self :				Optional[int]							,   **_UpperCamelCase :				List[str]							)      ->Optional[Any]:
									return WavaVecaFeatureExtractor.from_pretrained(self.tmpdirname							,   **_UpperCamelCase							)







			def 				snake_case__(     self :				str							,   **_UpperCamelCase :				List[str]							)      ->Optional[int]:
									return BeamSearchDecoderCTC.load_from_hf_hub(self.decoder_name							,   **_UpperCamelCase							)







			def 				snake_case__(     self :				Any							)      ->Optional[int]:
									shutil.rmtree(self.tmpdirname							)







			def 				snake_case__(     self :				Dict							)      ->Dict:
									snake_case_   =	self.get_tokenizer()
									snake_case_   =	self.get_feature_extractor()
									snake_case_   =	self.get_decoder()

									snake_case_   =	WavaVecaProcessorWithLM(tokenizer=_UpperCamelCase							,   feature_extractor=_UpperCamelCase							,   decoder=_UpperCamelCase							)

									processor.save_pretrained(self.tmpdirname							)
									snake_case_   =	WavaVecaProcessorWithLM.from_pretrained(self.tmpdirname							)

									# tokenizer
									self.assertEqual(processor.tokenizer.get_vocab()							,   tokenizer.get_vocab()							)
									self.assertIsInstance(processor.tokenizer							,   _UpperCamelCase							)

									# feature extractor
									self.assertEqual(processor.feature_extractor.to_json_string()							,   feature_extractor.to_json_string()							)
									self.assertIsInstance(processor.feature_extractor							,   _UpperCamelCase							)

									# decoder
									self.assertEqual(processor.decoder._alphabet.labels							,   decoder._alphabet.labels							)
									self.assertEqual(
									    processor.decoder.model_container[decoder._model_key]._unigram_set							,   decoder.model_container[decoder._model_key]._unigram_set							,   )
									self.assertIsInstance(processor.decoder							,   _UpperCamelCase							)







			def 				snake_case__(     self :				str							)      ->Tuple:
									snake_case_   =	WavaVecaProcessorWithLM(
									    tokenizer=self.get_tokenizer()							,   feature_extractor=self.get_feature_extractor()							,   decoder=self.get_decoder()							)
									processor.save_pretrained(self.tmpdirname							)

									# make sure that error is thrown when decoder alphabet doesn't match
									snake_case_   =	WavaVecaProcessorWithLM.from_pretrained(
									    self.tmpdirname							,   alpha=5.0							,   beta=3.0							,   score_boundary=-7.0							,   unk_score_offset=3							)

									# decoder
									self.assertEqual(processor.language_model.alpha							,   5.0							)
									self.assertEqual(processor.language_model.beta							,   3.0							)
									self.assertEqual(processor.language_model.score_boundary							,   -7.0							)
									self.assertEqual(processor.language_model.unk_score_offset							,   3							)







			def 				snake_case__(     self :				List[str]							)      ->Any:
									snake_case_   =	self.get_tokenizer()
									# add token to trigger raise
									tokenizer.add_tokens(['''xx''']							)
									with self.assertRaisesRegex(_UpperCamelCase							,   '''include'''							):
															WavaVecaProcessorWithLM(
															    tokenizer=_UpperCamelCase							,   feature_extractor=self.get_feature_extractor()							,   decoder=self.get_decoder()							)







			def 				snake_case__(     self :				str							)      ->str:
									snake_case_   =	self.get_feature_extractor()
									snake_case_   =	self.get_tokenizer()
									snake_case_   =	self.get_decoder()

									snake_case_   =	WavaVecaProcessorWithLM(tokenizer=_UpperCamelCase							,   feature_extractor=_UpperCamelCase							,   decoder=_UpperCamelCase							)

									snake_case_   =	floats_list((3, 1_0_0_0)							)

									snake_case_   =	feature_extractor(_UpperCamelCase							,   return_tensors='''np'''							)
									snake_case_   =	processor(_UpperCamelCase							,   return_tensors='''np'''							)

									for key in input_feat_extract.keys():
															self.assertAlmostEqual(input_feat_extract[key].sum()							,   input_processor[key].sum()							,   delta=1e-2							)







			def 				snake_case__(     self :				Union[str, Any]							)      ->Optional[int]:
									snake_case_   =	self.get_feature_extractor()
									snake_case_   =	self.get_tokenizer()
									snake_case_   =	self.get_decoder()

									snake_case_   =	WavaVecaProcessorWithLM(tokenizer=_UpperCamelCase							,   feature_extractor=_UpperCamelCase							,   decoder=_UpperCamelCase							)

									snake_case_   =	'''This is a test string'''

									snake_case_   =	processor(text=_UpperCamelCase							)

									snake_case_   =	tokenizer(_UpperCamelCase							)

									for key in encoded_tok.keys():
															self.assertListEqual(encoded_tok[key]							,   encoded_processor[key]							)







			def 				snake_case__(     self :				str							,   _UpperCamelCase :				Optional[Any]=(2, 1_0, 1_6)							,   _UpperCamelCase :				Optional[int]=7_7							)      ->Any:
									np.random.seed(_UpperCamelCase							)
									return np.random.rand(*_UpperCamelCase							)







			def 				snake_case__(     self :				int							)      ->Any:
									snake_case_   =	self.get_feature_extractor()
									snake_case_   =	self.get_tokenizer()
									snake_case_   =	self.get_decoder()

									snake_case_   =	WavaVecaProcessorWithLM(tokenizer=_UpperCamelCase							,   feature_extractor=_UpperCamelCase							,   decoder=_UpperCamelCase							)

									snake_case_   =	self._get_dummy_logits(shape=(1_0, 1_6)							,   seed=1_3							)

									snake_case_   =	processor.decode(_UpperCamelCase							)

									snake_case_   =	decoder.decode_beams(_UpperCamelCase							)[0]

									self.assertEqual(decoded_decoder[0]							,   decoded_processor.text							)
									self.assertEqual('''</s> <s> </s>'''							,   decoded_processor.text							)
									self.assertEqual(decoded_decoder[-2]							,   decoded_processor.logit_score							)
									self.assertEqual(decoded_decoder[-1]							,   decoded_processor.lm_score							)







			@parameterized.expand([[None], ['''fork'''], ['''spawn''']]							)
			def 				snake_case__(     self :				Union[str, Any]							,   _UpperCamelCase :				Dict							)      ->Any:
									snake_case_   =	self.get_feature_extractor()
									snake_case_   =	self.get_tokenizer()
									snake_case_   =	self.get_decoder()

									snake_case_   =	WavaVecaProcessorWithLM(tokenizer=_UpperCamelCase							,   feature_extractor=_UpperCamelCase							,   decoder=_UpperCamelCase							)

									snake_case_   =	self._get_dummy_logits()

									# note: pool should be instantiated *after* Wav2Vec2ProcessorWithLM.
									#       otherwise, the LM won't be available to the pool's sub-processes.
									# manual logic used to allow parameterized test for both pool=None and pool=Pool(...)
									if pool_context is None:
															snake_case_   =	processor.batch_decode(_UpperCamelCase							)
									else:
															with get_context(_UpperCamelCase							).Pool() as pool:
																					snake_case_   =	processor.batch_decode(_UpperCamelCase							,   _UpperCamelCase							)

									snake_case_   =	list(_UpperCamelCase							)

									with get_context('''fork'''							).Pool() as p:
															snake_case_   =	decoder.decode_beams_batch(_UpperCamelCase							,   _UpperCamelCase							)

									snake_case_,    snake_case_,    snake_case_   =	[], [], []
									for beams in decoded_beams:
															texts_decoder.append(beams[0][0]							)
															logit_scores_decoder.append(beams[0][-2]							)
															lm_scores_decoder.append(beams[0][-1]							)

									self.assertListEqual(_UpperCamelCase							,   decoded_processor.text							)
									self.assertListEqual(['''<s> <s> </s>''', '''<s> <s> <s>''']							,   decoded_processor.text							)
									self.assertListEqual(_UpperCamelCase							,   decoded_processor.logit_score							)
									self.assertListEqual(_UpperCamelCase							,   decoded_processor.lm_score							)







			def 				snake_case__(     self :				Tuple							)      ->Union[str, Any]:
									snake_case_   =	self.get_feature_extractor()
									snake_case_   =	self.get_tokenizer()
									snake_case_   =	self.get_decoder()

									snake_case_   =	WavaVecaProcessorWithLM(tokenizer=_UpperCamelCase							,   feature_extractor=_UpperCamelCase							,   decoder=_UpperCamelCase							)

									snake_case_   =	self._get_dummy_logits()

									snake_case_   =	1_5
									snake_case_   =	-20.0
									snake_case_   =	-4.0

									snake_case_   =	processor.batch_decode(
									    _UpperCamelCase							,   beam_width=_UpperCamelCase							,   beam_prune_logp=_UpperCamelCase							,   token_min_logp=_UpperCamelCase							,   )
									snake_case_   =	decoded_processor_out.text

									snake_case_   =	list(_UpperCamelCase							)

									with get_context('''fork'''							).Pool() as pool:
															snake_case_   =	decoder.decode_beams_batch(
															    _UpperCamelCase							,   _UpperCamelCase							,   beam_width=_UpperCamelCase							,   beam_prune_logp=_UpperCamelCase							,   token_min_logp=_UpperCamelCase							,   )

									snake_case_   =	[d[0][0] for d in decoded_decoder_out]
									snake_case_   =	[d[0][2] for d in decoded_decoder_out]
									snake_case_   =	[d[0][3] for d in decoded_decoder_out]

									self.assertListEqual(_UpperCamelCase							,   _UpperCamelCase							)
									self.assertListEqual(['''</s> <s> <s>''', '''<s> <s> <s>''']							,   _UpperCamelCase							)

									self.assertTrue(np.array_equal(_UpperCamelCase							,   decoded_processor_out.logit_score							)							)
									self.assertTrue(np.allclose([-20.054, -18.447]							,   _UpperCamelCase							,   atol=1e-3							)							)

									self.assertTrue(np.array_equal(_UpperCamelCase							,   decoded_processor_out.lm_score							)							)
									self.assertTrue(np.allclose([-15.554, -13.9474]							,   _UpperCamelCase							,   atol=1e-3							)							)







			def 				snake_case__(     self :				Tuple							)      ->Tuple:
									snake_case_   =	self.get_feature_extractor()
									snake_case_   =	self.get_tokenizer()
									snake_case_   =	self.get_decoder()

									snake_case_   =	WavaVecaProcessorWithLM(tokenizer=_UpperCamelCase							,   feature_extractor=_UpperCamelCase							,   decoder=_UpperCamelCase							)

									snake_case_   =	self._get_dummy_logits()

									snake_case_   =	2.0
									snake_case_   =	5.0
									snake_case_   =	-20.0
									snake_case_   =	True

									snake_case_   =	processor.batch_decode(
									    _UpperCamelCase							,   alpha=_UpperCamelCase							,   beta=_UpperCamelCase							,   unk_score_offset=_UpperCamelCase							,   lm_score_boundary=_UpperCamelCase							,   )
									snake_case_   =	decoded_processor_out.text

									snake_case_   =	list(_UpperCamelCase							)
									decoder.reset_params(
									    alpha=_UpperCamelCase							,   beta=_UpperCamelCase							,   unk_score_offset=_UpperCamelCase							,   lm_score_boundary=_UpperCamelCase							,   )

									with get_context('''fork'''							).Pool() as pool:
															snake_case_   =	decoder.decode_beams_batch(
															    _UpperCamelCase							,   _UpperCamelCase							,   )

									snake_case_   =	[d[0][0] for d in decoded_decoder_out]

									self.assertListEqual(_UpperCamelCase							,   _UpperCamelCase							)
									self.assertListEqual(['''<s> </s> <s> </s> </s>''', '''</s> </s> <s> </s> </s>''']							,   _UpperCamelCase							)
									snake_case_   =	processor.decoder.model_container[processor.decoder._model_key]
									self.assertEqual(lm_model.alpha							,   2.0							)
									self.assertEqual(lm_model.beta							,   5.0							)
									self.assertEqual(lm_model.unk_score_offset							,   -20.0							)
									self.assertEqual(lm_model.score_boundary							,   _UpperCamelCase							)







			def 				snake_case__(     self :				Dict							)      ->str:
									snake_case_   =	WavaVecaProcessorWithLM.from_pretrained('''hf-internal-testing/processor_with_lm'''							)

									snake_case_   =	processor.decoder.model_container[processor.decoder._model_key]
									snake_case_   =	Path(language_model._kenlm_model.path.decode('''utf-8'''							)							).parent.parent.absolute()

									snake_case_   =	os.listdir(_UpperCamelCase							)
									snake_case_   =	['''alphabet.json''', '''language_model''']

									downloaded_decoder_files.sort()
									expected_decoder_files.sort()

									# test that only decoder relevant files from
									# https://huggingface.co/hf-internal-testing/processor_with_lm/tree/main
									# are downloaded and none of the rest (e.g. README.md, ...)
									self.assertListEqual(_UpperCamelCase							,   _UpperCamelCase							)







			def 				snake_case__(     self :				List[Any]							)      ->Optional[Any]:
									snake_case_   =	snapshot_download('''hf-internal-testing/processor_with_lm'''							)

									snake_case_   =	WavaVecaProcessorWithLM.from_pretrained(_UpperCamelCase							)

									snake_case_   =	processor.decoder.model_container[processor.decoder._model_key]
									snake_case_   =	Path(language_model._kenlm_model.path.decode('''utf-8'''							)							).parent.parent.absolute()

									snake_case_   =	os.listdir(_UpperCamelCase							)
									snake_case_   =	os.listdir(_UpperCamelCase							)

									local_decoder_files.sort()
									expected_decoder_files.sort()

									# test that both decoder form hub and local files in cache are the same
									self.assertListEqual(_UpperCamelCase							,   _UpperCamelCase							)







			def 				snake_case__(     self :				Tuple							)      ->Optional[Any]:
									snake_case_   =	WavaVecaProcessorWithLM.from_pretrained('''hf-internal-testing/processor_with_lm'''							)
									snake_case_   =	AutoProcessor.from_pretrained('''hf-internal-testing/processor_with_lm'''							)

									snake_case_   =	floats_list((3, 1_0_0_0)							)

									snake_case_   =	processor_wavaveca(_UpperCamelCase							,   return_tensors='''np'''							)
									snake_case_   =	processor_auto(_UpperCamelCase							,   return_tensors='''np'''							)

									for key in input_wavaveca.keys():
															self.assertAlmostEqual(input_wavaveca[key].sum()							,   input_auto[key].sum()							,   delta=1e-2							)

									snake_case_   =	self._get_dummy_logits()

									snake_case_   =	processor_wavaveca.batch_decode(_UpperCamelCase							)
									snake_case_   =	processor_auto.batch_decode(_UpperCamelCase							)

									self.assertListEqual(decoded_wavaveca.text							,   decoded_auto.text							)







			def 				snake_case__(     self :				List[str]							)      ->List[str]:
									snake_case_   =	self.get_feature_extractor()
									snake_case_   =	self.get_tokenizer()
									snake_case_   =	self.get_decoder()

									snake_case_   =	WavaVecaProcessorWithLM(tokenizer=_UpperCamelCase							,   feature_extractor=_UpperCamelCase							,   decoder=_UpperCamelCase							)

									self.assertListEqual(
									    processor.model_input_names							,   feature_extractor.model_input_names							,   msg='''`processor` and `feature_extractor` model input names do not match'''							,   )







			@staticmethod
			def 				snake_case__(     _UpperCamelCase :				Tuple							,   _UpperCamelCase :				Optional[Any]							)      ->str:
									snake_case_   =	[d[key] for d in offsets]
									return retrieved_list







			def 				snake_case__(     self :				str							)      ->Union[str, Any]:
									snake_case_   =	WavaVecaProcessorWithLM.from_pretrained('''hf-internal-testing/processor_with_lm'''							)
									snake_case_   =	self._get_dummy_logits()[0]

									snake_case_   =	processor.decode(_UpperCamelCase							,   output_word_offsets=_UpperCamelCase							)
									# check Wav2Vec2CTCTokenizerOutput keys for word
									self.assertEqual(len(outputs.keys()							)							,   4							)
									self.assertTrue('''text''' in outputs							)
									self.assertTrue('''word_offsets''' in outputs							)
									self.assertTrue(isinstance(_UpperCamelCase							,   _UpperCamelCase							)							)

									self.assertEqual(''' '''.join(self.get_from_offsets(outputs['''word_offsets''']							,   '''word'''							)							)							,   outputs.text							)
									self.assertListEqual(self.get_from_offsets(outputs['''word_offsets''']							,   '''word'''							)							,   ['''<s>''', '''<s>''', '''</s>''']							)
									self.assertListEqual(self.get_from_offsets(outputs['''word_offsets''']							,   '''start_offset'''							)							,   [0, 2, 4]							)
									self.assertListEqual(self.get_from_offsets(outputs['''word_offsets''']							,   '''end_offset'''							)							,   [1, 3, 5]							)







			def 				snake_case__(     self :				Dict							)      ->int:
									snake_case_   =	WavaVecaProcessorWithLM.from_pretrained('''hf-internal-testing/processor_with_lm'''							)
									snake_case_   =	self._get_dummy_logits()

									snake_case_   =	processor.batch_decode(_UpperCamelCase							,   output_word_offsets=_UpperCamelCase							)

									# check Wav2Vec2CTCTokenizerOutput keys for word
									self.assertEqual(len(outputs.keys()							)							,   4							)
									self.assertTrue('''text''' in outputs							)
									self.assertTrue('''word_offsets''' in outputs							)
									self.assertTrue(isinstance(_UpperCamelCase							,   _UpperCamelCase							)							)

									self.assertListEqual(
									    [''' '''.join(self.get_from_offsets(_UpperCamelCase							,   '''word'''							)							) for o in outputs['''word_offsets''']]							,   outputs.text							)
									self.assertListEqual(self.get_from_offsets(outputs['''word_offsets'''][0]							,   '''word'''							)							,   ['''<s>''', '''<s>''', '''</s>''']							)
									self.assertListEqual(self.get_from_offsets(outputs['''word_offsets'''][0]							,   '''start_offset'''							)							,   [0, 2, 4]							)
									self.assertListEqual(self.get_from_offsets(outputs['''word_offsets'''][0]							,   '''end_offset'''							)							,   [1, 3, 5]							)







			@slow
			@require_torch
			@require_torchaudio
			def 				snake_case__(     self :				int							)      ->Any:
									import torch

									snake_case_   =	load_dataset('''common_voice'''							,   '''en'''							,   split='''train'''							,   streaming=_UpperCamelCase							)
									snake_case_   =	ds.cast_column('''audio'''							,   datasets.Audio(sampling_rate=1_6_0_0_0							)							)
									snake_case_   =	iter(_UpperCamelCase							)
									snake_case_   =	next(_UpperCamelCase							)

									snake_case_   =	AutoProcessor.from_pretrained('''patrickvonplaten/wav2vec2-base-100h-with-lm'''							)
									snake_case_   =	WavaVecaForCTC.from_pretrained('''patrickvonplaten/wav2vec2-base-100h-with-lm'''							)

									# compare to filename `common_voice_en_100038.mp3` of dataset viewer on https://huggingface.co/datasets/common_voice/viewer/en/train
									snake_case_   =	processor(sample['''audio''']['''array''']							,   return_tensors='''pt'''							).input_values

									with torch.no_grad():
															snake_case_   =	model(_UpperCamelCase							).logits.cpu().numpy()

									snake_case_   =	processor.decode(logits[0]							,   output_word_offsets=_UpperCamelCase							)

									snake_case_   =	model.config.inputs_to_logits_ratio / processor.feature_extractor.sampling_rate
									snake_case_   =	[
									    {
									        '''start_time''': d['''start_offset'''] * time_offset,
									        '''end_time''': d['''end_offset'''] * time_offset,
									        '''word''': d['''word'''],
									    }
									    for d in output['''word_offsets''']
									]

									snake_case_   =	'''WHY DOES MILISANDRA LOOK LIKE SHE WANTS TO CONSUME JOHN SNOW ON THE RIVER AT THE WALL'''

									# output words
									self.assertEqual(''' '''.join(self.get_from_offsets(_UpperCamelCase							,   '''word'''							)							)							,   _UpperCamelCase							)
									self.assertEqual(''' '''.join(self.get_from_offsets(_UpperCamelCase							,   '''word'''							)							)							,   output.text							)

									# output times
									snake_case_   =	torch.tensor(self.get_from_offsets(_UpperCamelCase							,   '''start_time'''							)							)
									snake_case_   =	torch.tensor(self.get_from_offsets(_UpperCamelCase							,   '''end_time'''							)							)

									# fmt: off
									snake_case_   =	torch.tensor([1.4199, 1.6599, 2.2599, 3.0, 3.24, 3.5999, 3.7999, 4.0999, 4.26, 4.94, 5.28, 5.6599, 5.78, 5.94, 6.32, 6.5399, 6.6599]							)
									snake_case_   =	torch.tensor([1.5399, 1.8999, 2.9, 3.16, 3.5399, 3.72, 4.0199, 4.1799, 4.76, 5.1599, 5.5599, 5.6999, 5.86, 6.1999, 6.38, 6.6199, 6.94]							)
									# fmt: on

									self.assertTrue(torch.allclose(_UpperCamelCase							,   _UpperCamelCase							,   atol=0.01							)							)
									self.assertTrue(torch.allclose(_UpperCamelCase							,   _UpperCamelCase							,   atol=0.01							)							)


from decimal import Decimal, getcontext
from math import ceil, factorial


def   __SCREAMING_SNAKE_CASE					(SCREAMING_SNAKE_CASE__       ):

						if not isinstance(SCREAMING_SNAKE_CASE__  ,		SCREAMING_SNAKE_CASE__       ):
												raise TypeError('''Undefined for non-integers'''       )
						elif precision < 1:
												raise ValueError('''Undefined for non-natural numbers'''       )

						snake_case_   =	precision
						snake_case_   =	ceil(precision / 14       )
						snake_case_   =	426880 * Decimal(10005       ).sqrt()
						snake_case_   =	1
						snake_case_   =	13591409
						snake_case_   =	Decimal(SCREAMING_SNAKE_CASE__       )
						for k in range(1  ,		SCREAMING_SNAKE_CASE__       ):
												snake_case_   =	factorial(6 * k       ) // (factorial(3 * k       ) * factorial(SCREAMING_SNAKE_CASE__       ) ** 3)
												linear_term += 545140134
												exponential_term *= -262537412640768000
												partial_sum += Decimal(multinomial_term * linear_term       ) / exponential_term
						return str(constant_term / partial_sum       )[:-1]


if __name__ == "__main__":
					lowerCAmelCase_       	=	50
					print(f"""The first {n} digits of pi is: {pi(n)}""")