





'''simple docstring'''


import argparse
import json
import re
import string
import sys
from collections import Counter




def    __a (     UpperCAmelCase    )      ->str:



	"""simple docstring"""







	def remove_articles(UpperCAmelCase    ):
		return re.sub(R"""\b(a|an|the)\b"""       ,			""" """       ,			UpperCAmelCase    )

	def white_space_fix(UpperCAmelCase    ):
		return " ".join(text.split()    )

	def remove_punc(UpperCAmelCase    ):
		A							  =      set(string.punctuation    )
		return "".join(ch for ch in text if ch not in exclude    )

	def lower(UpperCAmelCase    ):
		return text.lower()

	return white_space_fix(remove_articles(remove_punc(lower(UpperCAmelCase    )    )    )    )




def    __a (     UpperCAmelCase       ,			UpperCAmelCase    )      ->Any:



	"""simple docstring"""







	A							  =      normalize_answer(UpperCAmelCase    ).split()
	A							  =      normalize_answer(UpperCAmelCase    ).split()
	A							  =      Counter(UpperCAmelCase    ) & Counter(UpperCAmelCase    )
	A							  =      sum(common.values()    )
	if num_same == 0:
		return 0
	A							  =      1.0 * num_same / len(UpperCAmelCase    )
	A							  =      1.0 * num_same / len(UpperCAmelCase    )
	A							  =      (2 * precision * recall) / (precision + recall)
	return fa




def    __a (     UpperCAmelCase       ,			UpperCAmelCase    )      ->Any:



	"""simple docstring"""







	return normalize_answer(UpperCAmelCase    ) == normalize_answer(UpperCAmelCase    )




def    __a (     UpperCAmelCase       ,			UpperCAmelCase       ,			UpperCAmelCase    )      ->Dict:



	"""simple docstring"""







	A							  =      []
	for ground_truth in ground_truths:
		A							  =      metric_fn(UpperCAmelCase       ,			UpperCAmelCase    )
		scores_for_ground_truths.append(UpperCAmelCase    )
	return max(UpperCAmelCase    )




def    __a (     UpperCAmelCase       ,			UpperCAmelCase    )      ->Union[str, Any]:



	"""simple docstring"""







	A							  =      A							  =      A							  =      0
	for article in dataset:
		for paragraph in article["paragraphs"]:
			for qa in paragraph["qas"]:
				total += 1
				if qa["id"] not in predictions:
					A							  =      """Unanswered question """ + qa["""id"""] + """ will receive score 0."""
					print(UpperCAmelCase       ,			file=sys.stderr    )
					continue
				A							  =      [x["""text"""] for x in qa["""answers"""]]
				A							  =      predictions[qa["""id"""]]
				exact_match += metric_max_over_ground_truths(UpperCAmelCase       ,			UpperCAmelCase       ,			UpperCAmelCase    )
				fa += metric_max_over_ground_truths(UpperCAmelCase       ,			UpperCAmelCase       ,			UpperCAmelCase    )

	A							  =      100.0 * exact_match / total
	A							  =      100.0 * fa / total

	return {"exact_match": exact_match, "f1": fa}


if __name__ == "__main__":
				_lowerCamelCase				:	Optional[Any]				    =       '1.1'
				_lowerCamelCase				:	Any				    =       argparse.ArgumentParser(description='Evaluation for SQuAD ' + expected_version)
				parser.add_argument('dataset_file', help='Dataset file')
				parser.add_argument('prediction_file', help='Prediction File')
				_lowerCamelCase				:	int				    =       parser.parse_args()
				with open(args.dataset_file) as dataset_file:
								_lowerCamelCase				:	List[str]				    =       json.load(dataset_file)
								if dataset_json["version"] != expected_version:
												print(
												    'Evaluation expects v-' + expected_version + ', but got dataset with v-' + dataset_json['version'],
												    file=sys.stderr,
												)
								_lowerCamelCase				:	List[str]				    =       dataset_json['data']
				with open(args.prediction_file) as prediction_file:
								_lowerCamelCase				:	str				    =       json.load(prediction_file)
				print(json.dumps(evaluate(dataset, predictions)))








'''simple docstring'''


class 							__UpperCAmelCase  :







		'''simple docstring'''







		def __init__(self						:      List[str]      ):
			# numbermap keys are the number and its values are lists of indexes sorted
			# in ascending order
			A							  =      {}
			# indexmap keys are an index and it's values are the number at that index
			A							  =      {}







		def        A     (self						:      Union[str, Any]      ,      _lowerCAmelCase						:      list | str | range      ,      _lowerCAmelCase						:      int      ):
			if isinstance(_lowerCAmelCase      ,      (range, str)      ):
				A							  =      list(_lowerCAmelCase      )
			elif not isinstance(_lowerCAmelCase      ,      _lowerCAmelCase      ):
				raise TypeError(
				    """binary_search_delete() only accepts either a list, range or str"""      )

			A							  =      0
			A							  =      len(_lowerCAmelCase      ) - 1

			while low <= high:
				A							  =      (low + high) // 2
				if array[mid] == item:
					array.pop(_lowerCAmelCase      )
					return array
				elif array[mid] < item:
					A							  =      mid + 1
				else:
					A							  =      mid - 1
			raise ValueError(
			    """Either the item is not in the array or the array was unsorted"""      )







		def        A     (self						:      Dict      ,      _lowerCAmelCase						:      list | str | range      ,      _lowerCAmelCase						:      int      ):
			if isinstance(_lowerCAmelCase      ,      (range, str)      ):
				A							  =      list(_lowerCAmelCase      )
			elif not isinstance(_lowerCAmelCase      ,      _lowerCAmelCase      ):
				raise TypeError(
				    """binary_search_insert() only accepts either a list, range or str"""      )

			A							  =      0
			A							  =      len(_lowerCAmelCase      ) - 1

			while low <= high:
				A							  =      (low + high) // 2
				if array[mid] == index:
					# If the item already exists in the array,
					# insert it after the existing item
					array.insert(mid + 1      ,      _lowerCAmelCase      )
					return array
				elif array[mid] < index:
					A							  =      mid + 1
				else:
					A							  =      mid - 1

        # If the item doesn't exist in the array, insert it at the appropriate position
			array.insert(_lowerCAmelCase      ,      _lowerCAmelCase      )
			return array







		def        A     (self						:      List[str]      ,      _lowerCAmelCase						:      int      ,      _lowerCAmelCase						:      int      ):
			# Remove previous index
			if index in self.indexmap:
				A							  =      self.indexmap[index]
				if len(self.numbermap[n]      ) == 1:
					del self.numbermap[n]
				else:
					A							  =      self.binary_search_delete(self.numbermap[n]      ,      _lowerCAmelCase      )

        # Set new index
			A							  =      number

			# Number not seen before or empty so insert number value
			if number not in self.numbermap:
				A							  =      [index]

			# Here we need to perform a binary search insertion in order to insert
			# The item in the correct place
			else:
				A							  =      self.binary_search_insert(
				    self.numbermap[number]      ,      _lowerCAmelCase      )







		def        A     (self						:      int      ,      _lowerCAmelCase						:      int      ):
			return self.numbermap.get(_lowerCAmelCase      ,      [-1]      )[0]


if __name__ == "__main__":
				import doctest

				doctest.testmod()

