



import importlib.metadata
import warnings
from copy import deepcopy

from packaging import version

from ..utils import logging
from .import_utils import is_accelerate_available, is_bitsandbytes_available


if is_bitsandbytes_available():
	import bitsandbytes as bnb
	import torch
	import torch.nn as nn

	from ..pytorch_utils import ConvaD

if is_accelerate_available():
	from accelerate import init_empty_weights
	from accelerate.utils import find_tied_parameters

snake_case__					:     Optional[Any]    		=   logging.get_logger(__name__)



def    snake_case_				(    _SCREAMING_SNAKE_CASE  ,	_SCREAMING_SNAKE_CASE  ,	_SCREAMING_SNAKE_CASE  ,	_SCREAMING_SNAKE_CASE=None  ,	_SCREAMING_SNAKE_CASE=None   ):
	# Recurse if needed
	if "." in tensor_name:
		__lowercase		       =			tensor_name.split("."   )
		for split in splits[:-1]:
			__lowercase		       =			getattr(_SCREAMING_SNAKE_CASE  ,	_SCREAMING_SNAKE_CASE   )
			if new_module is None:
				raise ValueError(F"""{module} has no attribute {split}."""   )
			__lowercase		       =			new_module
		__lowercase		       =			splits[-1]

	if tensor_name not in module._parameters and tensor_name not in module._buffers:
		raise ValueError(F"""{module} does not have a parameter or a buffer named {tensor_name}."""   )
	__lowercase		       =			tensor_name in module._buffers
	__lowercase		       =			getattr(_SCREAMING_SNAKE_CASE  ,	_SCREAMING_SNAKE_CASE   )

	if old_value.device == torch.device("meta"   ) and device not in ["meta", torch.device("meta"   )] and value is None:
		raise ValueError(F"""{tensor_name} is on the meta device, we need a `value` to put in on {device}."""   )

	__lowercase		       =			False
	__lowercase		       =			False
	if is_buffer or not is_bitsandbytes_available():
		__lowercase		       =			False
		__lowercase		       =			False
	else:
		__lowercase		       =			hasattr(bnb.nn  ,	"Params4bit"   ) and isinstance(module._parameters[tensor_name]  ,	bnb.nn.Paramsabit   )
		__lowercase		       =			isinstance(module._parameters[tensor_name]  ,	bnb.nn.IntaParams   )

	if is_abit or is_abit:
		__lowercase		       =			module._parameters[tensor_name]
		if param.device.type != "cuda":
			if value is None:
				__lowercase		       =			old_value.to(_SCREAMING_SNAKE_CASE   )
			elif isinstance(_SCREAMING_SNAKE_CASE  ,	torch.Tensor   ):
				__lowercase		       =			value.to("cpu"   )
				if value.dtype == torch.inta:
					__lowercase		       =			version.parse(importlib.metadata.version("bitsandbytes"   )   ) > version.parse(
					    "0.37.2"   )
					if not is_abit_serializable:
						raise ValueError(
						    "Detected int8 weights but the version of bitsandbytes is not compatible with int8 serialization. "
						    "Make sure to download the latest `bitsandbytes` version. `pip install --upgrade bitsandbytes`."   )
			else:
				__lowercase		       =			torch.tensor(_SCREAMING_SNAKE_CASE  ,	device="cpu"   )

			# Support models using `Conv1D` in place of `nn.Linear` (e.g. gpt2) by transposing the weight matrix prior to quantization.
			# Since weights are saved in the correct "orientation", we skip transposing when loading.
			if issubclass(module.source_cls  ,	_SCREAMING_SNAKE_CASE   ) and fpaa_statistics is None:
				__lowercase		       =			new_value.T

			__lowercase		       =			old_value.__dict__
			if is_abit:
				__lowercase		       =			bnb.nn.IntaParams(_SCREAMING_SNAKE_CASE  ,	requires_grad=_SCREAMING_SNAKE_CASE  ,	**_SCREAMING_SNAKE_CASE   ).to(_SCREAMING_SNAKE_CASE   )
			elif is_abit:
				__lowercase		       =			bnb.nn.Paramsabit(_SCREAMING_SNAKE_CASE  ,	requires_grad=_SCREAMING_SNAKE_CASE  ,	**_SCREAMING_SNAKE_CASE   ).to(_SCREAMING_SNAKE_CASE   )

			__lowercase		       =			new_value
			if fpaa_statistics is not None:
				setattr(module.weight  ,	"SCB"  ,	fpaa_statistics.to(_SCREAMING_SNAKE_CASE   )   )

	else:
		if value is None:
			__lowercase		       =			old_value.to(_SCREAMING_SNAKE_CASE   )
		elif isinstance(_SCREAMING_SNAKE_CASE  ,	torch.Tensor   ):
			__lowercase		       =			value.to(_SCREAMING_SNAKE_CASE   )
		else:
			__lowercase		       =			torch.tensor(_SCREAMING_SNAKE_CASE  ,	device=_SCREAMING_SNAKE_CASE   )

		if is_buffer:
			__lowercase		       =			new_value
		else:
			__lowercase		       =			nn.Parameter(_SCREAMING_SNAKE_CASE  ,	requires_grad=old_value.requires_grad   )
			__lowercase		       =			new_value



def    snake_case_				(    _SCREAMING_SNAKE_CASE  ,	_SCREAMING_SNAKE_CASE=None  ,	_SCREAMING_SNAKE_CASE=None  ,	_SCREAMING_SNAKE_CASE=None  ,	_SCREAMING_SNAKE_CASE=False   ):
	for name, module in model.named_children():
		if current_key_name is None:
			__lowercase		       =			[]
		current_key_name.append(_SCREAMING_SNAKE_CASE   )

		if (isinstance(_SCREAMING_SNAKE_CASE  ,	nn.Linear   ) or isinstance(_SCREAMING_SNAKE_CASE  ,	_SCREAMING_SNAKE_CASE   )) and name not in modules_to_not_convert:
			# Check if the current key is not in the `modules_to_not_convert`
			if not any(key in ".".join(_SCREAMING_SNAKE_CASE   ) for key in modules_to_not_convert   ):
				with init_empty_weights():
					if isinstance(_SCREAMING_SNAKE_CASE  ,	_SCREAMING_SNAKE_CASE   ):
						__lowercase       ,    __lowercase		       =			module.weight.shape
					else:
						__lowercase		       =			module.in_features
						__lowercase		       =			module.out_features

					if quantization_config.quantization_method() == "llm_int8":
						__lowercase		       =			bnb.nn.LinearabitLt(
						    _SCREAMING_SNAKE_CASE  ,	_SCREAMING_SNAKE_CASE  ,	module.bias is not None  ,	has_fpaa_weights=quantization_config.llm_inta_has_fpaa_weight  ,	threshold=quantization_config.llm_inta_threshold  ,	)
						__lowercase		       =			True
					else:
						if (
						    quantization_config.llm_inta_skip_modules is not None
						    and name in quantization_config.llm_inta_skip_modules
						):
							pass
						else:
							__lowercase		       =			bnb.nn.Linearabit(
							    _SCREAMING_SNAKE_CASE  ,	_SCREAMING_SNAKE_CASE  ,	module.bias is not None  ,	quantization_config.bnb_abit_compute_dtype  ,	compress_statistics=quantization_config.bnb_abit_use_double_quant  ,	quant_type=quantization_config.bnb_abit_quant_type  ,	)
							__lowercase		       =			True
                    # Store the module class in case we need to transpose the weight later
					__lowercase		       =			type(_SCREAMING_SNAKE_CASE   )
					# Force requires grad to False to avoid unexpected errors
					model._modules[name].requires_grad_(_SCREAMING_SNAKE_CASE   )
		if len(list(module.children()   )   ) > 0:
			__lowercase       ,    __lowercase		       =			_replace_with_bnb_linear(
			    _SCREAMING_SNAKE_CASE  ,	_SCREAMING_SNAKE_CASE  ,	_SCREAMING_SNAKE_CASE  ,	_SCREAMING_SNAKE_CASE  ,	has_been_replaced=_SCREAMING_SNAKE_CASE  ,	)
		# Remove the last key for recursion
		current_key_name.pop(-1   )
	return model, has_been_replaced



def    snake_case_				(    _SCREAMING_SNAKE_CASE  ,	_SCREAMING_SNAKE_CASE=None  ,	_SCREAMING_SNAKE_CASE=None  ,	_SCREAMING_SNAKE_CASE=None   ):
	__lowercase		       =			["lm_head"] if modules_to_not_convert is None else modules_to_not_convert
	__lowercase       ,    __lowercase		       =			_replace_with_bnb_linear(
	    _SCREAMING_SNAKE_CASE  ,	_SCREAMING_SNAKE_CASE  ,	_SCREAMING_SNAKE_CASE  ,	_SCREAMING_SNAKE_CASE   )

	if not has_been_replaced:
		logger.warning(
		    "You are loading your model in 8bit or 4bit but no linear modules were found in your model."
		    " Please double check your model architecture, or submit an issue on github if you think this is"
		    " a bug."   )

	return model



def    snake_case_				(    *_SCREAMING_SNAKE_CASE  ,	**_SCREAMING_SNAKE_CASE   ):
	warnings.warn(
	    "`replace_8bit_linear` will be deprecated in a future version, please use `replace_with_bnb_linear` instead"  ,	_SCREAMING_SNAKE_CASE  ,	)
	return replace_with_bnb_linear(*_SCREAMING_SNAKE_CASE  ,	**_SCREAMING_SNAKE_CASE   )



def    snake_case_				(    *_SCREAMING_SNAKE_CASE  ,	**_SCREAMING_SNAKE_CASE   ):
	warnings.warn(
	    "`set_module_8bit_tensor_to_device` will be deprecated in a future version, please use `set_module_quantized_tensor_to_device` instead"  ,	_SCREAMING_SNAKE_CASE  ,	)
	return set_module_quantized_tensor_to_device(*_SCREAMING_SNAKE_CASE  ,	**_SCREAMING_SNAKE_CASE   )



def    snake_case_				(    _SCREAMING_SNAKE_CASE   ):
	__lowercase		       =			deepcopy(_SCREAMING_SNAKE_CASE   )  # this has 0 cost since it is done inside `init_empty_weights` context manager`
	tied_model.tie_weights()

	__lowercase		       =			find_tied_parameters(_SCREAMING_SNAKE_CASE   )
	# For compatibility with Accelerate < 0.18
	if isinstance(_SCREAMING_SNAKE_CASE  ,	_SCREAMING_SNAKE_CASE   ):
		__lowercase		       =			sum(list(tied_params.values()   )  ,	[]   ) + list(tied_params.keys()   )
	else:
		__lowercase		       =			sum(_SCREAMING_SNAKE_CASE  ,	[]   )
	__lowercase		       =			len(_SCREAMING_SNAKE_CASE   ) > 0

	# Check if it is a base model
	__lowercase		       =			not hasattr(_SCREAMING_SNAKE_CASE  ,	model.base_model_prefix   )

	# Ignore this for base models (BertModel, GPT2Model, etc.)
	if (not has_tied_params) and is_base_model:
		return []

	# otherwise they have an attached head
	__lowercase		       =			list(model.named_children()   )
	__lowercase		       =			[list_modules[-1][0]]

	# add last module together with tied weights
	__lowercase		       =			set(_SCREAMING_SNAKE_CASE   ) - set(_SCREAMING_SNAKE_CASE   )
	__lowercase		       =			list(set(_SCREAMING_SNAKE_CASE   )   ) + list(_SCREAMING_SNAKE_CASE   )

	# remove ".weight" from the keys
	__lowercase		       =			[".weight", ".bias"]
	__lowercase		       =			[]
	for name in list_untouched:
		for name_to_remove in names_to_remove:
			if name_to_remove in name:
				__lowercase		       =			name.replace(_SCREAMING_SNAKE_CASE  ,	""   )
		filtered_module_names.append(_SCREAMING_SNAKE_CASE   )

	return filtered_module_names








def    snake_case_				(    _SCREAMING_SNAKE_CASE  ,	_SCREAMING_SNAKE_CASE  ,	_SCREAMING_SNAKE_CASE   ):
	if len(_SCREAMING_SNAKE_CASE   ) != len(_SCREAMING_SNAKE_CASE   ):
		raise ValueError("The length of profit and weight must be same."   )
	if max_weight <= 0:
		raise ValueError("max_weight must greater than zero."   )
	if any(p < 0 for p in profit   ):
		raise ValueError("Profit can not be negative."   )
	if any(w < 0 for w in weight   ):
		raise ValueError("Weight can not be negative."   )

	# List created to store profit gained for the 1kg in case of each weight
	# respectively.  Calculate and append profit/weight for each element.
	__lowercase		       =			[p / w for p, w in zip(_SCREAMING_SNAKE_CASE  ,	_SCREAMING_SNAKE_CASE   )]

	# Creating a copy of the list and sorting profit/weight in ascending order
	__lowercase		       =			sorted(_SCREAMING_SNAKE_CASE   )

	# declaring useful variables
	__lowercase		       =			len(_SCREAMING_SNAKE_CASE   )
	__lowercase		       =			0
	__lowercase		       =			0
	__lowercase		       =			0

	# loop till the total weight do not reach max limit e.g. 15 kg and till i<length
	while limit <= max_weight and i < length:
		# flag value for encountered greatest element in sorted_profit_by_weight
		__lowercase		       =			sorted_profit_by_weight[length - i - 1]
		__lowercase		       =			profit_by_weight.index(_SCREAMING_SNAKE_CASE   )
		__lowercase		       =			-1

		# check if the weight encountered is less than the total weight
		# encountered before.
		if max_weight - limit >= weight[index]:
			limit += weight[index]
			# Adding profit gained for the given weight 1 ===
			# weight[index]/weight[index]
			gain += 1 * profit[index]
		else:
			# Since the weight encountered is greater than limit, therefore take the
			# required number of remaining kgs and calculate profit for it.
			# weight remaining / weight[index]
			gain += (max_weight - limit) / weight[index] * profit[index]
			break
		i += 1
	return gain


if __name__ == "__main__":
	print(
	    """Input profits, weights, and then max_weight (all positive ints) separated by """
	    """spaces."""
	)

	snake_case__					:     str    		=   [int(x) for x in input("""Input profits separated by spaces: """).split()]
	snake_case__					:     str    		=   [int(x) for x in input("""Input weights separated by spaces: """).split()]
	snake_case__					:     Optional[Any]    		=   int(input("""Max weight allowed: """))

	# Function Call
	calc_profit(profit, weight, max_weight)



