code: def params(self):
          
          comb_sizes = []
          comb_keys = []
          for key,val in self.comb_params.items():
              comb_keys.append(key)
              comb_sizes.append(len(val))
          # length of first values array, since lengths should match for sets of
          # jointly varying parameters
          joint_sizes = [len(next(iter(jlist.values()))) for jlist in self.joint_params]
          all_sizes = comb_sizes + joint_sizes
          total_combinations = reduce(operator.mul, all_sizes, 1)
          for i in range(total_combinations):
              sub = np.unravel_index(i, all_sizes)
              params = {}
              # get the comb_params
              for j in range(len(comb_sizes)):
                  key = comb_keys[j]
                  val_arr = self.comb_params[key]
                  params[key] = val_arr[sub[j]]
              # get the joint_params
              for j in range(len(joint_sizes)):
                  subj = j + len(comb_sizes)
                  for key,val_arr in self.joint_params[j].items():
                      params[key] = val_arr[sub[subj]]
              # how we have one parameter set, check how many times to repeat it
              num_repeats = self.default_repeats
              for func in self.count_funcs:
                  c = func(params)
                  if c:
                      num_repeats = c
              for i in range(num_repeats):
                  yield params
docs: A generator that iterates through all parameters requested the
          correct number of times each. Returns them as a dict with form
          {'param_name': param_value, ... } for use as f(**params).