<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def to_perseus(df, path_or_file, main_columns=None, separator=separator, convert_bool_to_category=True, numerical_annotation_rows = set([])):
 """ Save pd.DataFrame to Perseus text format. :param df: pd.DataFrame. :param path_or_file: File name or file-like object. :param main_columns: Main columns. Will be infered if set to None. All numeric columns up-until the first non-numeric column are considered main columns. :param separator: For separating fields, default='\t'. :param covert_bool_to_category: Convert bool columns of True/False to category columns '+'/'', default=True. :param numerical_annotation_rows: Set of column names to be interpreted as numerical annotation rows, default=set([]). """

    _df = df.copy()
    if not _df.columns.name:
        _df.columns.name = 'Column Name'
    column_names = _df.columns.get_level_values('Column Name')
    annotations = {}
    main_columns = _infer_main_columns(_df) if main_columns is None else main_columns
    annotations['Type'] = ['E' if column_names[i] in main_columns else dtype_to_perseus(dtype)
            for i, dtype in enumerate(_df.dtypes)]
    # detect multi-numeric columns
    for i, column in enumerate(_df.columns):
        valid_values = [value for value in _df[column] if value is not None]
        if len(valid_values) > 0 and all(type(value) is list for value in valid_values):
            annotations['Type'][i] = 'M'
            _df[column] = _df[column].apply(lambda xs: ';'.join(str(x) for x in xs))
    if convert_bool_to_category:
        for i, column in enumerate(_df.columns):
            if _df.dtypes[i] is np.dtype('bool'):
                values = _df[column].values
                _df[column][values] = '+'
                _df[column][~values] = ''
    annotation_row_names = set(_df.columns.names) - {'Column Name'}
    for name in annotation_row_names:
        annotation_type = 'N' if name in numerical_annotation_rows else 'C'
        annotations['{}:{}'.format(annotation_type, name)] = _df.columns.get_level_values(name)
    with PathOrFile(path_or_file, 'w') as f:
        f.write(separator.join(column_names) + '\n')
        for name, values in annotations.items():
            f.write('#!{{{name}}}{values}\n'.format(name=name, values=separator.join([str(x) for x in values])))
        _df.to_csv(f, header=None, index=False, sep=separator)