import logging
import re

import pytorch_quantization
import pytorch_quantization.nn as quant_nn
import torch
from pytorch_quantization import calib
from pytorch_quantization.tensor_quant import QuantDescriptor


__magic_name__    		=logging.getLogger(__name__)

__magic_name__    		=50  # max width of layer names
__magic_name__    		=70  # max width of quantizer names







def 			__UpperCamelCase     (    A				):
     UpperCamelCase__					    =   parser.add_argument_group('''quant_trainer arguments'''				)
     group.add_argument('''--wprec'''			,				type=SCREAMING_SNAKE_CASE__			,				default=8			,				help='''weight precision'''				)
     group.add_argument('''--aprec'''			,				type=SCREAMING_SNAKE_CASE__			,				default=8			,				help='''activation precision'''				)
     group.add_argument('''--quant-per-tensor'''			,				action='''store_true'''			,				help='''per tensor weight scaling'''				)
     group.add_argument('''--quant-disable'''			,				action='''store_true'''			,				help='''disable all quantizers'''				)
     group.add_argument('''--quant-disable-embeddings'''			,				action='''store_true'''			,				help='''disable all embeddings quantizers'''				)
     group.add_argument('''--quant-disable-keyword'''			,				type=SCREAMING_SNAKE_CASE__			,				nargs='''+'''			,				help='''disable quantizers by keyword'''				)
     group.add_argument('''--quant-disable-layer-module'''			,				type=SCREAMING_SNAKE_CASE__			,				help='''disable quantizers by keyword under layer.'''				)
     group.add_argument('''--quant-enable-layer-module'''			,				type=SCREAMING_SNAKE_CASE__			,				help='''enable quantizers by keyword under layer'''				)
     group.add_argument('''--calibrator'''			,				default='''max'''			,				help='''which quantization range calibrator to use'''				)
     group.add_argument('''--percentile'''			,				default=SCREAMING_SNAKE_CASE__			,				type=SCREAMING_SNAKE_CASE__			,				help='''percentile for PercentileCalibrator'''				)
     group.add_argument('''--fuse-qkv'''			,				action='''store_true'''			,				help='''use the same scale factor for qkv'''				)
     group.add_argument('''--clip-gelu'''			,				metavar='''N'''			,				type=SCREAMING_SNAKE_CASE__			,				help='''clip gelu output maximum value to N'''				)
     group.add_argument(
         '''--recalibrate-weights'''			,				action='''store_true'''			,				help=(
             '''recalibrate weight amaxes by taking the max of the weights.'''
             ''' amaxes will be computed with the current quantization granularity (axis).'''
         )			,				)







def 			__UpperCamelCase     (    A				):





     if args.calibrator == "max":
          UpperCamelCase__					    =   """max"""
     elif args.calibrator == "percentile":
          if args.percentile is None:
               raise ValueError('''Specify --percentile when using percentile calibrator'''				)
          UpperCamelCase__					    =   """histogram"""
     elif args.calibrator == "mse":
          UpperCamelCase__					    =   """histogram"""
     else:
          raise ValueError(f"Invalid calibrator {args.calibrator}"				)

     UpperCamelCase__					    =   QuantDescriptor(num_bits=args.aprec			,				calib_method=SCREAMING_SNAKE_CASE__				)
     UpperCamelCase__					    =   QuantDescriptor(num_bits=args.wprec			,				axis=(None if args.quant_per_tensor else (0,))				)
     quant_nn.QuantLinear.set_default_quant_desc_input(SCREAMING_SNAKE_CASE__				)
     quant_nn.QuantLinear.set_default_quant_desc_weight(SCREAMING_SNAKE_CASE__				)







def 			__UpperCamelCase     (    A			,				A			,				A=False			,				A=False				):
     logger.info('''Configuring Model for Quantization'''				)
     logger.info(f"using quantization package {pytorch_quantization.__file__}"				)

     if not calib:
          if args.quant_disable_embeddings:
               set_quantizer_by_name(SCREAMING_SNAKE_CASE__			,				['''embeddings''']			,				which='''weight'''			,				_disabled=SCREAMING_SNAKE_CASE__				)

          if args.quant_disable:
               set_quantizer_by_name(SCREAMING_SNAKE_CASE__			,				['''''']			,				_disabled=SCREAMING_SNAKE_CASE__				)

          if args.quant_disable_keyword:
               set_quantizer_by_name(SCREAMING_SNAKE_CASE__			,				args.quant_disable_keyword			,				_disabled=SCREAMING_SNAKE_CASE__				)

          if args.quant_disable_layer_module:
               set_quantizer_by_name(SCREAMING_SNAKE_CASE__			,				[r'''layer.\d+.''' + args.quant_disable_layer_module]			,				_disabled=SCREAMING_SNAKE_CASE__				)

          if args.quant_enable_layer_module:
               set_quantizer_by_name(SCREAMING_SNAKE_CASE__			,				[r'''layer.\d+.''' + args.quant_enable_layer_module]			,				_disabled=SCREAMING_SNAKE_CASE__				)

          if args.recalibrate_weights:
               recalibrate_weights(SCREAMING_SNAKE_CASE__				)

          if args.fuse_qkv:
               fuse_qkv(SCREAMING_SNAKE_CASE__			,				SCREAMING_SNAKE_CASE__				)

     if args.clip_gelu:
          clip_gelu(SCREAMING_SNAKE_CASE__			,				args.clip_gelu				)

     # if args.local_rank in [-1, 0] and not calib:
     print_quant_summary(SCREAMING_SNAKE_CASE__				)







def 			__UpperCamelCase     (    A				):
     logger.info('''Enabling Calibration'''				)
     for name, module in model.named_modules():
          if name.endswith('''_quantizer'''				):
               if module._calibrator is not None:
                    module.disable_quant()
                    module.enable_calib()
               else:
                    module.disable()
               logger.info(f"{name:80}: {module}"				)







def 			__UpperCamelCase     (    A			,				A				):
     logger.info('''Loading calibrated amax'''				)
     for name, module in model.named_modules():
          if name.endswith('''_quantizer'''				):
               if module._calibrator is not None:
                    if isinstance(module._calibrator			,				calib.MaxCalibrator				):
                         module.load_calib_amax()
                    else:
                         module.load_calib_amax('''percentile'''			,				percentile=args.percentile				)
                    module.enable_quant()
                    module.disable_calib()
               else:
                    module.enable()
     model.cuda()
     print_quant_summary(SCREAMING_SNAKE_CASE__				)







def 			__UpperCamelCase     (    A			,				A				):





     def fusea(A			,				A			,				A				):
          for mod in [qq, qk, qv]:
               if not hasattr(SCREAMING_SNAKE_CASE__			,				'''_amax'''				):
                    print('''          WARNING: NO AMAX BUFFER'''				)
                    return
          UpperCamelCase__					    =   qq._amax.detach().item()
          UpperCamelCase__					    =   qk._amax.detach().item()
          UpperCamelCase__					    =   qv._amax.detach().item()

          UpperCamelCase__					    =   max(SCREAMING_SNAKE_CASE__			,				SCREAMING_SNAKE_CASE__			,				SCREAMING_SNAKE_CASE__				)
          qq._amax.fill_(SCREAMING_SNAKE_CASE__				)
          qk._amax.fill_(SCREAMING_SNAKE_CASE__				)
          qv._amax.fill_(SCREAMING_SNAKE_CASE__				)
          logger.info(f"          q={q:5.2f} k={k:5.2f} v={v:5.2f} -> {amax:5.2f}"				)

     for name, mod in model.named_modules():
          if name.endswith('''.attention.self'''				):
               logger.info(f"FUSE_QKV: {name:{name_width}}"				)
               fusea(mod.matmul_q_input_quantizer			,				mod.matmul_k_input_quantizer			,				mod.matmul_v_input_quantizer				)
               if args.quant_per_tensor:
                    fusea(mod.query._weight_quantizer			,				mod.key._weight_quantizer			,				mod.value._weight_quantizer				)







def 			__UpperCamelCase     (    A			,				A				):





     for name, mod in model.named_modules():
          if name.endswith('''.output.dense'''				) and not name.endswith('''attention.output.dense'''				):
               UpperCamelCase__					    =   mod._input_quantizer._amax.data.detach().item()
               mod._input_quantizer._amax.data.detach().clamp_(max=SCREAMING_SNAKE_CASE__				)
               UpperCamelCase__					    =   mod._input_quantizer._amax.data.detach().item()
               logger.info(f"CLIP_GELU: {name:{name_width}} amax: {amax_init:5.2f} -> {amax:5.2f}"				)







def 			__UpperCamelCase     (    A				):





     for name, mod in model.named_modules():
          if hasattr(SCREAMING_SNAKE_CASE__			,				'''_weight_quantizer'''				) and mod._weight_quantizer.axis is not None:
               UpperCamelCase__					    =   mod.weight.shape[0]
               UpperCamelCase__					    =   mod._weight_quantizer._amax.detach()
               UpperCamelCase__					    =   torch.ones(SCREAMING_SNAKE_CASE__			,				dtype=amax.dtype			,				device=amax.device				) * amax
               print(f"expanding {name} {amax} -> {mod._weight_quantizer._amax}"				)







def 			__UpperCamelCase     (    A				):





     for name, mod in model.named_modules():
          if hasattr(SCREAMING_SNAKE_CASE__			,				'''_weight_quantizer'''				):
               if not hasattr(mod.weight_quantizer			,				'''_amax'''				):
                    print('''RECALIB: {name:{name_width}} WARNING: NO AMAX BUFFER'''				)
                    continue

               # determine which axes to reduce across
               # e.g. a 4D tensor quantized per axis 0 should reduce over (1,2,3)
               UpperCamelCase__					    =   set() if mod._weight_quantizer.axis is None else set(mod._weight_quantizer.axis				)
               UpperCamelCase__					    =   set(range(len(mod.weight.size()				)				)				) - axis_set
               UpperCamelCase__					    =   pytorch_quantization.utils.reduce_amax(mod.weight			,				axis=SCREAMING_SNAKE_CASE__			,				keepdims=SCREAMING_SNAKE_CASE__				).detach()
               logger.info(f"RECALIB: {name:{name_width}} {mod._weight_quantizer._amax.flatten()} -> {amax.flatten()}"				)
               UpperCamelCase__					    =   amax







def 			__UpperCamelCase     (    A			,				A=25			,				A=180			,				A=None				):





     if ignore is None:
          UpperCamelCase__					    =   []
     elif not isinstance(SCREAMING_SNAKE_CASE__			,				SCREAMING_SNAKE_CASE__				):
          UpperCamelCase__					    =   [ignore]

     UpperCamelCase__					    =   0
     for name, mod in model.named_modules():
          if not hasattr(SCREAMING_SNAKE_CASE__			,				'''weight'''				):
               continue
          UpperCamelCase__					    =   max(SCREAMING_SNAKE_CASE__			,				len(SCREAMING_SNAKE_CASE__				)				)

     for name, mod in model.named_modules():
          UpperCamelCase__					    =   getattr(SCREAMING_SNAKE_CASE__			,				'''_input_quantizer'''			,				SCREAMING_SNAKE_CASE__				)
          UpperCamelCase__					    =   getattr(SCREAMING_SNAKE_CASE__			,				'''_weight_quantizer'''			,				SCREAMING_SNAKE_CASE__				)
          if not hasattr(SCREAMING_SNAKE_CASE__			,				'''weight'''				):
               continue
          if type(SCREAMING_SNAKE_CASE__				) in ignore:
               continue
          if [True for s in ignore if type(SCREAMING_SNAKE_CASE__				) is str and s in name]:
               continue
          UpperCamelCase__					    =   f"Act:{input_q.extra_repr()}"
          UpperCamelCase__					    =   f"Wgt:{weight_q.extra_repr()}"
          UpperCamelCase__					    =   f"{name:{name_width}} {act_str} {wgt_str}"
          if len(SCREAMING_SNAKE_CASE__				) <= line_width:
               logger.info(SCREAMING_SNAKE_CASE__				)
          else:
               logger.info(f"{name:{name_width}} {act_str}"				)
               logger.info(f"{'  ':{name_width}} {wgt_str}"				)







def 			__UpperCamelCase     (    A				):
     UpperCamelCase__					    =   0
     for name, mod in model.named_modules():
          if isinstance(SCREAMING_SNAKE_CASE__			,				pytorch_quantization.nn.TensorQuantizer				):
               print(f"{name:80} {mod}"				)
               count += 1
     print(f"{count} TensorQuantizers found in model"				)







def 			__UpperCamelCase     (    A			,				A			,				A			,				A			,				A				):
     UpperCamelCase__					    =   getattr(SCREAMING_SNAKE_CASE__			,				SCREAMING_SNAKE_CASE__			,				SCREAMING_SNAKE_CASE__				)
     if quantizer_mod is not None:
          assert hasattr(SCREAMING_SNAKE_CASE__			,				SCREAMING_SNAKE_CASE__				)
          setattr(SCREAMING_SNAKE_CASE__			,				SCREAMING_SNAKE_CASE__			,				SCREAMING_SNAKE_CASE__				)
     else:
          logger.warning(f"{name} has no {quantizer}"				)







def 			__UpperCamelCase     (    A			,				A			,				A="both"			,				**A				):
     UpperCamelCase__					    =   f"Warning: changing {which} quantizers of {name:{qname_width}}"
     for k, v in kwargs.items():
          s += f" {k}={v}"
          if which in ["input", "both"]:
               set_quantizer(SCREAMING_SNAKE_CASE__			,				SCREAMING_SNAKE_CASE__			,				'''_input_quantizer'''			,				SCREAMING_SNAKE_CASE__			,				SCREAMING_SNAKE_CASE__				)
          if which in ["weight", "both"]:
               set_quantizer(SCREAMING_SNAKE_CASE__			,				SCREAMING_SNAKE_CASE__			,				'''_weight_quantizer'''			,				SCREAMING_SNAKE_CASE__			,				SCREAMING_SNAKE_CASE__				)
     logger.info(SCREAMING_SNAKE_CASE__				)







def 			__UpperCamelCase     (    A			,				A			,				**A				):





     for name, mod in model.named_modules():
          if hasattr(SCREAMING_SNAKE_CASE__			,				'''_input_quantizer'''				) or hasattr(SCREAMING_SNAKE_CASE__			,				'''_weight_quantizer'''				):
               for n in names:
                    if re.search(SCREAMING_SNAKE_CASE__			,				SCREAMING_SNAKE_CASE__				):
                         set_quantizers(SCREAMING_SNAKE_CASE__			,				SCREAMING_SNAKE_CASE__			,				**SCREAMING_SNAKE_CASE__				)
          elif name.endswith('''_quantizer'''				):
               for n in names:
                    if re.search(SCREAMING_SNAKE_CASE__			,				SCREAMING_SNAKE_CASE__				):
                         UpperCamelCase__					    =   f"Warning: changing {name:{name_width}}"
                         for k, v in kwargs.items():
                              s += f" {k}={v}"
                              setattr(SCREAMING_SNAKE_CASE__			,				SCREAMING_SNAKE_CASE__			,				SCREAMING_SNAKE_CASE__				)
                         logger.info(SCREAMING_SNAKE_CASE__				)







'''simple docstring'''


def      snake_case_  (    SCREAMING_SNAKE_CASE__				, SCREAMING_SNAKE_CASE__	):







				"""simple docstring"""





				print("""\nThe shortest path matrix using Floyd Warshall algorithm\n"""	)
				for i in range(SCREAMING_SNAKE_CASE__	):
								for j in range(SCREAMING_SNAKE_CASE__	):
												if dist[i][j] != float("""inf"""	):
																print(int(dist[i][j]	)				, end="""\t"""	)
												else:
																print("""INF"""				, end="""\t"""	)
								print()







def      snake_case_  (    SCREAMING_SNAKE_CASE__				, SCREAMING_SNAKE_CASE__	):







				"""simple docstring"""





				_SCREAMING_SNAKE_CASE					:			Any							= [[float("""inf"""	) for _ in range(SCREAMING_SNAKE_CASE__	)] for _ in range(SCREAMING_SNAKE_CASE__	)]

				for i in range(SCREAMING_SNAKE_CASE__	):
								for j in range(SCREAMING_SNAKE_CASE__	):
												_SCREAMING_SNAKE_CASE					:			List[str]							= graph[i][j]

												# check vertex k against all other vertices (i, j)
				for k in range(SCREAMING_SNAKE_CASE__	):
								# looping through rows of graph array
								for i in range(SCREAMING_SNAKE_CASE__	):
												# looping through columns of graph array
												for j in range(SCREAMING_SNAKE_CASE__	):
																if (
																    dist[i][k] != float("""inf"""	)
																    and dist[k][j] != float("""inf"""	)
																    and dist[i][k] + dist[k][j] < dist[i][j]
																):
																				_SCREAMING_SNAKE_CASE					:			int							= dist[i][k] + dist[k][j]

				_print_dist(SCREAMING_SNAKE_CASE__				, SCREAMING_SNAKE_CASE__	)
				return dist, v


if __name__ == "__main__":
				UpperCAmelCase_						:  str				  =						int(input('Enter number of vertices: '))
				UpperCAmelCase_						:  Union[str, Any]				  =						int(input('Enter number of edges: '))

				UpperCAmelCase_						:  Dict				  =						[[float('inf') for i in range(v)] for j in range(v)]

				for i in range(v):
								UpperCAmelCase_						:  Union[str, Any]				  =						0.0

								# src and dst are indices that must be within the array size graph[e][v]
								# failure to follow this will result in an error
				for i in range(e):
								print('\nEdge ', i + 1)
								UpperCAmelCase_						:  int				  =						int(input('Enter source:'))
								UpperCAmelCase_						:  List[str]				  =						int(input('Enter destination:'))
								UpperCAmelCase_						:  List[str]				  =						float(input('Enter weight:'))
								UpperCAmelCase_						:  int				  =						weight

				floyd_warshall(graph, v)

				# Example Input
				# Enter number of vertices: 3
				# Enter number of edges: 2

				# # generated graph from vertex and edge inputs
				# [[inf, inf, inf], [inf, inf, inf], [inf, inf, inf]]
				# [[0.0, inf, inf], [inf, 0.0, inf], [inf, inf, 0.0]]

				# specify source, destination and weight for edge #1
				# Edge  1
				# Enter source:1
				# Enter destination:2
				# Enter weight:2

				# specify source, destination and weight for edge #2
				# Edge  2
				# Enter source:2
				# Enter destination:1
				# Enter weight:1

				# # Expected Output from the vertice, edge and src, dst, weight inputs!!
				# 0		INF	INF
				# INF	0	2
				# INF	1	0




