text: import pkgutil
  import csv
  from warnings import warn
  
  import numpy as np
  
  
  def avail_approaches(pkg):
      """Create list of available modules.
  
      Parameters
      ----------
      pkg : module
          module to inspect
  
      Returns
      ---------
      method : list
          A list of available submodules
      """
      methods = [modname for importer, modname, ispkg in
                 pkgutil.walk_packages(path=pkg.__path__)
                 if modname not in
                 ['common_args', 'directions', 'sobol_sequence']
                 and 'test' not in modname]
  
      return methods
  
  
  def read_param_file(filename, delimiter=None):
      """Unpacks a parameter file into a dictionary
  
      Reads a parameter file of format::
  
          Param1,0,1,Group1,dist1
          Param2,0,1,Group2,dist2
          Param3,0,1,Group3,dist3
  
      (Group and Dist columns are optional)
  
      Returns a dictionary containing:
          - names - the names of the parameters
          - bounds - a list of lists of lower and upper bounds
          - num_vars - a scalar indicating the number of variables
                       (the length of names)
          - groups - a list of group names (strings) for each variable
          - dists - a list of distributions for the problem,
                      None if not specified or all uniform
  
      Parameters
      ----------
      filename : str
          The path to the parameter file
      delimiter : str, default=None
          The delimiter used in the file to distinguish between columns
  
      """
      names = []
      bounds = []
      groups = []
      dists = []
      num_vars = 0
      fieldnames = ['name', 'lower_bound', 'upper_bound', 'group', 'dist']
  
      with open(filename, 'r') as csvfile:
          dialect = csv.Sniffer().sniff(csvfile.read(1024), delimiters=delimiter)
          csvfile.seek(0)
          reader = csv.DictReader(
              csvfile, fieldnames=fieldnames, dialect=dialect)
          for row in reader:
              if row['name'].strip().startswith('#'):
                  pass
              else:
                  num_vars += 1
                  names.append(row['name'])
                  bounds.append(
                      [float(row['lower_bound']), float(row['upper_bound'])])
  
                  # If the fourth column does not contain a group name, use
                  # the parameter name
                  if row['group'] is None:
                      groups.append(row['name'])
                  elif row['group'] == 'NA':
                      groups.append(row['name'])
                  else:
                      groups.append(row['group'])
  
                  # If the fifth column does not contain a distribution
                  # use uniform
                  if row['dist'] is None:
                      dists.append('unif')
                  else:
                      dists.append(row['dist'])
  
      if groups == names:
          groups = None
      elif len(set(groups)) == 1:
          raise ValueError("""Only one group defined, results will not be
              meaningful""")
  
      # setting dists to none if all are uniform
      # because non-uniform scaling is not needed
      if all([d == 'unif' for d in dists]):
          dists = None
  
      return {'names': names, 'bounds': bounds, 'num_vars': num_vars,
              'groups': groups, 'dists': dists}
  
  
  def _check_groups(problem):
      """Check if there is more than 1 group."""
      groups = problem.get('groups')
      if not groups:
          return False
  
      if len(set(groups)) == 1:
          return False
      return groups
  
  
  def _check_bounds(bounds):
      """Check user supplied distribution bounds for validity.
  
      Parameters
      ----------
      problem : dict
          The problem definition
  
      Returns
      -------
      tuple : containing upper and lower bounds
      """
      b = np.array(bounds)
  
      lower_bounds = b[:, 0]
      upper_bounds = b[:, 1]
  
      if np.any(lower_bounds >= upper_bounds):
          raise ValueError("Bounds are not legal")
  
      return lower_bounds, upper_bounds