<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def analyze(problem, X, Y, second_order=False, print_to_console=False, seed=None):
 """Perform a fractional factorial analysis Returns a dictionary with keys 'ME' (main effect) and 'IE' (interaction effect). The techniques bulks out the number of parameters with dummy parameters to the nearest 2**n. Any results involving dummy parameters could indicate a problem with the model runs. Arguments --------- problem: dict The problem definition X: numpy.matrix The NumPy matrix containing the model inputs Y: numpy.array The NumPy array containing the model outputs second_order: bool, default=False Include interaction effects print_to_console: bool, default=False Print results directly to console Returns ------- Si: dict A dictionary of sensitivity indices, including main effects ``ME``, and interaction effects ``IE`` (if ``second_order`` is True) Examples -------- """

    if seed:
        np.random.seed(seed)

    problem = extend_bounds(problem)
    num_vars = problem['num_vars']

    X = generate_contrast(problem)

    main_effect = (1. / (2 * num_vars)) * np.dot(Y, X)

    Si = ResultDict((k, [None] * num_vars)
                    for k in ['names', 'ME'])
    Si['ME'] = main_effect
    Si['names'] = problem['names']

    if print_to_console:
        print("Parameter ME")
        for j in range(num_vars):
            print("%s %f" % (problem['names'][j], Si['ME'][j]))

    if second_order:
        interaction_names, interaction_effects = interactions(problem,
                                                              Y,
                                                              print_to_console)
        Si['interaction_names'] = interaction_names
        Si['IE'] = interaction_effects

    Si.to_df = MethodType(to_df, Si)

    return Si