code: def find_all_coin_change_ways(
      coins: List,
      amount: int,
      allowed_deviation: int = 0,
      max_solutions=50,
  ):
      def coin_change(
          unique_coins: List, amount: int, tmp_ret: Tuple = ()
      ):
          """Search in ascending order."""
          if (
              len(unique_coins) == 0
              or len(all_combinations) > max_solutions
          ):
              return
          biggest_coin, rest_coins = unique_coins[0], unique_coins[1:]
          if allowed_deviation > 0:
              num = math.ceil(amount / biggest_coin)
          else:
              num = amount // biggest_coin
          for i in range(1 + num):
              if i > coin_num[biggest_coin]:
                  break
              remainder = amount - biggest_coin * i
              if abs(remainder) <= allowed_deviation:
                  new_combo = tmp_ret + (biggest_coin,) * i
                  if allowed_deviation > 0:
                      if (
                          len(all_combinations) == 0
                          or new_combo != all_combinations[-1]
                      ):
                          all_combinations.append(new_combo)
                      coin_change(
                          rest_coins,
                          remainder,
                          tmp_ret + (biggest_coin,) * i,
                      )
                  else:
                      all_combinations.append(new_combo)
                      break
              elif remainder > 0:
                  coin_change(
                      rest_coins,
                      remainder,
                      tmp_ret + (biggest_coin,) * i,
                  )
              else:
                  break
  
      def coin_change_v2(
          unique_coins: List, amount: int, tmp_ret: Tuple = ()
      ):
          """Search in descending order."""
          if (
              len(unique_coins) == 0
              or len(all_combinations) > max_solutions
          ):
              return
          biggest_coin, rest_coins = unique_coins[0], unique_coins[1:]
          if allowed_deviation > 0:
              num = min(
                  coin_num[biggest_coin],
                  math.ceil(amount / biggest_coin),
              )
          else:
              num = min(coin_num[biggest_coin], amount // biggest_coin)
          for i in range(num, -1, -1):
              remainder = amount - biggest_coin * i
              if abs(remainder) <= allowed_deviation:
                  new_combo = tmp_ret + (biggest_coin,) * i
                  if allowed_deviation > 0:
                      if (
                          len(all_combinations) == 0
                          or new_combo != all_combinations[-1]
                      ):
                          all_combinations.append(new_combo)
                      length = len(all_combinations)
                      coin_change_v2(
                          rest_coins,
                          remainder,
                          tmp_ret + (biggest_coin,) * i,
                      )
                      if len(all_combinations) == length:
                          break
                  else:
                      all_combinations.append(new_combo)
              elif remainder > 0:
                  coin_change_v2(
                      rest_coins,
                      remainder,
                      tmp_ret + (biggest_coin,) * i,
                  )
  
      coin_num = Counter(coins)
      unique_coins = sorted(
          coin_num.keys(), reverse=True
      )  # in descending order
      all_combinations = []
      if unique_coins[0] * coin_num[unique_coins[0]] < amount:
          coin_change_v2(unique_coins, amount)
      else:
          coin_change(unique_coins, amount)
      return all_combinations
  
file_path: espnet/egs2/aishell4/enh1/local/split_train_dev.py
imports: import math
  import random
  from collections import Counter, defaultdict
  from fractions import Fraction
  from pathlib import Path
  from typing import List, Tuple
label_desc: Use image node_id 4 for calling a global function with example usage: find_all_coin_change_ways(coins, amount, allowed_deviation, max_solutions) and returns: all_combinations