




'''simple docstring'''



import inspect
import unittest

import torch
import torch.nn as nn

from accelerate.hooks import (
    AlignDevicesHook,
    ModelHook,
    SequentialHook,
    add_hook_to_module,
    attach_align_device_hook,
    remove_hook_from_module,
    remove_hook_from_submodules,
)
from accelerate.test_utils import require_multi_gpu





class      lowerCAmelCase (			nn.Module):


       def __init__( self	)   ->	Optional[Any]:



            '''simple docstring'''




            super().__init__()
            __snake_case            =	nn.Linear(3     ,	4	)
            __snake_case            =	nn.BatchNormad(4	)
            __snake_case            =	nn.Linear(4     ,	5	)




       def    lowerCAmelCase   ( self     ,	__SCREAMING_SNAKE_CASE	)   ->	Dict:



            '''simple docstring'''




            return self.lineara(self.batchnorm(self.lineara(__SCREAMING_SNAKE_CASE	)	)	)





class      lowerCAmelCase (			__lowerCAmelCase):


       def    lowerCAmelCase   ( self     ,	__SCREAMING_SNAKE_CASE     ,	*__SCREAMING_SNAKE_CASE     ,	**__SCREAMING_SNAKE_CASE	)   ->	Union[str, Any]:



            '''simple docstring'''




            return (args[0] + 1,) + args[1:], kwargs





class      lowerCAmelCase (			__lowerCAmelCase):


       def    lowerCAmelCase   ( self     ,	__SCREAMING_SNAKE_CASE     ,	__SCREAMING_SNAKE_CASE	)   ->	Optional[int]:



            '''simple docstring'''




            return output + 1





class      lowerCAmelCase (			unittest.TestCase):


       def    lowerCAmelCase   ( self	)   ->	Dict:



            '''simple docstring'''




            __snake_case            =	ModelForTest()
            __snake_case            =	ModelHook()

            add_hook_to_module(__SCREAMING_SNAKE_CASE     ,	__SCREAMING_SNAKE_CASE	)
            self.assertEqual(test_model._hf_hook     ,	__SCREAMING_SNAKE_CASE	)
            self.assertTrue(hasattr(__SCREAMING_SNAKE_CASE     ,	'''_old_forward'''	)	)

            # Check adding the hook did not change the name or the signature
            self.assertEqual(test_model.forward.__name__     ,	'''forward'''	)
            self.assertListEqual(list(inspect.signature(test_model.forward	).parameters	)     ,	['''x''']	)

            remove_hook_from_module(__SCREAMING_SNAKE_CASE	)
            self.assertFalse(hasattr(__SCREAMING_SNAKE_CASE     ,	'''_hf_hook'''	)	)
            self.assertFalse(hasattr(__SCREAMING_SNAKE_CASE     ,	'''_old_forward'''	)	)


       def    lowerCAmelCase   ( self	)   ->	Dict:



            '''simple docstring'''




            __snake_case            =	ModelForTest()
            __snake_case            =	ModelHook()

            add_hook_to_module(__SCREAMING_SNAKE_CASE     ,	__SCREAMING_SNAKE_CASE	)
            add_hook_to_module(__SCREAMING_SNAKE_CASE     ,	__SCREAMING_SNAKE_CASE     ,	append=__SCREAMING_SNAKE_CASE	)

            self.assertEqual(isinstance(test_model._hf_hook     ,	__SCREAMING_SNAKE_CASE	)     ,	__SCREAMING_SNAKE_CASE	)
            self.assertEqual(len(test_model._hf_hook.hooks	)     ,	2	)
            self.assertTrue(hasattr(__SCREAMING_SNAKE_CASE     ,	'''_old_forward'''	)	)

            # Check adding the hook did not change the name or the signature
            self.assertEqual(test_model.forward.__name__     ,	'''forward'''	)
            self.assertListEqual(list(inspect.signature(test_model.forward	).parameters	)     ,	['''x''']	)

            remove_hook_from_module(__SCREAMING_SNAKE_CASE	)
            self.assertFalse(hasattr(__SCREAMING_SNAKE_CASE     ,	'''_hf_hook'''	)	)
            self.assertFalse(hasattr(__SCREAMING_SNAKE_CASE     ,	'''_old_forward'''	)	)


       def    lowerCAmelCase   ( self	)   ->	Optional[Any]:



            '''simple docstring'''




            __snake_case            =	ModelForTest()
            __snake_case            =	torch.randn(2     ,	3	)
            __snake_case            =	test_model(x + 1	)
            __snake_case            =	test_model(x + 2	)

            __snake_case            =	PreForwardHook()
            add_hook_to_module(__SCREAMING_SNAKE_CASE     ,	__SCREAMING_SNAKE_CASE	)
            __snake_case            =	test_model(__SCREAMING_SNAKE_CASE	)
            self.assertTrue(torch.allclose(__SCREAMING_SNAKE_CASE     ,	__SCREAMING_SNAKE_CASE     ,	atol=1E-5	)	)

            # Attaching a hook to a model when it already has one replaces, does not chain
            __snake_case            =	PreForwardHook()
            add_hook_to_module(__SCREAMING_SNAKE_CASE     ,	__SCREAMING_SNAKE_CASE	)
            __snake_case            =	test_model(__SCREAMING_SNAKE_CASE	)
            self.assertTrue(torch.allclose(__SCREAMING_SNAKE_CASE     ,	__SCREAMING_SNAKE_CASE     ,	atol=1E-5	)	)

            # You need to use the sequential hook to chain two or more hooks
            __snake_case            =	SequentialHook(PreForwardHook()     ,	PreForwardHook()	)
            add_hook_to_module(__SCREAMING_SNAKE_CASE     ,	__SCREAMING_SNAKE_CASE	)

            __snake_case            =	test_model(__SCREAMING_SNAKE_CASE	)
            assert torch.allclose(__SCREAMING_SNAKE_CASE     ,	__SCREAMING_SNAKE_CASE     ,	atol=1E-5	)


       def    lowerCAmelCase   ( self	)   ->	Tuple:



            '''simple docstring'''




            __snake_case            =	ModelForTest()
            __snake_case            =	torch.randn(2     ,	3	)
            __snake_case            =	test_model(__SCREAMING_SNAKE_CASE	)

            __snake_case            =	PostForwardHook()
            add_hook_to_module(__SCREAMING_SNAKE_CASE     ,	__SCREAMING_SNAKE_CASE	)
            __snake_case            =	test_model(__SCREAMING_SNAKE_CASE	)
            self.assertTrue(torch.allclose(__SCREAMING_SNAKE_CASE     ,	output + 1     ,	atol=1E-5	)	)

            # Attaching a hook to a model when it already has one replaces, does not chain
            __snake_case            =	PostForwardHook()
            add_hook_to_module(__SCREAMING_SNAKE_CASE     ,	__SCREAMING_SNAKE_CASE	)
            __snake_case            =	test_model(__SCREAMING_SNAKE_CASE	)
            self.assertTrue(torch.allclose(__SCREAMING_SNAKE_CASE     ,	output + 1     ,	atol=1E-5	)	)

            # You need to use the sequential hook to chain two or more hooks
            __snake_case            =	SequentialHook(PostForwardHook()     ,	PostForwardHook()	)
            add_hook_to_module(__SCREAMING_SNAKE_CASE     ,	__SCREAMING_SNAKE_CASE	)

            __snake_case            =	test_model(__SCREAMING_SNAKE_CASE	)
            assert torch.allclose(__SCREAMING_SNAKE_CASE     ,	output + 2     ,	atol=1E-5	)


       def    lowerCAmelCase   ( self	)   ->	int:



            '''simple docstring'''




            __snake_case            =	ModelForTest()
            __snake_case            =	torch.randn(2     ,	3	)
            __snake_case            =	test_model(__SCREAMING_SNAKE_CASE	)

            __snake_case            =	PostForwardHook()
            add_hook_to_module(__SCREAMING_SNAKE_CASE     ,	__SCREAMING_SNAKE_CASE	)
            __snake_case            =	test_model(__SCREAMING_SNAKE_CASE	)
            self.assertTrue(torch.allclose(__SCREAMING_SNAKE_CASE     ,	output + 1	)	)
            self.assertTrue(outputa.requires_grad	)

            __snake_case            =	True
            __snake_case            =	test_model(__SCREAMING_SNAKE_CASE	)
            self.assertFalse(outputa.requires_grad	)


       @require_multi_gpu
       def    lowerCAmelCase   ( self	)   ->	Optional[int]:



            '''simple docstring'''




            __snake_case            =	ModelForTest()
            # Everything is on CPU
            self.assertEqual(model.lineara.weight.device     ,	torch.device('''cpu'''	)	)
            self.assertEqual(model.batchnorm.weight.device     ,	torch.device('''cpu'''	)	)
            self.assertEqual(model.lineara.weight.device     ,	torch.device('''cpu'''	)	)

            # This will move each submodule on different devices
            add_hook_to_module(model.lineara     ,	AlignDevicesHook(execution_device=0	)	)
            add_hook_to_module(model.batchnorm     ,	AlignDevicesHook(execution_device=0	)	)
            add_hook_to_module(model.lineara     ,	AlignDevicesHook(execution_device=1	)	)

            self.assertEqual(model.lineara.weight.device     ,	torch.device(0	)	)
            self.assertEqual(model.batchnorm.weight.device     ,	torch.device(0	)	)
            self.assertEqual(model.batchnorm.running_mean.device     ,	torch.device(0	)	)
            self.assertEqual(model.lineara.weight.device     ,	torch.device(1	)	)

            # We can still make a forward pass. The input does not need to be on any particular device
            __snake_case            =	torch.randn(2     ,	3	)
            __snake_case            =	model(__SCREAMING_SNAKE_CASE	)
            self.assertEqual(output.device     ,	torch.device(1	)	)

            # We can add a general hook to put back output on same device as input.
            add_hook_to_module(__SCREAMING_SNAKE_CASE     ,	AlignDevicesHook(io_same_device=__SCREAMING_SNAKE_CASE	)	)
            __snake_case            =	torch.randn(2     ,	3	).to(0	)
            __snake_case            =	model(__SCREAMING_SNAKE_CASE	)
            self.assertEqual(output.device     ,	torch.device(0	)	)


       def    lowerCAmelCase   ( self	)   ->	Dict:



            '''simple docstring'''




            __snake_case            =	ModelForTest()

            # Everything is on CPU
            self.assertEqual(model.lineara.weight.device     ,	torch.device('''cpu'''	)	)
            self.assertEqual(model.batchnorm.weight.device     ,	torch.device('''cpu'''	)	)
            self.assertEqual(model.lineara.weight.device     ,	torch.device('''cpu'''	)	)

            # This will move each submodule on different devices
            __snake_case            =	{'''execution_device''': 0 if torch.cuda.is_available() else '''cpu''', '''offload''': True}

            add_hook_to_module(model.lineara     ,	AlignDevicesHook(**__SCREAMING_SNAKE_CASE	)	)
            add_hook_to_module(model.batchnorm     ,	AlignDevicesHook(**__SCREAMING_SNAKE_CASE	)	)
            add_hook_to_module(model.lineara     ,	AlignDevicesHook(**__SCREAMING_SNAKE_CASE	)	)

            # Parameters have been offloaded, so on the meta device
            self.assertEqual(model.lineara.weight.device     ,	torch.device('''meta'''	)	)
            self.assertEqual(model.batchnorm.weight.device     ,	torch.device('''meta'''	)	)
            self.assertEqual(model.lineara.weight.device     ,	torch.device('''meta'''	)	)
            # Buffers are not included in the offload by default, so are on the execution device
            __snake_case            =	torch.device(hook_kwargs['''execution_device''']	)
            self.assertEqual(model.batchnorm.running_mean.device     ,	__SCREAMING_SNAKE_CASE	)

            __snake_case            =	torch.randn(2     ,	3	)
            __snake_case            =	model(__SCREAMING_SNAKE_CASE	)
            self.assertEqual(output.device     ,	__SCREAMING_SNAKE_CASE	)

            # Removing hooks loads back the weights in the model.
            remove_hook_from_module(model.lineara	)
            remove_hook_from_module(model.batchnorm	)
            remove_hook_from_module(model.lineara	)
            self.assertEqual(model.lineara.weight.device     ,	torch.device('''cpu'''	)	)
            self.assertEqual(model.batchnorm.weight.device     ,	torch.device('''cpu'''	)	)
            self.assertEqual(model.lineara.weight.device     ,	torch.device('''cpu'''	)	)

            # Now test with buffers included in the offload
            __snake_case            =	{
                '''execution_device''': 0 if torch.cuda.is_available() else '''cpu''',
                '''offload''': True,
                '''offload_buffers''': True,
            }

            add_hook_to_module(model.lineara     ,	AlignDevicesHook(**__SCREAMING_SNAKE_CASE	)	)
            add_hook_to_module(model.batchnorm     ,	AlignDevicesHook(**__SCREAMING_SNAKE_CASE	)	)
            add_hook_to_module(model.lineara     ,	AlignDevicesHook(**__SCREAMING_SNAKE_CASE	)	)

            # Parameters have been offloaded, so on the meta device, buffers included
            self.assertEqual(model.lineara.weight.device     ,	torch.device('''meta'''	)	)
            self.assertEqual(model.batchnorm.weight.device     ,	torch.device('''meta'''	)	)
            self.assertEqual(model.lineara.weight.device     ,	torch.device('''meta'''	)	)
            self.assertEqual(model.batchnorm.running_mean.device     ,	torch.device('''meta'''	)	)

            __snake_case            =	torch.randn(2     ,	3	)
            __snake_case            =	model(__SCREAMING_SNAKE_CASE	)
            self.assertEqual(output.device     ,	__SCREAMING_SNAKE_CASE	)

            # Removing hooks loads back the weights in the model.
            remove_hook_from_module(model.lineara	)
            remove_hook_from_module(model.batchnorm	)
            remove_hook_from_module(model.lineara	)
            self.assertEqual(model.lineara.weight.device     ,	torch.device('''cpu'''	)	)
            self.assertEqual(model.batchnorm.weight.device     ,	torch.device('''cpu'''	)	)
            self.assertEqual(model.lineara.weight.device     ,	torch.device('''cpu'''	)	)


       def    lowerCAmelCase   ( self	)   ->	str:



            '''simple docstring'''




            __snake_case            =	ModelForTest()

            # Everything is on CPU
            self.assertEqual(model.lineara.weight.device     ,	torch.device('''cpu'''	)	)
            self.assertEqual(model.batchnorm.weight.device     ,	torch.device('''cpu'''	)	)
            self.assertEqual(model.lineara.weight.device     ,	torch.device('''cpu'''	)	)

            # This will move each submodule on different devices
            __snake_case            =	0 if torch.cuda.is_available() else '''cpu'''
            attach_align_device_hook(__SCREAMING_SNAKE_CASE     ,	execution_device=__SCREAMING_SNAKE_CASE     ,	offload=__SCREAMING_SNAKE_CASE	)

            # Parameters have been offloaded, so on the meta device
            self.assertEqual(model.lineara.weight.device     ,	torch.device('''meta'''	)	)
            self.assertEqual(model.batchnorm.weight.device     ,	torch.device('''meta'''	)	)
            self.assertEqual(model.lineara.weight.device     ,	torch.device('''meta'''	)	)
            # Buffers are not included in the offload by default, so are on the execution device
            __snake_case            =	torch.device(__SCREAMING_SNAKE_CASE	)
            self.assertEqual(model.batchnorm.running_mean.device     ,	__SCREAMING_SNAKE_CASE	)

            __snake_case            =	torch.randn(2     ,	3	)
            __snake_case            =	model(__SCREAMING_SNAKE_CASE	)
            self.assertEqual(output.device     ,	__SCREAMING_SNAKE_CASE	)

            # Removing hooks loads back the weights in the model.
            remove_hook_from_submodules(__SCREAMING_SNAKE_CASE	)
            self.assertEqual(model.lineara.weight.device     ,	torch.device('''cpu'''	)	)
            self.assertEqual(model.batchnorm.weight.device     ,	torch.device('''cpu'''	)	)
            self.assertEqual(model.lineara.weight.device     ,	torch.device('''cpu'''	)	)

            # Now test with buffers included in the offload
            attach_align_device_hook(__SCREAMING_SNAKE_CASE     ,	execution_device=__SCREAMING_SNAKE_CASE     ,	offload=__SCREAMING_SNAKE_CASE     ,	offload_buffers=__SCREAMING_SNAKE_CASE	)

            # Parameters have been offloaded, so on the meta device, buffers included
            self.assertEqual(model.lineara.weight.device     ,	torch.device('''meta'''	)	)
            self.assertEqual(model.batchnorm.weight.device     ,	torch.device('''meta'''	)	)
            self.assertEqual(model.lineara.weight.device     ,	torch.device('''meta'''	)	)
            self.assertEqual(model.batchnorm.running_mean.device     ,	torch.device('''meta'''	)	)

            __snake_case            =	torch.randn(2     ,	3	)
            __snake_case            =	model(__SCREAMING_SNAKE_CASE	)
            self.assertEqual(output.device     ,	__SCREAMING_SNAKE_CASE	)

            # Removing hooks loads back the weights in the model.
            remove_hook_from_submodules(__SCREAMING_SNAKE_CASE	)
            self.assertEqual(model.lineara.weight.device     ,	torch.device('''cpu'''	)	)
            self.assertEqual(model.batchnorm.weight.device     ,	torch.device('''cpu'''	)	)
            self.assertEqual(model.lineara.weight.device     ,	torch.device('''cpu'''	)	)




       def    lowerCAmelCase   ( self	)   ->	Tuple:



            '''simple docstring'''




            __snake_case            =	ModelForTest()

            # Everything is on CPU
            self.assertEqual(model.lineara.weight.device     ,	torch.device('''cpu'''	)	)
            self.assertEqual(model.batchnorm.weight.device     ,	torch.device('''cpu'''	)	)
            self.assertEqual(model.lineara.weight.device     ,	torch.device('''cpu'''	)	)

            # This will move each submodule on different devices
            __snake_case            =	0 if torch.cuda.is_available() else '''cpu'''
            attach_align_device_hook(
                __SCREAMING_SNAKE_CASE     ,	execution_device=__SCREAMING_SNAKE_CASE     ,	offload=__SCREAMING_SNAKE_CASE     ,	weights_map=model.state_dict()	)

            # Parameters have been offloaded, so on the meta device
            self.assertEqual(model.lineara.weight.device     ,	torch.device('''meta'''	)	)
            self.assertEqual(model.batchnorm.weight.device     ,	torch.device('''meta'''	)	)
            self.assertEqual(model.lineara.weight.device     ,	torch.device('''meta'''	)	)
            # Buffers are not included in the offload by default, so are on the execution device
            __snake_case            =	torch.device(__SCREAMING_SNAKE_CASE	)
            self.assertEqual(model.batchnorm.running_mean.device     ,	__SCREAMING_SNAKE_CASE	)

            __snake_case            =	torch.randn(2     ,	3	)
            __snake_case            =	model(__SCREAMING_SNAKE_CASE	)
            self.assertEqual(output.device     ,	__SCREAMING_SNAKE_CASE	)

            # Removing hooks loads back the weights in the model.
            remove_hook_from_submodules(__SCREAMING_SNAKE_CASE	)
            self.assertEqual(model.lineara.weight.device     ,	torch.device('''cpu'''	)	)
            self.assertEqual(model.batchnorm.weight.device     ,	torch.device('''cpu'''	)	)
            self.assertEqual(model.lineara.weight.device     ,	torch.device('''cpu'''	)	)

            # Now test with buffers included in the offload
            attach_align_device_hook(
                __SCREAMING_SNAKE_CASE     ,	execution_device=__SCREAMING_SNAKE_CASE     ,	offload=__SCREAMING_SNAKE_CASE     ,	weights_map=model.state_dict()     ,	offload_buffers=__SCREAMING_SNAKE_CASE     ,	)

            # Parameters have been offloaded, so on the meta device, buffers included
            self.assertEqual(model.lineara.weight.device     ,	torch.device('''meta'''	)	)
            self.assertEqual(model.batchnorm.weight.device     ,	torch.device('''meta'''	)	)
            self.assertEqual(model.lineara.weight.device     ,	torch.device('''meta'''	)	)
            self.assertEqual(model.batchnorm.running_mean.device     ,	torch.device('''meta'''	)	)

            __snake_case            =	torch.randn(2     ,	3	)
            __snake_case            =	model(__SCREAMING_SNAKE_CASE	)
            self.assertEqual(output.device     ,	__SCREAMING_SNAKE_CASE	)

            # Removing hooks loads back the weights in the model.
            remove_hook_from_submodules(__SCREAMING_SNAKE_CASE	)
            self.assertEqual(model.lineara.weight.device     ,	torch.device('''cpu'''	)	)
            self.assertEqual(model.batchnorm.weight.device     ,	torch.device('''cpu'''	)	)
            self.assertEqual(model.lineara.weight.device     ,	torch.device('''cpu'''	)	)












'''simple docstring'''


def  _SCREAMING_SNAKE_CASE     (      UpperCamelCase__    :					list[int] ,    UpperCamelCase__    :					str				):




     """simple docstring"""


     a_     :							Tuple     						=  int(UpperCamelCase__				)

     # Initialize Result
     a_     :							Tuple     						=  []

     # Traverse through all denomination
     for denomination in reversed(UpperCamelCase__				):
          # Find denominations
          while int(UpperCamelCase__				) >= int(UpperCamelCase__				):
               total_value -= int(UpperCamelCase__				)
               answer.append(UpperCamelCase__				)  # Append the "answers" array

     return answer


# Driver Code
if __name__ == "__main__":
 lowerCAmelCase_      :  List[str]				     =  []
 lowerCAmelCase_      :  Union[str, Any]				     =  '0'

 if (
     input('Do you want to enter your denominations ? (yY/n): ').strip().lower()
     == "y"
 ):
  lowerCAmelCase_      :  str				     =  int(input('Enter the number of denominations you want to add: ').strip())

  for i in range(0, n):
   denominations.append(int(input(f"Denomination {i}: ").strip()))
  lowerCAmelCase_      :  Union[str, Any]				     =  input('Enter the change you want to make in Indian Currency: ').strip()
 else:
  # All denominations of Indian Currency if user does not enter
  lowerCAmelCase_      :  List[Any]				     =  [1, 2, 5, 10, 20, 50, 100, 500, 2000]
  lowerCAmelCase_      :  str				     =  input('Enter the change you want to make: ').strip()

 if int(value) == 0 or int(value) < 0:
  print('The total value cannot be zero or negative.')

 else:
  print(f"Following is minimal change for {value}: ")
  lowerCAmelCase_      :  Optional[int]				     =  find_minimum_change(denominations, value)
  # Print result
  for i in range(len(answer)):
   print(answer[i], end=' ')
