<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def flat_map(self, column_names, fn, column_types='auto', seed=None):
 """ Map each row of the SFrame to multiple rows in a new SFrame via a function. will be a single row in the new output, and the collection of these rows within the outer list make up the data for the output SFrame. All rows must have the same length and the same order of types to make sure the result columns are homogeneously typed. For example, if the first element emitted into in the outer list by `fn` is [43, 2.3, 'string'], then all other elements emitted into the outer list must be a list with three elements, where the first is an int, second is a float, and third is a string. If column_types is not specified, the first 10 rows of the SFrame are used to determine the column types of the returned sframe. Parameters column_names : list[str] The column names for the returned SFrame. fn : function The function that maps each of the sframe row into multiple rows, length and order of types. column_types : list[type], optional The column types of the output SFrame. Default value will be automatically inferred by running `fn` on the first 10 rows of the input. If the types cannot be inferred from the first 10 rows, an error is raised. seed : int, optional Used as the seed if a random number generator is included in `fn`. Returns ------- out : SFrame A new SFrame containing the results of the flat_map of the original SFrame. Examples --------- Repeat each row according to the value in the 'number' column. +--------+--------+ | number | letter | +--------+--------+ | 1 | a | | 2 | b | | 2 | b | | 3 | c | | 3 | c | | 3 | c | +--------+--------+ [6 rows x 2 columns] """

        assert callable(fn), "Input must be callable"
        if seed is None:
            seed = abs(hash("%0.20f" % time.time())) % (2 ** 31)


        # determine the column_types
        if column_types == 'auto':
            types = set()
            sample = self[0:10]
            results = [fn(row) for row in sample]

            for rows in results:
                if type(rows) is not list:
                    raise TypeError("Output type of the lambda function must be a list of lists")

                # note: this skips empty lists
                for row in rows:
                    if type(row) is not list:
                        raise TypeError("Output type of the lambda function must be a list of lists")
                    types.add(tuple([type(v) for v in row]))

            if len(types) == 0:
                raise TypeError(
                    "Could not infer output column types from the first ten rows " +\
                    "of the SFrame. Please use the 'column_types' parameter to " +\
                    "set the types.")

            if len(types) > 1:
                raise TypeError("Mapped rows must have the same length and types")

            column_types = list(types.pop())

        assert type(column_types) is list, "'column_types' must be a list."
        assert len(column_types) == len(column_names), "Number of output columns must match the size of column names"
        with cython_context():
            return SFrame(_proxy=self.__proxy__.flat_map(fn, column_names, column_types, seed))