



'''simple docstring'''





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


lowercase_	 =						logging.getLogger(__name__)

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




def lowerCAmelCase						(__A):



     """simple docstring"""



     _a											=						parser.add_argument_group('''quant_trainer arguments''')
     group.add_argument('''--wprec'''						,			type=__A						,			default=8						,			help='''weight precision''')
     group.add_argument('''--aprec'''						,			type=__A						,			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=__A						,			nargs='''+'''						,			help='''disable quantizers by keyword''')
     group.add_argument('''--quant-disable-layer-module'''						,			type=__A						,			help='''disable quantizers by keyword under layer.''')
     group.add_argument('''--quant-enable-layer-module'''						,			type=__A						,			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=__A						,			type=__A						,			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=__A						,			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 lowerCAmelCase						(__A):



     """simple docstring"""



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

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




def lowerCAmelCase						(__A						,			__A						,			__A=False						,			__A=False):



     """simple docstring"""



     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(__A						,			['''embeddings''']						,			which='''weight'''						,			_disabled=__A)

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

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

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

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

          if args.recalibrate_weights:
               recalibrate_weights(__A)

          if args.fuse_qkv:
               fuse_qkv(__A						,			__A)

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

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




def lowerCAmelCase						(__A):



     """simple docstring"""



     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 lowerCAmelCase						(__A						,			__A):



     """simple docstring"""



     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(__A)




def lowerCAmelCase						(__A						,			__A):



     """simple docstring"""



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

          _a											=						max(__A						,			__A						,			__A)
          qq._amax.fill_(__A)
          qk._amax.fill_(__A)
          qv._amax.fill_(__A)
          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 lowerCAmelCase						(__A						,			__A):



     """simple docstring"""



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




def lowerCAmelCase						(__A):



     """simple docstring"""



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




def lowerCAmelCase						(__A):



     """simple docstring"""



     for name, mod in model.named_modules():
          if hasattr(__A						,			'''_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)
               _a											=						set() if mod._weight_quantizer.axis is None else set(mod._weight_quantizer.axis)
               _a											=						set(range(len(mod.weight.size()))) - axis_set
               _a											=						pytorch_quantization.utils.reduce_amax(mod.weight						,			axis=__A						,			keepdims=__A).detach()
               logger.info(F'''RECALIB: {name:{name_width}} {mod._weight_quantizer._amax.flatten()} -> {amax.flatten()}''')
               _a											=						amax




def lowerCAmelCase						(__A						,			__A=25						,			__A=180						,			__A=None):



     """simple docstring"""



     if ignore is None:
          _a											=						[]
     elif not isinstance(__A						,			__A):
          _a											=						[ignore]

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

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




def lowerCAmelCase						(__A):



     """simple docstring"""



     _a											=						0
     for name, mod in model.named_modules():
          if isinstance(__A						,			pytorch_quantization.nn.TensorQuantizer):
               print(F'''{name:80} {mod}''')
               count += 1
     print(F'''{count} TensorQuantizers found in model''')




def lowerCAmelCase						(__A						,			__A						,			__A						,			__A						,			__A):



     """simple docstring"""



     _a											=						getattr(__A						,			__A						,			__A)
     if quantizer_mod is not None:
          assert hasattr(__A						,			__A)
          setattr(__A						,			__A						,			__A)
     else:
          logger.warning(F'''{name} has no {quantizer}''')




def lowerCAmelCase						(__A						,			__A						,			__A="both"						,			**__A):



     """simple docstring"""



     _a											=						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(__A						,			__A						,			'''_input_quantizer'''						,			__A						,			__A)
          if which in ["weight", "both"]:
               set_quantizer(__A						,			__A						,			'''_weight_quantizer'''						,			__A						,			__A)
     logger.info(__A)




def lowerCAmelCase						(__A						,			__A						,			**__A):



     """simple docstring"""



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








'''simple docstring'''





import numpy as np
import qiskit




def lowerCAmelCase						(__A = 8						,			__A = None):



     """simple docstring"""



     _a											=						np.random.default_rng(seed=__A)

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

     # Quantum Circuit to simulate BB84
     _a											=						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.
     _a											=						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.
     _a											=						qiskit.execute(__A						,			__A						,			shots=1						,			seed_simulator=__A)
     # Returns the result of measurement.
     _a											=						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.
     _a											=						''''''.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.
     _a											=						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()



