Generate the Parameter Configuration Space (PCS) which defines the 
    legal ranges of the parameters to be optimized and their default values.
    
    Generally, the format is:
    # parameter_name categorical {value_1, ..., value_N} [default value]
    # parameter_name ordinal {value_1, ..., value_N} [default value]
    # parameter_name integer [min_value, max_value] [default value]
    # parameter_name integer [min_value, max_value] [default value] log
    # parameter_name real [min_value, max_value] [default value]
    # parameter_name real [min_value, max_value] [default value] log
    
    Reference: https://automl.github.io/SMAC3/stable/options.html

    Parameters
    ----------
    nni_search_space_content: search_space
        The search space in this experiment in nni
    
    Returns
    -------
    Parameter Configuration Space (PCS)
        the legal ranges of the parameters to be optimized and their default values

    Raises
    ------
    RuntimeError
        unsupported type or value error or incorrect search space

def generate_pcs(nni_search_space_content):
    """Generate the Parameter Configuration Space (PCS) which defines the 
    legal ranges of the parameters to be optimized and their default values.
    
    Generally, the format is:
    # parameter_name categorical {value_1, ..., value_N} [default value]
    # parameter_name ordinal {value_1, ..., value_N} [default value]
    # parameter_name integer [min_value, max_value] [default value]
    # parameter_name integer [min_value, max_value] [default value] log
    # parameter_name real [min_value, max_value] [default value]
    # parameter_name real [min_value, max_value] [default value] log
    
    Reference: https://automl.github.io/SMAC3/stable/options.html

    Parameters
    ----------
    nni_search_space_content: search_space
        The search space in this experiment in nni
    
    Returns
    -------
    Parameter Configuration Space (PCS)
        the legal ranges of the parameters to be optimized and their default values

    Raises
    ------
    RuntimeError
        unsupported type or value error or incorrect search space
    """
    categorical_dict = {}
    search_space = nni_search_space_content
    with open('param_config_space.pcs', 'w') as pcs_fd:
        if isinstance(search_space, dict):
            for key in search_space.keys():
                if isinstance(search_space[key], dict):
                    try:
                        if search_space[key]['_type'] == 'choice':
                            choice_len = len(search_space[key]['_value'])
                            pcs_fd.write('%s categorical {%s} [%s]\n' % (
                                key, 
                                json.dumps(list(range(choice_len)))[1:-1], 
                                json.dumps(0)))
                            if key in categorical_dict:
                                raise RuntimeError('%s has already existed, please make sure search space has no duplicate key.' % key)
                            categorical_dict[key] = search_space[key]['_value']
                        elif search_space[key]['_type'] == 'randint':
                            # TODO: support lower bound in randint
                            pcs_fd.write('%s integer [0, %d] [%d]\n' % (
                                key, 
                                search_space[key]['_value'][0], 
                                search_space[key]['_value'][0]))
                        elif search_space[key]['_type'] == 'uniform':
                            pcs_fd.write('%s real %s [%s]\n' % (
                                key, 
                                json.dumps(search_space[key]['_value']),
                                json.dumps(search_space[key]['_value'][0])))
                        elif search_space[key]['_type'] == 'loguniform':
                            # use np.round here to ensure that the rounded defaut value is in the range, which will be rounded in configure_space package
                            search_space[key]['_value'] = list(np.round(np.log(search_space[key]['_value']), 10))
                            pcs_fd.write('%s real %s [%s]\n' % (
                                key, 
                                json.dumps(search_space[key]['_value']),
                                json.dumps(search_space[key]['_value'][0])))
                        elif search_space[key]['_type'] == 'quniform' \
                            and search_space[key]['_value'][2] == 1:
                            pcs_fd.write('%s integer [%d, %d] [%d]\n' % (
                                key,
                                search_space[key]['_value'][0],
                                search_space[key]['_value'][1],
                                search_space[key]['_value'][0]))
                        else:
                            raise RuntimeError('unsupported _type %s' % search_space[key]['_type'])
                    except:
                        raise RuntimeError('_type or _value error.')
        else:
            raise RuntimeError('incorrect search space.')
        return categorical_dict
    return None