





import random
import unittest

from torch.utils.data import BatchSampler, DataLoader, IterableDataset

from accelerate import Accelerator
from accelerate.data_loader import (
    BatchSamplerShard,
    DataLoaderDispatcher,
    DataLoaderShard,
    IterableDatasetShard,
    SkipBatchSampler,
    SkipDataLoader,
    skip_first_batches,
)





class UpperCAmelCase_				( _SCREAMING_SNAKE_CASE ):


  def __init__(							self ,__snake_case=0.01 ,__snake_case=1_0_0_0 ):



       """simple docstring"""





       A_          =       p_stop
       A_          =       max_length




  def __iter__(							self ):



       """simple docstring"""





       A_          =       0
       A_          =       False
       while not stop and count < self.max_length:
            yield count
            count += 1
            A_          =       random.random() < self.p_stop





class UpperCAmelCase_				( unittest.TestCase ):


  def 						__UpperCAmelCase     (							self ,__snake_case ,__snake_case ,__snake_case=False ,__snake_case=True ):



       """simple docstring"""





       A_          =       [
           BatchSamplerShard(__snake_case ,2 ,__snake_case ,split_batches=__snake_case ,even_batches=__snake_case )
           for i in range(2 )
       ]
       A_          =       [list(__snake_case ) for batch_sampler_shard in batch_sampler_shards]
       if not split_batches:
            self.assertListEqual([len(__snake_case ) for shard in batch_sampler_shards] ,[len(__snake_case ) for e in expected] )
       self.assertListEqual(__snake_case ,__snake_case )


  def 						__UpperCAmelCase     (							self ):



       """simple docstring"""





       A_          =       BatchSampler(range(2_4 ) ,batch_size=3 ,drop_last=__snake_case )
       A_          =       [
           [[0, 1, 2], [6, 7, 8], [1_2, 1_3, 1_4], [1_8, 1_9, 2_0]],
           [[3, 4, 5], [9, 1_0, 1_1], [1_5, 1_6, 1_7], [2_1, 2_2, 2_3]],
       ]
       self.check_batch_sampler_shards(__snake_case ,__snake_case )

       A_          =       BatchSampler(range(2_4 ) ,batch_size=3 ,drop_last=__snake_case )
       # Expected shouldn't change
       self.check_batch_sampler_shards(__snake_case ,__snake_case )

       # Check the shards when the dataset is a round multiple of batch size but not total batch size.
       A_          =       BatchSampler(range(2_1 ) ,batch_size=3 ,drop_last=__snake_case )
       A_          =       [
           [[0, 1, 2], [6, 7, 8], [1_2, 1_3, 1_4], [1_8, 1_9, 2_0]],
           [[3, 4, 5], [9, 1_0, 1_1], [1_5, 1_6, 1_7], [0, 1, 2]],
       ]
       self.check_batch_sampler_shards(__snake_case ,__snake_case )

       A_          =       BatchSampler(range(2_1 ) ,batch_size=3 ,drop_last=__snake_case )
       A_          =       [
           [[0, 1, 2], [6, 7, 8], [1_2, 1_3, 1_4]],
           [[3, 4, 5], [9, 1_0, 1_1], [1_5, 1_6, 1_7]],
       ]
       self.check_batch_sampler_shards(__snake_case ,__snake_case )

       # Check the shards when the dataset is not a round multiple of batch size but has a multiple of
       # num_processes batch.
       A_          =       BatchSampler(range(2_2 ) ,batch_size=3 ,drop_last=__snake_case )
       A_          =       [
           [[0, 1, 2], [6, 7, 8], [1_2, 1_3, 1_4], [1_8, 1_9, 2_0]],
           [[3, 4, 5], [9, 1_0, 1_1], [1_5, 1_6, 1_7], [2_1, 0, 1]],
       ]
       self.check_batch_sampler_shards(__snake_case ,__snake_case )

       A_          =       BatchSampler(range(2_2 ) ,batch_size=3 ,drop_last=__snake_case )
       A_          =       [
           [[0, 1, 2], [6, 7, 8], [1_2, 1_3, 1_4]],
           [[3, 4, 5], [9, 1_0, 1_1], [1_5, 1_6, 1_7]],
       ]
       self.check_batch_sampler_shards(__snake_case ,__snake_case )

       # Check the shards when the dataset is not a round multiple of batch size but and has not a multiple of
       # num_processes batch.
       A_          =       BatchSampler(range(2_0 ) ,batch_size=3 ,drop_last=__snake_case )
       A_          =       [
           [[0, 1, 2], [6, 7, 8], [1_2, 1_3, 1_4], [1_8, 1_9, 0]],
           [[3, 4, 5], [9, 1_0, 1_1], [1_5, 1_6, 1_7], [1, 2, 3]],
       ]
       self.check_batch_sampler_shards(__snake_case ,__snake_case )

       A_          =       BatchSampler(range(2_0 ) ,batch_size=3 ,drop_last=__snake_case )
       A_          =       [
           [[0, 1, 2], [6, 7, 8], [1_2, 1_3, 1_4]],
           [[3, 4, 5], [9, 1_0, 1_1], [1_5, 1_6, 1_7]],
       ]
       self.check_batch_sampler_shards(__snake_case ,__snake_case )

       # Check the shards when the dataset is very small.
       A_          =       BatchSampler(range(2 ) ,batch_size=3 ,drop_last=__snake_case )
       A_          =       [[[0, 1, 0]], [[1, 0, 1]]]
       self.check_batch_sampler_shards(__snake_case ,__snake_case )

       A_          =       BatchSampler(range(2 ) ,batch_size=3 ,drop_last=__snake_case )
       A_          =       [[], []]
       self.check_batch_sampler_shards(__snake_case ,__snake_case )


  def 						__UpperCAmelCase     (							self ):



       """simple docstring"""





       A_          =       BatchSampler(range(2_4 ) ,batch_size=4 ,drop_last=__snake_case )
       A_          =       [
           [[0, 1], [4, 5], [8, 9], [1_2, 1_3], [1_6, 1_7], [2_0, 2_1]],
           [[2, 3], [6, 7], [1_0, 1_1], [1_4, 1_5], [1_8, 1_9], [2_2, 2_3]],
       ]
       self.check_batch_sampler_shards(__snake_case ,__snake_case ,split_batches=__snake_case )

       A_          =       BatchSampler(range(2_4 ) ,batch_size=4 ,drop_last=__snake_case )
       # Expected shouldn't change
       self.check_batch_sampler_shards(__snake_case ,__snake_case ,split_batches=__snake_case )

       # Check the shards when the dataset is not a round multiple of batch size.
       A_          =       BatchSampler(range(2_2 ) ,batch_size=4 ,drop_last=__snake_case )
       A_          =       [
           [[0, 1], [4, 5], [8, 9], [1_2, 1_3], [1_6, 1_7], [2_0, 2_1]],
           [[2, 3], [6, 7], [1_0, 1_1], [1_4, 1_5], [1_8, 1_9], [0, 1]],
       ]
       self.check_batch_sampler_shards(__snake_case ,__snake_case ,split_batches=__snake_case )

       A_          =       BatchSampler(range(2_2 ) ,batch_size=4 ,drop_last=__snake_case )
       A_          =       [
           [[0, 1], [4, 5], [8, 9], [1_2, 1_3], [1_6, 1_7]],
           [[2, 3], [6, 7], [1_0, 1_1], [1_4, 1_5], [1_8, 1_9]],
       ]
       self.check_batch_sampler_shards(__snake_case ,__snake_case ,split_batches=__snake_case )

       # Check the shards when the dataset is not a round multiple of batch size or num_processes.
       A_          =       BatchSampler(range(2_1 ) ,batch_size=4 ,drop_last=__snake_case )
       A_          =       [
           [[0, 1], [4, 5], [8, 9], [1_2, 1_3], [1_6, 1_7], [2_0, 0]],
           [[2, 3], [6, 7], [1_0, 1_1], [1_4, 1_5], [1_8, 1_9], [1, 2]],
       ]
       self.check_batch_sampler_shards(__snake_case ,__snake_case ,split_batches=__snake_case )

       A_          =       BatchSampler(range(2_1 ) ,batch_size=4 ,drop_last=__snake_case )
       A_          =       [
           [[0, 1], [4, 5], [8, 9], [1_2, 1_3], [1_6, 1_7]],
           [[2, 3], [6, 7], [1_0, 1_1], [1_4, 1_5], [1_8, 1_9]],
       ]
       self.check_batch_sampler_shards(__snake_case ,__snake_case ,split_batches=__snake_case )

       # Check the shards when the dataset is very small.
       A_          =       BatchSampler(range(2 ) ,batch_size=4 ,drop_last=__snake_case )
       A_          =       [[[0, 1]], [[0, 1]]]
       self.check_batch_sampler_shards(__snake_case ,__snake_case ,split_batches=__snake_case )

       A_          =       BatchSampler(range(2 ) ,batch_size=4 ,drop_last=__snake_case )
       A_          =       [[], []]
       self.check_batch_sampler_shards(__snake_case ,__snake_case ,split_batches=__snake_case )


  def 						__UpperCAmelCase     (							self ):



       """simple docstring"""





       A_          =       BatchSampler(range(2_4 ) ,batch_size=3 ,drop_last=__snake_case )
       A_          =       [
           [[0, 1, 2], [6, 7, 8], [1_2, 1_3, 1_4], [1_8, 1_9, 2_0]],
           [[3, 4, 5], [9, 1_0, 1_1], [1_5, 1_6, 1_7], [2_1, 2_2, 2_3]],
       ]
       self.check_batch_sampler_shards(__snake_case ,__snake_case ,even_batches=__snake_case )

       A_          =       BatchSampler(range(2_4 ) ,batch_size=3 ,drop_last=__snake_case )
       # Expected shouldn't change
       self.check_batch_sampler_shards(__snake_case ,__snake_case ,even_batches=__snake_case )

       # Check the shards when the dataset is a round multiple of batch size but not total batch size.
       A_          =       BatchSampler(range(2_1 ) ,batch_size=3 ,drop_last=__snake_case )
       A_          =       [
           [[0, 1, 2], [6, 7, 8], [1_2, 1_3, 1_4], [1_8, 1_9, 2_0]],
           [[3, 4, 5], [9, 1_0, 1_1], [1_5, 1_6, 1_7]],
       ]
       self.check_batch_sampler_shards(__snake_case ,__snake_case ,even_batches=__snake_case )

       A_          =       BatchSampler(range(2_1 ) ,batch_size=3 ,drop_last=__snake_case )
       A_          =       [
           [[0, 1, 2], [6, 7, 8], [1_2, 1_3, 1_4]],
           [[3, 4, 5], [9, 1_0, 1_1], [1_5, 1_6, 1_7]],
       ]
       self.check_batch_sampler_shards(__snake_case ,__snake_case ,even_batches=__snake_case )

       # Check the shards when the dataset is not a round multiple of batch size but has a multiple of
       # num_processes batch.
       A_          =       BatchSampler(range(2_2 ) ,batch_size=3 ,drop_last=__snake_case )
       A_          =       [
           [[0, 1, 2], [6, 7, 8], [1_2, 1_3, 1_4], [1_8, 1_9, 2_0]],
           [[3, 4, 5], [9, 1_0, 1_1], [1_5, 1_6, 1_7], [2_1]],
       ]
       self.check_batch_sampler_shards(__snake_case ,__snake_case ,even_batches=__snake_case )

       A_          =       BatchSampler(range(2_2 ) ,batch_size=3 ,drop_last=__snake_case )
       A_          =       [
           [[0, 1, 2], [6, 7, 8], [1_2, 1_3, 1_4]],
           [[3, 4, 5], [9, 1_0, 1_1], [1_5, 1_6, 1_7]],
       ]
       self.check_batch_sampler_shards(__snake_case ,__snake_case ,even_batches=__snake_case )

       # Check the shards when the dataset is not a round multiple of batch size but and has not a multiple of
       # num_processes batch.
       A_          =       BatchSampler(range(2_0 ) ,batch_size=3 ,drop_last=__snake_case )
       A_          =       [
           [[0, 1, 2], [6, 7, 8], [1_2, 1_3, 1_4], [1_8, 1_9]],
           [[3, 4, 5], [9, 1_0, 1_1], [1_5, 1_6, 1_7]],
       ]
       self.check_batch_sampler_shards(__snake_case ,__snake_case ,even_batches=__snake_case )

       A_          =       BatchSampler(range(2_0 ) ,batch_size=3 ,drop_last=__snake_case )
       A_          =       [
           [[0, 1, 2], [6, 7, 8], [1_2, 1_3, 1_4]],
           [[3, 4, 5], [9, 1_0, 1_1], [1_5, 1_6, 1_7]],
       ]
       self.check_batch_sampler_shards(__snake_case ,__snake_case ,even_batches=__snake_case )

       # Check the shards when the dataset is very small.
       A_          =       BatchSampler(range(2 ) ,batch_size=3 ,drop_last=__snake_case )
       A_          =       [[[0, 1]], []]
       self.check_batch_sampler_shards(__snake_case ,__snake_case ,even_batches=__snake_case )

       A_          =       BatchSampler(range(2 ) ,batch_size=3 ,drop_last=__snake_case )
       A_          =       [[], []]
       self.check_batch_sampler_shards(__snake_case ,__snake_case ,even_batches=__snake_case )


  def 						__UpperCAmelCase     (							self ):



       """simple docstring"""





       A_          =       BatchSampler(range(2_4 ) ,batch_size=4 ,drop_last=__snake_case )
       A_          =       [
           [[0, 1], [4, 5], [8, 9], [1_2, 1_3], [1_6, 1_7], [2_0, 2_1]],
           [[2, 3], [6, 7], [1_0, 1_1], [1_4, 1_5], [1_8, 1_9], [2_2, 2_3]],
       ]
       self.check_batch_sampler_shards(__snake_case ,__snake_case ,split_batches=__snake_case ,even_batches=__snake_case )

       A_          =       BatchSampler(range(2_4 ) ,batch_size=4 ,drop_last=__snake_case )
       # Expected shouldn't change
       self.check_batch_sampler_shards(__snake_case ,__snake_case ,split_batches=__snake_case ,even_batches=__snake_case )

       # Check the shards when the dataset is not a round multiple of batch size.
       A_          =       BatchSampler(range(2_2 ) ,batch_size=4 ,drop_last=__snake_case )
       A_          =       [
           [[0, 1], [4, 5], [8, 9], [1_2, 1_3], [1_6, 1_7], [2_0, 2_1]],
           [[2, 3], [6, 7], [1_0, 1_1], [1_4, 1_5], [1_8, 1_9]],
       ]
       self.check_batch_sampler_shards(__snake_case ,__snake_case ,split_batches=__snake_case ,even_batches=__snake_case )

       A_          =       BatchSampler(range(2_2 ) ,batch_size=4 ,drop_last=__snake_case )
       A_          =       [
           [[0, 1], [4, 5], [8, 9], [1_2, 1_3], [1_6, 1_7]],
           [[2, 3], [6, 7], [1_0, 1_1], [1_4, 1_5], [1_8, 1_9]],
       ]
       self.check_batch_sampler_shards(__snake_case ,__snake_case ,split_batches=__snake_case ,even_batches=__snake_case )

       # Check the shards when the dataset is not a round multiple of batch size or num_processes.
       A_          =       BatchSampler(range(2_1 ) ,batch_size=4 ,drop_last=__snake_case )
       A_          =       [
           [[0, 1], [4, 5], [8, 9], [1_2, 1_3], [1_6, 1_7], [2_0]],
           [[2, 3], [6, 7], [1_0, 1_1], [1_4, 1_5], [1_8, 1_9]],
       ]
       self.check_batch_sampler_shards(__snake_case ,__snake_case ,split_batches=__snake_case ,even_batches=__snake_case )

       A_          =       BatchSampler(range(2_1 ) ,batch_size=4 ,drop_last=__snake_case )
       A_          =       [
           [[0, 1], [4, 5], [8, 9], [1_2, 1_3], [1_6, 1_7]],
           [[2, 3], [6, 7], [1_0, 1_1], [1_4, 1_5], [1_8, 1_9]],
       ]
       self.check_batch_sampler_shards(__snake_case ,__snake_case ,split_batches=__snake_case ,even_batches=__snake_case )

       # Check the shards when the dataset is very small.
       A_          =       BatchSampler(range(2 ) ,batch_size=4 ,drop_last=__snake_case )
       A_          =       [[[0, 1]], []]
       self.check_batch_sampler_shards(__snake_case ,__snake_case ,split_batches=__snake_case ,even_batches=__snake_case )

       A_          =       BatchSampler(range(2 ) ,batch_size=4 ,drop_last=__snake_case )
       A_          =       [[], []]
       self.check_batch_sampler_shards(__snake_case ,__snake_case ,split_batches=__snake_case ,even_batches=__snake_case )


  def 						__UpperCAmelCase     (							self ):



       """simple docstring"""





       A_          =       [[0, 1, 2], [3, 4], [5, 6, 7, 8], [9, 1_0, 1_1], [1_2, 1_3]]
       A_          =       [BatchSamplerShard(__snake_case ,2 ,__snake_case ,even_batches=__snake_case ) for i in range(2 )]

       self.assertEqual(len(batch_sampler_shards[0] ) ,3 )
       self.assertEqual(len(batch_sampler_shards[1] ) ,2 )

       self.assertListEqual(list(batch_sampler_shards[0] ) ,[[0, 1, 2], [5, 6, 7, 8], [1_2, 1_3]] )
       self.assertListEqual(list(batch_sampler_shards[1] ) ,[[3, 4], [9, 1_0, 1_1]] )


  def 						__UpperCAmelCase     (							self ,__snake_case ,__snake_case ,__snake_case ,__snake_case=False ,__snake_case=2 ,__snake_case=False ):



       """simple docstring"""





       random.seed(__snake_case )
       A_          =       list(__snake_case )

       A_          =       [
           IterableDatasetShard(
               __snake_case ,batch_size=__snake_case ,drop_last=__snake_case ,num_processes=__snake_case ,process_index=__snake_case ,split_batches=__snake_case ,)
           for i in range(__snake_case )
       ]
       A_          =       []
       for iterable_dataset_shard in iterable_dataset_shards:
            # Since our random iterable dataset will be... random... we need to use a seed to get reproducible results.
            random.seed(__snake_case )
            iterable_dataset_lists.append(list(__snake_case ) )

       A_          =       batch_size // num_processes if split_batches else batch_size
       # All iterable dataset shard should have the same length, a round multiple of shard_batch_size
       A_          =       iterable_dataset_lists[0]
       for l in iterable_dataset_lists[1:]:
            self.assertEqual(len(__snake_case ) ,len(__snake_case ) )
            self.assertTrue(len(__snake_case ) % shard_batch_size == 0 )

       A_          =       []
       for idx in range(0 ,len(__snake_case ) ,__snake_case ):
            for l in iterable_dataset_lists:
                 observed += l[idx : idx + shard_batch_size]

       if not drop_last:
            while len(__snake_case ) < len(__snake_case ):
                 reference += reference
       self.assertListEqual(__snake_case ,reference[: len(__snake_case )] )


  def 						__UpperCAmelCase     (							self ):



       """simple docstring"""





       A_          =       4_2
       A_          =       RandomIterableDataset()

       self.check_iterable_dataset_shards(__snake_case ,__snake_case ,batch_size=4 ,drop_last=__snake_case ,split_batches=__snake_case )
       self.check_iterable_dataset_shards(__snake_case ,__snake_case ,batch_size=4 ,drop_last=__snake_case ,split_batches=__snake_case )
       self.check_iterable_dataset_shards(__snake_case ,__snake_case ,batch_size=4 ,drop_last=__snake_case ,split_batches=__snake_case )
       self.check_iterable_dataset_shards(__snake_case ,__snake_case ,batch_size=4 ,drop_last=__snake_case ,split_batches=__snake_case )

       # Edge case with a very small dataset
       A_          =       RandomIterableDataset(max_length=2 )

       self.check_iterable_dataset_shards(__snake_case ,__snake_case ,batch_size=4 ,drop_last=__snake_case ,split_batches=__snake_case )
       self.check_iterable_dataset_shards(__snake_case ,__snake_case ,batch_size=4 ,drop_last=__snake_case ,split_batches=__snake_case )
       self.check_iterable_dataset_shards(__snake_case ,__snake_case ,batch_size=4 ,drop_last=__snake_case ,split_batches=__snake_case )
       self.check_iterable_dataset_shards(__snake_case ,__snake_case ,batch_size=4 ,drop_last=__snake_case ,split_batches=__snake_case )


  def 						__UpperCAmelCase     (							self ):



       """simple docstring"""





       A_          =       BatchSampler(range(1_6 ) ,batch_size=4 ,drop_last=__snake_case )
       A_          =       SkipBatchSampler(__snake_case ,2 )
       self.assertListEqual(list(__snake_case ) ,[[8, 9, 1_0, 1_1], [1_2, 1_3, 1_4, 1_5]] )


  def 						__UpperCAmelCase     (							self ):



       """simple docstring"""





       A_          =       SkipDataLoader(list(range(1_6 ) ) ,batch_size=4 ,skip_batches=2 )
       self.assertListEqual([t.tolist() for t in dataloader] ,[[8, 9, 1_0, 1_1], [1_2, 1_3, 1_4, 1_5]] )


  def 						__UpperCAmelCase     (							self ):



       """simple docstring"""





       A_          =       DataLoader(list(range(1_6 ) ) ,batch_size=4 )
       A_          =       skip_first_batches(__snake_case ,num_batches=2 )
       self.assertListEqual([t.tolist() for t in new_dataloader] ,[[8, 9, 1_0, 1_1], [1_2, 1_3, 1_4, 1_5]] )


  def 						__UpperCAmelCase     (							self ):



       """simple docstring"""





       A_          =       DataLoaderShard(list(range(1_6 ) ) ,batch_size=4 )
       for idx, _ in enumerate(__snake_case ):
            self.assertEqual(dataloader.end_of_dataloader ,idx == 3 )

       # Test it also works on the second iteration
       for idx, _ in enumerate(__snake_case ):
            self.assertEqual(dataloader.end_of_dataloader ,idx == 3 )




  def 						__UpperCAmelCase     (							self ):



       """simple docstring"""





       Accelerator()
       A_          =       DataLoaderDispatcher(range(1_6 ) ,batch_size=4 )
       for idx, _ in enumerate(__snake_case ):
            self.assertEqual(dataloader.end_of_dataloader ,idx == 3 )

       # Test it also works on the second iteration
       for idx, _ in enumerate(__snake_case ):
            self.assertEqual(dataloader.end_of_dataloader ,idx == 3 )










from math import pi, sqrt, tan

def      UpperCAmelCase_    (    _UpperCAmelCase							:float				)	->				float:
     '''simple docstring'''


     if side_length < 0:
          raise ValueError('''surface_area_cube() only accepts non-negative values'''				)
     return 6 * side_length**2

def      UpperCAmelCase_    (    _UpperCAmelCase							:float  ,						_UpperCAmelCase							:float  ,						_UpperCAmelCase							:float				)	->				float:
     '''simple docstring'''


     if length < 0 or breadth < 0 or height < 0:
          raise ValueError('''surface_area_cuboid() only accepts non-negative values'''				)
     return 2 * ((length * breadth) + (breadth * height) + (length * height))

def      UpperCAmelCase_    (    _UpperCAmelCase							:float				)	->				float:
     '''simple docstring'''


     if radius < 0:
          raise ValueError('''surface_area_sphere() only accepts non-negative values'''				)
     return 4 * pi * radius**2

def      UpperCAmelCase_    (    _UpperCAmelCase							:float				)	->				float:
     '''simple docstring'''


     if radius < 0:
          raise ValueError('''surface_area_hemisphere() only accepts non-negative values'''				)
     return 3 * pi * radius**2

def      UpperCAmelCase_    (    _UpperCAmelCase							:float  ,						_UpperCAmelCase							:float				)	->				float:
     '''simple docstring'''


     if radius < 0 or height < 0:
          raise ValueError('''surface_area_cone() only accepts non-negative values'''				)
     return pi * radius * (radius + (height**2 + radius**2) ** 0.5)

def      UpperCAmelCase_    (    _UpperCAmelCase							:float  ,						_UpperCAmelCase							:float  ,						_UpperCAmelCase							:float				)	->				float:
     '''simple docstring'''


     if radius_a < 0 or radius_a < 0 or height < 0:
          raise ValueError(
              '''surface_area_conical_frustum() only accepts non-negative values'''				)
     A_          =       (height**2 + (radius_a - radius_a) ** 2) ** 0.5
     return pi * ((slant_height * (radius_a + radius_a)) + radius_a**2 + radius_a**2)

def      UpperCAmelCase_    (    _UpperCAmelCase							:float  ,						_UpperCAmelCase							:float				)	->				float:
     '''simple docstring'''


     if radius < 0 or height < 0:
          raise ValueError('''surface_area_cylinder() only accepts non-negative values'''				)
     return 2 * pi * radius * (height + radius)

def      UpperCAmelCase_    (    _UpperCAmelCase							:float  ,						_UpperCAmelCase							:float				)	->				float:
     '''simple docstring'''


     if torus_radius < 0 or tube_radius < 0:
          raise ValueError('''surface_area_torus() only accepts non-negative values'''				)
     if torus_radius < tube_radius:
          raise ValueError(
              '''surface_area_torus() does not support spindle or self intersecting tori'''				)
     return 4 * pow(_UpperCAmelCase  ,						2				) * torus_radius * tube_radius

def      UpperCAmelCase_    (    _UpperCAmelCase							:float  ,						_UpperCAmelCase							:float				)	->				float:
     '''simple docstring'''


     if length < 0 or width < 0:
          raise ValueError('''area_rectangle() only accepts non-negative values'''				)
     return length * width

def      UpperCAmelCase_    (    _UpperCAmelCase							:float				)	->				float:
     '''simple docstring'''


     if side_length < 0:
          raise ValueError('''area_square() only accepts non-negative values'''				)
     return side_length**2

def      UpperCAmelCase_    (    _UpperCAmelCase							:float  ,						_UpperCAmelCase							:float				)	->				float:
     '''simple docstring'''


     if base < 0 or height < 0:
          raise ValueError('''area_triangle() only accepts non-negative values'''				)
     return (base * height) / 2

def      UpperCAmelCase_    (    _UpperCAmelCase							:float  ,						_UpperCAmelCase							:float  ,						_UpperCAmelCase							:float				)	->				float:
     '''simple docstring'''


     if sidea < 0 or sidea < 0 or sidea < 0:
          raise ValueError('''area_triangle_three_sides() only accepts non-negative values'''				)
     elif sidea + sidea < sidea or sidea + sidea < sidea or sidea + sidea < sidea:
          raise ValueError('''Given three sides do not form a triangle'''				)
     A_          =       (sidea + sidea + sidea) / 2
     A_          =       sqrt(
         semi_perimeter
         * (semi_perimeter - sidea)
         * (semi_perimeter - sidea)
         * (semi_perimeter - sidea)				)
     return area

def      UpperCAmelCase_    (    _UpperCAmelCase							:float  ,						_UpperCAmelCase							:float				)	->				float:
     '''simple docstring'''


     if base < 0 or height < 0:
          raise ValueError('''area_parallelogram() only accepts non-negative values'''				)
     return base * height

def      UpperCAmelCase_    (    _UpperCAmelCase							:float  ,						_UpperCAmelCase							:float  ,						_UpperCAmelCase							:float				)	->				float:
     '''simple docstring'''


     if basea < 0 or basea < 0 or height < 0:
          raise ValueError('''area_trapezium() only accepts non-negative values'''				)
     return 1 / 2 * (basea + basea) * height

def      UpperCAmelCase_    (    _UpperCAmelCase							:float				)	->				float:
     '''simple docstring'''


     if radius < 0:
          raise ValueError('''area_circle() only accepts non-negative values'''				)
     return pi * radius**2

def      UpperCAmelCase_    (    _UpperCAmelCase							:float  ,						_UpperCAmelCase							:float				)	->				float:
     '''simple docstring'''


     if radius_x < 0 or radius_y < 0:
          raise ValueError('''area_ellipse() only accepts non-negative values'''				)
     return pi * radius_x * radius_y

def      UpperCAmelCase_    (    _UpperCAmelCase							:float  ,						_UpperCAmelCase							:float				)	->				float:
     '''simple docstring'''


     if diagonal_a < 0 or diagonal_a < 0:
          raise ValueError('''area_rhombus() only accepts non-negative values'''				)
     return 1 / 2 * diagonal_a * diagonal_a

def      UpperCAmelCase_    (    _UpperCAmelCase							:int  ,						_UpperCAmelCase							:float				)	->				float:
     '''simple docstring'''


     if not isinstance(_UpperCAmelCase  ,						_UpperCAmelCase				) or sides < 3:
          raise ValueError(
              '''area_reg_polygon() only accepts integers greater than or \
equal to three as number of sides'''				)
     elif length < 0:
          raise ValueError(
              '''area_reg_polygon() only accepts non-negative values as \
length of a side'''				)
     return (sides * length**2) / (4 * tan(pi / sides				))
     return (sides * length**2) / (4 * tan(pi / sides				))


if __name__ == "__main__":
      import doctest

      doctest.testmod(verbose=True)  # verbose so we can see methods missing tests

      print('[DEMO] Areas of various geometric shapes: \n')
      print(f'''Rectangle: {area_rectangle(10, 20) = }''')
      print(f'''Square: {area_square(10) = }''')
      print(f'''Triangle: {area_triangle(10, 10) = }''')
      print(f'''Triangle: {area_triangle_three_sides(5, 12, 13) = }''')
      print(f'''Parallelogram: {area_parallelogram(10, 20) = }''')
      print(f'''Rhombus: {area_rhombus(10, 20) = }''')
      print(f'''Trapezium: {area_trapezium(10, 20, 30) = }''')
      print(f'''Circle: {area_circle(20) = }''')
      print(f'''Ellipse: {area_ellipse(10, 20) = }''')
      print('\nSurface Areas of various geometric shapes: \n')
      print(f'''Cube: {surface_area_cube(20) = }''')
      print(f'''Cuboid: {surface_area_cuboid(10, 20, 30) = }''')
      print(f'''Sphere: {surface_area_sphere(20) = }''')
      print(f'''Hemisphere: {surface_area_hemisphere(20) = }''')
      print(f'''Cone: {surface_area_cone(10, 20) = }''')
      print(f'''Conical Frustum: {surface_area_conical_frustum(10, 20, 30) = }''')
      print(f'''Cylinder: {surface_area_cylinder(10, 20) = }''')
      print(f'''Torus: {surface_area_torus(20, 10) = }''')
      print(f'''Equilateral Triangle: {area_reg_polygon(3, 10) = }''')
      print(f'''Square: {area_reg_polygon(4, 10) = }''')
      print(f'''Reqular Pentagon: {area_reg_polygon(5, 10) = }''')



