'''simple docstring'''

import copy
import importlib.metadata
import json
import os
from dataclasses import dataclass
from typing import Any, Dict, Union

from packaging import version

from ..utils import is_torch_available, logging


if is_torch_available():
       import torch


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





@dataclass
class 							lowercase						:


   def __init__(   self				:	Dict   ,		__lowerCAmelCase				:	Optional[Any]=False   ,		__lowerCAmelCase				:	Optional[Any]=False   ,		__lowerCAmelCase				:	Union[str, Any]=6.0   ,		__lowerCAmelCase				:	str=None   ,		__lowerCAmelCase				:	Optional[Any]=False   ,		__lowerCAmelCase				:	Tuple=False   ,		__lowerCAmelCase				:	int=None   ,		__lowerCAmelCase				:	Union[str, Any]="fp4"   ,		__lowerCAmelCase				:	Optional[int]=False   ,		**__lowerCAmelCase				:	Union[str, Any]   ,		)      ->					Union[str, Any]:
         lowercase_     =      load_in_abit
         lowercase_     =      load_in_abit
         lowercase_     =      llm_inta_threshold
         lowercase_     =      llm_inta_skip_modules
         lowercase_     =      llm_inta_enable_fpaa_cpu_offload
         lowercase_     =      llm_inta_has_fpaa_weight
         lowercase_     =      bnb_abit_quant_type
         lowercase_     =      bnb_abit_use_double_quant

         if bnb_abit_compute_dtype is None:
               lowercase_     =      torch.floataa
         elif isinstance(__lowerCAmelCase   ,		__lowerCAmelCase):
               lowercase_     =      getattr(__lowerCAmelCase   ,		__lowerCAmelCase)
         elif isinstance(__lowerCAmelCase   ,		torch.dtype):
               lowercase_     =      bnb_abit_compute_dtype
         else:
               raise ValueError("bnb_4bit_compute_dtype must be a string or a torch.dtype")

         self.post_init()


   def __UpperCAmelCase       (   self				:	str)      ->					Any:
         if not isinstance(self.llm_inta_threshold   ,		__lowerCAmelCase):
               raise ValueError("llm_int8_threshold must be a float")

         if self.llm_inta_skip_modules is not None and not isinstance(self.llm_inta_skip_modules   ,		__lowerCAmelCase):
               raise ValueError("llm_int8_skip_modules must be a list of strings")
         if not isinstance(self.llm_inta_enable_fpaa_cpu_offload   ,		__lowerCAmelCase):
               raise ValueError("llm_int8_enable_fp32_cpu_offload must be a boolean")

         if not isinstance(self.llm_inta_has_fpaa_weight   ,		__lowerCAmelCase):
               raise ValueError("llm_int8_has_fp16_weight must be a boolean")

         if self.bnb_abit_compute_dtype is not None and not isinstance(self.bnb_abit_compute_dtype   ,		torch.dtype):
               raise ValueError("bnb_4bit_compute_dtype must be torch.dtype")

         if not isinstance(self.bnb_abit_quant_type   ,		__lowerCAmelCase):
               raise ValueError("bnb_4bit_quant_type must be a string")

         if not isinstance(self.bnb_abit_use_double_quant   ,		__lowerCAmelCase):
               raise ValueError("bnb_4bit_use_double_quant must be a boolean")

         if self.load_in_abit and not version.parse(importlib.metadata.version("bitsandbytes")) >= version.parse(
             "0.39.0"):
               raise ValueError(
                   "4 bit quantization requires bitsandbytes>=0.39.0 - please upgrade your bitsandbytes version")


   def __UpperCAmelCase       (   self				:	List[str])      ->					str:
         return self.load_in_abit or self.load_in_abit


   def __UpperCAmelCase       (   self				:	str)      ->					Tuple:
         if self.load_in_abit:
               return "llm_int8"
         elif self.load_in_abit and self.bnb_abit_quant_type == "fp4":
               return "fp4"
         elif self.load_in_abit and self.bnb_abit_quant_type == "nf4":
               return "nf4"
         else:
               return None


   @classmethod
   def __UpperCAmelCase       (   cls				:	Dict   ,		__lowerCAmelCase				:	Any   ,		__lowerCAmelCase				:	str   ,		**__lowerCAmelCase				:	Dict)      ->					int:
         lowercase_     =      cls(**__lowerCAmelCase)

         lowercase_     =      []
         for key, value in kwargs.items():
               if hasattr(__lowerCAmelCase   ,		__lowerCAmelCase):
                     setattr(__lowerCAmelCase   ,		__lowerCAmelCase   ,		__lowerCAmelCase)
                     to_remove.append(__lowerCAmelCase)
         for key in to_remove:
               kwargs.pop(__lowerCAmelCase   ,		__lowerCAmelCase)

         if return_unused_kwargs:
               return config, kwargs
         else:
               return config


   def __UpperCAmelCase       (   self				:	Union[str, Any]   ,		__lowerCAmelCase				:	Union[str, os.PathLike])      ->					Optional[Any]:
         with open(__lowerCAmelCase   ,		"w"   ,		encoding="utf-8") as writer:
               lowercase_     =      self.to_dict()
               lowercase_     =      json.dumps(__lowerCAmelCase   ,		indent=2   ,		sort_keys=__lowerCAmelCase) + "\n"

               writer.write(__lowerCAmelCase)


   def __UpperCAmelCase       (   self				:	Union[str, Any])      ->					Dict[str, Any]:
         lowercase_     =      copy.deepcopy(self.__dict__)
         lowercase_     =      str(output["bnb_4bit_compute_dtype"]).split(".")[1]

         return output


   def __repr__(   self				:	Optional[int])      ->					str:
         return F'{self.__class__.__name__} {self.to_json_string()}'


   def __UpperCAmelCase       (   self				:	str   ,		__lowerCAmelCase				:	bool = True)      ->					str:
         if use_diff is True:
               lowercase_     =      self.to_diff_dict()
         else:
               lowercase_     =      self.to_dict()
         return json.dumps(__lowerCAmelCase   ,		indent=2   ,		sort_keys=__lowerCAmelCase) + "\n"


   def __UpperCAmelCase       (   self				:	Tuple)      ->					Dict[str, Any]:
         lowercase_     =      self.to_dict()

         # get the default config dict
         lowercase_     =      BitsAndBytesConfig().to_dict()

         lowercase_     =      {}

         # only serialize values that differ from the default config
         for key, value in config_dict.items():
               if value != default_config_dict[key]:
                     lowercase_     =      value

         return serializable_config_dict







'''simple docstring'''

# Author: OMKAR PATHAK, Nwachukwu Chidiebere

# Use a Python dictionary to construct the graph.
from __future__ import annotations

from pprint import pformat
from typing import Generic, TypeVar

lowerCAmelCase_ : Dict						  =      TypeVar("T")





class 							lowercase						(						Generic[T] ):


   def __init__(   self				:	int   ,		__lowerCAmelCase				:	bool = True)      ->					None:
         lowercase_     =      {}  # dictionary of lists
         lowercase_     =      directed


   def __UpperCAmelCase       (   self				:	int   ,		__lowerCAmelCase				:	T   ,		__lowerCAmelCase				:	T)      ->					GraphAdjacencyList[T]:

         if not self.directed:  # For undirected graphs
               # if both source vertex and destination vertex are both present in the
               # adjacency list, add destination vertex to source vertex list of adjacent
               # vertices and add source vertex to destination vertex list of adjacent
               # vertices.
               if source_vertex in self.adj_list and destination_vertex in self.adj_list:
                     self.adj_list[source_vertex].append(__lowerCAmelCase)
                     self.adj_list[destination_vertex].append(__lowerCAmelCase)
               # if only source vertex is present in adjacency list, add destination vertex
               # to source vertex list of adjacent vertices, then create a new vertex with
               # destination vertex as key and assign a list containing the source vertex
               # as it's first adjacent vertex.
               elif source_vertex in self.adj_list:
                     self.adj_list[source_vertex].append(__lowerCAmelCase)
                     lowercase_     =      [source_vertex]
               # if only destination vertex is present in adjacency list, add source vertex
               # to destination vertex list of adjacent vertices, then create a new vertex
               # with source vertex as key and assign a list containing the source vertex
               # as it's first adjacent vertex.
               elif destination_vertex in self.adj_list:
                     self.adj_list[destination_vertex].append(__lowerCAmelCase)
                     lowercase_     =      [destination_vertex]
               # if both source vertex and destination vertex are not present in adjacency
               # list, create a new vertex with source vertex as key and assign a list
               # containing the destination vertex as it's first adjacent vertex also
               # create a new vertex with destination vertex as key and assign a list
               # containing the source vertex as it's first adjacent vertex.
               else:
                     lowercase_     =      [destination_vertex]
                     lowercase_     =      [source_vertex]
         else:  # For directed graphs
               # if both source vertex and destination vertex are present in adjacency
               # list, add destination vertex to source vertex list of adjacent vertices.
               if source_vertex in self.adj_list and destination_vertex in self.adj_list:
                     self.adj_list[source_vertex].append(__lowerCAmelCase)
               # if only source vertex is present in adjacency list, add destination
               # vertex to source vertex list of adjacent vertices and create a new vertex
               # with destination vertex as key, which has no adjacent vertex
               elif source_vertex in self.adj_list:
                     self.adj_list[source_vertex].append(__lowerCAmelCase)
                     lowercase_     =      []
               # if only destination vertex is present in adjacency list, create a new
               # vertex with source vertex as key and assign a list containing destination
               # vertex as first adjacent vertex
               elif destination_vertex in self.adj_list:
                     lowercase_     =      [destination_vertex]
               # if both source vertex and destination vertex are not present in adjacency
               # list, create a new vertex with source vertex as key and a list containing
               # destination vertex as it's first adjacent vertex. Then create a new vertex
               # with destination vertex as key, which has no adjacent vertex
               else:
                     lowercase_     =      [destination_vertex]
                     lowercase_     =      []

         return self


   def __repr__(   self				:	str)      ->					str:
         return pformat(self.adj_list)






