示例#1
0
def run_conf(scenario_instance_factory, index_list, num_scenarios_for_solution,
             num_scenarios_per_sample, full_scenario_tree, xhat_ph, options):

    if options.MRP_directory_basename is None:
        AllInOne = True

    sense = xhat_ph._scenario_tree._scenarios[0]._objective_sense

    # in order to handle the case of scenarios that are not equally
    # likely, we will split the expectations for Gsupk
    # BUT we are going to assume that the groups themselves are
    # equally likely and just scale by n_g and n_g-1 for Gbar and VarG

    # really not always needed...
    # http://www.eecs.berkeley.edu/~mhoemmen/cs194/Tutorials/variance.pdf
    g_supk_of_xhat = []
    g_bar = 0
    sum_xstar_obj_given_xhat = 0
    n_g = options.n_g

    for k in range(1, n_g + 1):

        gk_ph = None
        try:

            if AllInOne:

                start_index = num_scenarios_for_solution + \
                              (k-1)*num_scenarios_per_sample
                stop_index = start_index + num_scenarios_per_sample

                print("")
                print("Computing statistics for sample k=" + str(k) + ".")
                if options.verbose:
                    print("Bundle start index=" + str(start_index) +
                          ", stop index=" + str(stop_index) + ".")

                # compute this xstar solution for the EF associated with
                # sample k.

                print("Loading scenario instances and initializing "
                      "scenario tree for xstar scenario bundle.")

                gk_ph = ph_for_bundle(start_index, stop_index,
                                      scenario_instance_factory,
                                      full_scenario_tree, index_list, options)

            else:

                options.instance_directory = \
                    options.MRP_directory_basename+str(k)

                gk_ph = PHFromScratch(options)

            print("Creating the xstar extensive form.")
            print("")
            print("Composite scenarios:")
            for scenario in gk_ph._scenario_tree._scenarios:
                print(scenario._name)
            print("")
            gk_ef = ExtensiveFormAlgorithm(gk_ph,
                                           options._ef_options,
                                           prefix="ef_")
            gk_ef.build_ef()
            print("Solving the xstar extensive form.")
            # Instance preprocessing is managed within the
            # ph object automatically when required for a
            # solve. Since we are solving the instances
            # outside of the ph object, we will inform it
            # that it should complete the instance
            # preprocessing early
            gk_ph._preprocess_scenario_instances()
            gk_ef.solve(io_options=\
                        {'output_fixed_variable_bounds':
                         options.write_fixed_variables})
            xstar_obj = gk_ef.objective
            # assuming this is the absolute gap
            xstar_obj_gap = gk_ef.gap
            """
            gk_ef = create_ef_instance(gk_ph._scenario_tree,
                                       generate_weighted_cvar=options.generate_weighted_cvar,
                                       cvar_weight=options.cvar_weight,
                                       risk_alpha=options.risk_alpha)
            print("Solving the xstar extensive form.")

            # Instance preprocessing is managed within the ph object
            # automatically when required for a solve. Since we are
            # solving the instances outside of the ph object, we will
            # inform it that it should complete the instance preprocessing
            # early
            gk_ph._preprocess_scenario_instances()

            ef_results = solve_ef(gk_ef, options)

            # as in the computation of xhat, the following is required to form a
            # solution to the extensive form in the scenario tree itself.
            gk_ph._scenario_tree.pullScenarioSolutionsFromInstances()
            gk_ph._scenario_tree.snapshotSolutionFromScenarios()

            # extract the objective function value corresponding to the
            # xstar solution, along with any gap information.

            xstar_obj = gk_ph._scenario_tree.findRootNode().computeExpectedNodeCost()
            # assuming this is the absolute gap
            xstar_obj_gap = gk_ef.solutions[0].gap# ef_results.solution(0).gap
            """

            print("Sample extensive form objective value=" + str(xstar_obj))

            # CVARHACK: if CPLEX barfed, keep trucking and bury our head
            # in the sand.
            if type(xstar_obj_gap) is UndefinedData:
                xstar_obj_bound = xstar_obj
                #EW#print("xstar_obj_bound= "+str(xstar_obj_bound))
            else:
                if sense == minimize:
                    xstar_obj_bound = xstar_obj - xstar_obj_gap
                else:
                    xstar_obj_bound = xstar_obj + xstar_obj_gap
                #EW#print("xstar_obj_bound= "+str(xstar_obj_bound))
                #EW#print("xstar_obj = "+str(xstar_obj))
                #EW#print("xstar_obj_gap = "+str(xstar_obj_gap))
            # TBD: ADD VERBOSE OUTPUT HERE

            # to get f(xhat) for this sample, fix the first-stage
            # variables and re-solve the extensive form.  note that the
            # fixing yields side-effects on the original gk_ef, but that
            # is fine as it isn't used after this point.
            print("Solving the extensive form given the xhat solution.")
            #xhat = pyomo.pysp.phboundbase.ExtractInternalNodeSolutionsforInner(xhat_ph)
            #
            # fix the first stage variables
            #
            gk_root_node = gk_ph._scenario_tree.findRootNode()
            #root_xhat = xhat[gk_root_node._name]
            root_xhat = xhat_ph._scenario_tree.findRootNode()._solution
            for variable_id in gk_root_node._standard_variable_ids:
                gk_root_node.fix_variable(variable_id, root_xhat[variable_id])

            # Push fixed variable statuses on instances (or
            # transmit to the phsolverservers), since we are not
            # calling the solve method on the ph object, we
            # need to do this manually
            gk_ph._push_fix_queue_to_instances()
            gk_ph._preprocess_scenario_instances()

            gk_ef.solve(io_options=\
                        {'output_fixed_variable_bounds':
                         options.write_fixed_variables})
            #ef_results = solve_ef(gk_ef, options)

            # we don't need the solution - just the objective value.
            #objective_name = "MASTER"
            #objective = gk_ef.find_component(objective_name)
            xstar_obj_given_xhat = gk_ef.objective

            print("Sample extensive form objective value given xhat=" +
                  str(xstar_obj_given_xhat))

            #g_supk_of_xhat.append(xstar_obj_given_xhat - xstar_obj_bound)
            if sense == minimize:
                g_supk_of_xhat.append(xstar_obj_given_xhat - xstar_obj_bound)
            else:
                g_supk_of_xhat.append(-xstar_obj_given_xhat + xstar_obj_bound)
            g_bar += g_supk_of_xhat[k - 1]
            sum_xstar_obj_given_xhat += xstar_obj_given_xhat

        finally:

            if gk_ph is not None:

                # we are using the PHCleanup function for
                # convenience, but we need to prevent it
                # from shutting down the scenario_instance_factory
                # as it is managed outside this function
                if gk_ph._scenario_tree._scenario_instance_factory is \
                   scenario_instance_factory:
                    gk_ph._scenario_tree._scenario_instance_factory = None
                PHCleanup(gk_ph)

    g_bar /= n_g
    # second pass for variance calculation (because we like storing
    # the g_supk)
    g_var = 0.0
    for k in range(0, n_g):
        print("g_supk_of_xhat[%d]=%12.6f" % (k + 1, g_supk_of_xhat[k]))
        g_var = g_var + (g_supk_of_xhat[k] - g_bar) * \
                (g_supk_of_xhat[k] - g_bar)
    if n_g != 1:
        # sample var
        g_var = g_var / (n_g - 1)
    print("")
    print("Raw results:")
    print("g_bar= " + str(g_bar))
    print("g_stddev= " + str(math.sqrt(g_var)))
    print("Average f(xhat)= " + str(sum_xstar_obj_given_xhat / n_g))

    if n_g in t_table_values:
        print("")
        print("Results summary:")
        t_table_entries = t_table_values[n_g]
        for key in sorted(iterkeys(t_table_entries)):
            print("Confidence interval width for alpha="+str(key)
                  +" is "+str(g_bar + (t_table_entries[key] * \
                                       math.sqrt(g_var) / \
                                       math.sqrt(n_g))))
    else:
        print(
            "No built-in t-table entries for " + str(n_g) +
            " degrees of freedom - cannot calculate confidence interval width")

    if options.write_xhat_solution:
        print("")
        print("xhat solution:")
        scenario_tree = xhat_ph._scenario_tree
        first_stage = scenario_tree._stages[0]
        root_node = first_stage._tree_nodes[0]
        for key, val in iteritems(root_node._solutions):
            for idx in val:
                if val[idx] != 0.0:
                    print("%s %s %s" % (str(key), str(idx), str(val[idx]())))

    scenario_count = len(full_scenario_tree._stages[-1]._tree_nodes)
    if options.append_file is not None:
        output_file = open(options.append_file, "a")
        output_file.write("\ninstancedirectory, " +
                          str(options.instance_directory) + ", seed, " +
                          str(options.random_seed) + ", N, " +
                          str(scenario_count) + ", hatn, " +
                          str(num_scenarios_for_solution) + ", n_g, " +
                          str(options.n_g) + ", Eoffofxhat, " +
                          str(sum_xstar_obj_given_xhat / n_g) + ", gbar, " +
                          str(g_bar) + ", sg, " + str(math.sqrt(g_var)) +
                          ", objforxhat, " + str(xhat_obj) + ", n," +
                          str(num_scenarios_per_sample))

        if n_g in t_table_values:
            t_table_entries = t_table_values[n_g]
            for key in sorted(iterkeys(t_table_entries)):
                output_file.write(" , alpha="+str(key)+" , "
                                  +str(g_bar + (t_table_entries[key] * \
                                                math.sqrt(g_var) / \
                                                math.sqrt(n_g))))

        if options.write_xhat_solution:
            output_file.write(" , ")
            scenario_tree = xhat_ph._scenario_tree
            first_stage = scenario_tree._stages[0]
            root_node = first_stage._tree_nodes[0]
            for key, val in iteritems(root_node._solutions):
                for idx in val:
                    if val[idx] != 0.0:
                        output_file.write(
                            "%s %s %s" % (str(key), str(idx), str(val[idx]())))
        output_file.close()
        print("")
        print("Results summary appended to file=" + options.append_file)

    xhat_ph.release_components()
示例#2
0
def run_conf(
    scenario_instance_factory,
    index_list,
    num_scenarios_for_solution,
    num_scenarios_per_sample,
    full_scenario_tree,
    xhat_ph,
    options,
):

    if options.MRP_directory_basename is None:
        AllInOne = True

    sense = xhat_ph._scenario_tree._scenarios[0]._objective_sense

    # in order to handle the case of scenarios that are not equally
    # likely, we will split the expectations for Gsupk
    # BUT we are going to assume that the groups themselves are
    # equally likely and just scale by n_g and n_g-1 for Gbar and VarG

    # really not always needed...
    # http://www.eecs.berkeley.edu/~mhoemmen/cs194/Tutorials/variance.pdf
    g_supk_of_xhat = []
    g_bar = 0
    sum_xstar_obj_given_xhat = 0
    n_g = options.n_g

    for k in range(1, n_g + 1):

        gk_ph = None
        try:

            if AllInOne:

                start_index = num_scenarios_for_solution + (k - 1) * num_scenarios_per_sample
                stop_index = start_index + num_scenarios_per_sample

                print("")
                print("Computing statistics for sample k=" + str(k) + ".")
                if options.verbose:
                    print("Bundle start index=" + str(start_index) + ", stop index=" + str(stop_index) + ".")

                # compute this xstar solution for the EF associated with
                # sample k.

                print("Loading scenario instances and initializing " "scenario tree for xstar scenario bundle.")

                gk_ph = ph_for_bundle(
                    start_index, stop_index, scenario_instance_factory, full_scenario_tree, index_list, options
                )

            else:

                options.instance_directory = options.MRP_directory_basename + str(k)

                gk_ph = PHFromScratch(options)

            print("Creating the xstar extensive form.")
            print("")
            print("Composite scenarios:")
            for scenario in gk_ph._scenario_tree._scenarios:
                print(scenario._name)
            print("")
            gk_ef = ExtensiveFormAlgorithm(gk_ph, options._ef_options, prefix="ef_")
            gk_ef.build_ef()
            print("Solving the xstar extensive form.")
            # Instance preprocessing is managed within the
            # ph object automatically when required for a
            # solve. Since we are solving the instances
            # outside of the ph object, we will inform it
            # that it should complete the instance
            # preprocessing early
            gk_ph._preprocess_scenario_instances()
            gk_ef.solve(io_options={"output_fixed_variable_bounds": options.write_fixed_variables})
            xstar_obj = gk_ef.objective
            # assuming this is the absolute gap
            xstar_obj_gap = gk_ef.gap

            """
            gk_ef = create_ef_instance(gk_ph._scenario_tree,
                                       generate_weighted_cvar=options.generate_weighted_cvar,
                                       cvar_weight=options.cvar_weight,
                                       risk_alpha=options.risk_alpha)
            print("Solving the xstar extensive form.")

            # Instance preprocessing is managed within the ph object
            # automatically when required for a solve. Since we are
            # solving the instances outside of the ph object, we will
            # inform it that it should complete the instance preprocessing
            # early
            gk_ph._preprocess_scenario_instances()

            ef_results = solve_ef(gk_ef, options)

            # as in the computation of xhat, the following is required to form a
            # solution to the extensive form in the scenario tree itself.
            gk_ph._scenario_tree.pullScenarioSolutionsFromInstances()
            gk_ph._scenario_tree.snapshotSolutionFromScenarios()

            # extract the objective function value corresponding to the
            # xstar solution, along with any gap information.

            xstar_obj = gk_ph._scenario_tree.findRootNode().computeExpectedNodeCost()
            # assuming this is the absolute gap
            xstar_obj_gap = gk_ef.solutions[0].gap# ef_results.solution(0).gap
            """

            print("Sample extensive form objective value=" + str(xstar_obj))

            # CVARHACK: if CPLEX barfed, keep trucking and bury our head
            # in the sand.
            if type(xstar_obj_gap) is UndefinedData:
                xstar_obj_bound = xstar_obj
                # EW#print("xstar_obj_bound= "+str(xstar_obj_bound))
            else:
                if sense == minimize:
                    xstar_obj_bound = xstar_obj - xstar_obj_gap
                else:
                    xstar_obj_bound = xstar_obj + xstar_obj_gap
                # EW#print("xstar_obj_bound= "+str(xstar_obj_bound))
                # EW#print("xstar_obj = "+str(xstar_obj))
                # EW#print("xstar_obj_gap = "+str(xstar_obj_gap))
            # TBD: ADD VERBOSE OUTPUT HERE

            # to get f(xhat) for this sample, fix the first-stage
            # variables and re-solve the extensive form.  note that the
            # fixing yields side-effects on the original gk_ef, but that
            # is fine as it isn't used after this point.
            print("Solving the extensive form given the xhat solution.")
            # xhat = pyomo.pysp.phboundbase.ExtractInternalNodeSolutionsforInner(xhat_ph)
            #
            # fix the first stage variables
            #
            gk_root_node = gk_ph._scenario_tree.findRootNode()
            # root_xhat = xhat[gk_root_node._name]
            root_xhat = xhat_ph._scenario_tree.findRootNode()._solution
            for variable_id in gk_root_node._standard_variable_ids:
                gk_root_node.fix_variable(variable_id, root_xhat[variable_id])

            # Push fixed variable statuses on instances (or
            # transmit to the phsolverservers), since we are not
            # calling the solve method on the ph object, we
            # need to do this manually
            gk_ph._push_fix_queue_to_instances()
            gk_ph._preprocess_scenario_instances()

            gk_ef.solve(io_options={"output_fixed_variable_bounds": options.write_fixed_variables})
            # ef_results = solve_ef(gk_ef, options)

            # we don't need the solution - just the objective value.
            # objective_name = "MASTER"
            # objective = gk_ef.find_component(objective_name)
            xstar_obj_given_xhat = gk_ef.objective

            print("Sample extensive form objective value given xhat=" + str(xstar_obj_given_xhat))

            # g_supk_of_xhat.append(xstar_obj_given_xhat - xstar_obj_bound)
            if sense == minimize:
                g_supk_of_xhat.append(xstar_obj_given_xhat - xstar_obj_bound)
            else:
                g_supk_of_xhat.append(-xstar_obj_given_xhat + xstar_obj_bound)
            g_bar += g_supk_of_xhat[k - 1]
            sum_xstar_obj_given_xhat += xstar_obj_given_xhat

        finally:

            if gk_ph is not None:

                # we are using the PHCleanup function for
                # convenience, but we need to prevent it
                # from shutting down the scenario_instance_factory
                # as it is managed outside this function
                if gk_ph._scenario_tree._scenario_instance_factory is scenario_instance_factory:
                    gk_ph._scenario_tree._scenario_instance_factory = None
                PHCleanup(gk_ph)

    g_bar /= n_g
    # second pass for variance calculation (because we like storing
    # the g_supk)
    g_var = 0.0
    for k in range(0, n_g):
        print("g_supk_of_xhat[%d]=%12.6f" % (k + 1, g_supk_of_xhat[k]))
        g_var = g_var + (g_supk_of_xhat[k] - g_bar) * (g_supk_of_xhat[k] - g_bar)
    if n_g != 1:
        # sample var
        g_var = g_var / (n_g - 1)
    print("")
    print("Raw results:")
    print("g_bar= " + str(g_bar))
    print("g_stddev= " + str(math.sqrt(g_var)))
    print("Average f(xhat)= " + str(sum_xstar_obj_given_xhat / n_g))

    if n_g in t_table_values:
        print("")
        print("Results summary:")
        t_table_entries = t_table_values[n_g]
        for key in sorted(iterkeys(t_table_entries)):
            print(
                "Confidence interval width for alpha="
                + str(key)
                + " is "
                + str(g_bar + (t_table_entries[key] * math.sqrt(g_var) / math.sqrt(n_g)))
            )
    else:
        print(
            "No built-in t-table entries for "
            + str(n_g)
            + " degrees of freedom - cannot calculate confidence interval width"
        )

    if options.write_xhat_solution:
        print("")
        print("xhat solution:")
        scenario_tree = xhat_ph._scenario_tree
        first_stage = scenario_tree._stages[0]
        root_node = first_stage._tree_nodes[0]
        for key, val in iteritems(root_node._solutions):
            for idx in val:
                if val[idx] != 0.0:
                    print("%s %s %s" % (str(key), str(idx), str(val[idx]())))

    scenario_count = len(full_scenario_tree._stages[-1]._tree_nodes)
    if options.append_file is not None:
        output_file = open(options.append_file, "a")
        output_file.write(
            "\ninstancedirectory, "
            + str(options.instance_directory)
            + ", seed, "
            + str(options.random_seed)
            + ", N, "
            + str(scenario_count)
            + ", hatn, "
            + str(num_scenarios_for_solution)
            + ", n_g, "
            + str(options.n_g)
            + ", Eoffofxhat, "
            + str(sum_xstar_obj_given_xhat / n_g)
            + ", gbar, "
            + str(g_bar)
            + ", sg, "
            + str(math.sqrt(g_var))
            + ", objforxhat, "
            + str(xhat_obj)
            + ", n,"
            + str(num_scenarios_per_sample)
        )

        if n_g in t_table_values:
            t_table_entries = t_table_values[n_g]
            for key in sorted(iterkeys(t_table_entries)):
                output_file.write(
                    " , alpha="
                    + str(key)
                    + " , "
                    + str(g_bar + (t_table_entries[key] * math.sqrt(g_var) / math.sqrt(n_g)))
                )

        if options.write_xhat_solution:
            output_file.write(" , ")
            scenario_tree = xhat_ph._scenario_tree
            first_stage = scenario_tree._stages[0]
            root_node = first_stage._tree_nodes[0]
            for key, val in iteritems(root_node._solutions):
                for idx in val:
                    if val[idx] != 0.0:
                        output_file.write("%s %s %s" % (str(key), str(idx), str(val[idx]())))
        output_file.close()
        print("")
        print("Results summary appended to file=" + options.append_file)

    xhat_ph.release_components()
示例#3
0
def find_candidate(scenario_instance_factory, index_list,
                   num_scenarios_for_solution, full_scenario_tree, options):

    # create a ph object for finding the solution. we do this even if
    # we're solving the extensive form directly, mainly out of
    # convenience - we're leveraging the code in ph_for_bundle to
    # create the scenario tree and scenario instances.
    print("")
    print("Loading scenario instances and initializing "
          "scenario tree for xhat scenario bundle.")

    xhat_ph = None
    try:

        xhat_ph = ph_for_bundle(0, num_scenarios_for_solution,
                                scenario_instance_factory, full_scenario_tree,
                                index_list, options)

        xhat_obj = None

        sense = xhat_ph._scenario_tree._scenarios[0]._objective_sense
        if sense == minimize:
            print("We are solving a MINIMIZATION problem.")
        else:
            print("We are solving a MAXIMIZATION problem.")

        if not options.solve_xhat_with_ph:
            print("Creating the xhat extensive form.")
            print("")
            print("Composite scenarios:")
            for scenario in xhat_ph._scenario_tree._scenarios:
                print(scenario._name)
            print("")

            if options.verbose:
                print("Time=" + time.asctime())

            with ExtensiveFormAlgorithm(xhat_ph,
                                        options._ef_options,
                                        prefix="ef_") as ef:

                ef.build_ef()
                print("Solving the xhat extensive form.")
                # Instance preprocessing is managed within the
                # ph object automatically when required for a
                # solve. Since we are solving the instances
                # outside of the ph object, we will inform it
                # that it should complete the instance
                # preprocessing early
                xhat_ph._preprocess_scenario_instances()
                ef.solve(io_options=\
                         {'output_fixed_variable_bounds':
                          options.write_fixed_variables})
                xhat_obj = ef.objective
            """
            hatex_ef = create_ef_instance(
                xhat_ph._scenario_tree,
                verbose_output=options.verbose,
                generate_weighted_cvar=options.generate_weighted_cvar,
                cvar_weight=options.cvar_weight,
                risk_alpha=options.risk_alpha)

            if options.verbose:
                print("Time="+time.asctime())
            print("Solving the xhat extensive form.")

            # Instance preprocessing is managed within the ph object
            # automatically when required for a solve. Since we are
            # solving the instances outside of the ph object, we will
            # inform it that it should complete the instance preprocessing
            # early
            xhat_ph._preprocess_scenario_instances()

            ef_results = solve_ef(hatex_ef, options)

            if options.verbose:
                print("Loading extensive form solution.")
                print("Time="+time.asctime())

            # IMPT: the following method populates the _solution variables
            #       on the scenario tree nodes by forming an average of
            #       the corresponding variable values for all instances
            #       particpating in that node. if you don't do this, the
            #       scenario tree doesn't have the solution - and we need
            #       this below for variable fixing.
            if options.verbose:
                print("Computing extensive form solution from instances.")
                print("Time="+time.asctime())

            xhat_ph._scenario_tree.pullScenarioSolutionsFromInstances()
            xhat_ph._scenario_tree.snapshotSolutionFromScenarios()

            xhat_obj = xhat_ph._scenario_tree.findRootNode().computeExpectedNodeCost()
            """
            print("Extensive form objective value given xhat=" + str(xhat_obj))
        else:
            print("Solving for xhat via Progressive Hedging.")
            phretval = xhat_ph.solve()
            if phretval is not None:
                raise RuntimeError("No solution was obtained "
                                   "for scenario: " + phretval)
            # TBD - grab xhat_obj; complicated by the fact that PH may not
            #       have converged.
            # TBD - also not sure if PH calls
            #       snapshotSolutionFromAverages.
        print("The computation of xhat is complete - "
              "starting to compute confidence interval "
              "via sub-sampling.")

    finally:

        if xhat_ph is not None:

            # we are using the PHCleanup function for
            # convenience, but we need to prevent it
            # from shutting down the scenario_instance_factory
            # as it is managed outside this function
            xhat_ph._scenario_tree._scenario_instance_factory = None
            PHCleanup(xhat_ph)

    return xhat_ph
示例#4
0
def solve_ph_code(ph, options):
    import pyomo.environ
    import pyomo.solvers.plugins.smanager.phpyro

    # consolidate the code to solve the problem for the "global" ph object
    # return a solver code (string from the solver if EF, "PH" if PH) and the objective fct val
    SolStatus = None

    ph._preprocess_scenario_instances()

    ObjectiveFctValue = \
       float('inf') if (ph._objective_sense is minimize) else float('-inf')
    SolStatus = None
    if not options.solve_with_ph:
        if options.verbose is True:
            print("Creating the extensive form.")
            print("Time=" + time.asctime())

        with ExtensiveFormAlgorithm(ph,
                                    options._ef_options,
                                    options_prefix="ef_") as ef:
            ef.build_ef()
            failure = ef.solve(io_options=\
                               {'output_fixed_variable_bounds':
                                options.write_fixed_variables},
                               exception_on_failure=False)
            if not failure:
                ObjectiveFctValue = ef.objective
            SolStatus = str(ef.solver_status)
        """
      ef = create_ef_instance(ph._scenario_tree,
                              verbose_output=options.verbose)

      if options.verbose:
         print("Time="+time.asctime())
         print("Solving the extensive form.")

      ef_results = solve_ef(ef, options)

      SolStatus = str(ef_results.solver.status) 
      print("SolStatus="+SolStatus)
      if options.verbose is True:
         print("Loading extensive form solution.")
         print("Time="+time.asctime())
      ### If the solution is infeasible, we don't want to load the results
      ### It is up to the caller to decide what to do with non-optimal
      if SolStatus != "infeasible" and SolStatus != "unknown":

         # IMPT: the following method populates the _solution variables on the scenario tree
         #       nodes by forming an average of the corresponding variable values for all
         #       instances particpating in that node. if you don't do this, the scenario tree
         #       doesn't have the solution - and we need this below for variable bounding
         ph._scenario_tree.pullScenarioSolutionsFromInstances()
         ph._scenario_tree.snapshotSolutionFromScenarios()
         if options.verbose is True:
            print("SolStatus="+SolStatus)
            print("Time="+time.asctime())

      _tear_down_ef(ef, ph._instances)
      """
    else:
        if options.verbose:
            print("Solving via Progressive Hedging.")

        run_ph(options, ph)
        ph._scenario_tree.pullScenarioSolutionsFromInstances()
        root_node = ph._scenario_tree._stages[0]._tree_nodes[0]
        ObjectiveFctValue = root_node.computeExpectedNodeCost()
        SolStatus = "PH"
        """
      phretval = ph.solve()
      #print("--------->>>> "+str(phretval))
      SolStatus = "PH"
      if phretval is not None:
         print("Iteration zero solve was not successful for scenario: "+str(phretval))
         if options.verbose is True:
            print("Iteration zero solve was not successful for scenario: "+str(phretval))
         SolStatus = "PHFailAtScen"+str(phretval)

      # TBD - also not sure if PH calls snapshotSolutionFromAverages.
      if options.verbose is True:
         print("Done with PH solve.")

      ##begin copy from phinit
      solution_writer_plugins = ExtensionPoint(ISolutionWriterExtension)
      for plugin in solution_writer_plugins:
         plugin.write(ph._scenario_tree, "ph")

      # store the binding instance, if created, in order to load
      # the solution back into the scenario tree.
      binding_instance = None

      #
      # create the extensive form binding instance, so that we can either write or solve it (if specified).
      #
      if (options.write_ef) or (options.solve_ef):

        # The post-solve plugins may have done more variable
        # fixing. These should be pushed to the instance at this
        # point.
        print("Pushing fixed variable statuses to scenario instances")
        ph._push_all_node_fixed_to_instances()
        total_fixed_discrete_vars, total_fixed_continuous_vars = \
            ph.compute_fixed_variable_counts()
        print("Number of discrete variables fixed "
              "prior to ef creation="
              +str(total_fixed_discrete_vars)+
              " (total="+str(ph._total_discrete_vars)+")")
        print("Number of continuous variables fixed "
              "prior to ef creation="
              +str(total_fixed_continuous_vars)+
              " (total="+str(ph._total_continuous_vars)+")")

        print("Creating extensive form for remainder problem")
        ef_instance_start_time = time.time()
        binding_instance = create_ef_instance(ph._scenario_tree)

        ef_instance_end_time = time.time()
        print("Time to construct extensive form instance=%.2f seconds"
              % (ef_instance_end_time - ef_instance_start_time))

      ph._preprocess_scenario_instances()
      #
      # solve the extensive form and load the solution back into the PH scenario tree.
      # contents from the PH solve will obviously be over-written!
      #
      if options.write_ef:
         output_filename = os.path.expanduser(options.ef_output_file)
         # technically, we don't need the symbol map since we aren't solving it.
         print("Starting to write the extensive form")
         ef_write_start_time = time.time()
         symbol_map = write_ef(binding_instance,
                               output_filename,
                               symbolic_solver_labels=options.symbolic_solver_labels,
                               output_fixed_variable_bounds=options.write_fixed_variables)
         ef_write_end_time = time.time()
         print("Extensive form written to file="+output_filename)
         print("Time to write output file=%.2f seconds"
               % (ef_write_end_time - ef_write_start_time))

      if options.solve_ef:

         # set the value of each non-converged, non-final-stage variable to None -
         # this will avoid infeasible warm-stats.
         reset_nonconverged_variables(ph._scenario_tree, ph._instances)
         reset_stage_cost_variables(ph._scenario_tree, ph._instances)

         ef_results = solve_ef(binding_instance, options)

         print("Storing solution in scenario tree")
         ph._scenario_tree.pullScenarioSolutionsFromInstances()
         ph._scenario_tree.snapshotSolutionFromScenarios()

         ef_solve_end_time = time.time()
         print("Time to solve and load results for the "
               "extensive form=%.2f seconds"
               % (ef_solve_end_time - ef_solve_start_time))

         # print *the* metric of interest.
         print("")
         root_node = ph._scenario_tree._stages[0]._tree_nodes[0]
         print("***********************************************************************************************")
         print(">>>THE EXPECTED SUM OF THE STAGE COST VARIABLES="+str(root_node.computeExpectedNodeCost())+"<<<")
         print("***********************************************************************************************")
         print("")
         print("Extensive form solution:")
         ph._scenario_tree.pprintSolution()
         print("")
         print("Extensive form costs:")
         ph._scenario_tree.pprintCosts()

         solution_writer_plugins = ExtensionPoint(ISolutionWriterExtension)
         for plugin in solution_writer_plugins:
            plugin.write(ph._scenario_tree, "postphef")

      if binding_instance is not None:
         _tear_down_ef(binding_instance, ph._instances)
      """

    print("SolStatus=" + str(SolStatus))
    if options.verbose:
        print("Time=" + time.asctime())

    ## print "(using PySP Cost vars) ObjectiveFctValue=",ObjectiveFctValue
    return SolStatus, ObjectiveFctValue