Beispiel #1
0
 def test_solve_bundles_optimal(self):
     problem = _SP_Bundles_Feasible
     for names in [None,
                   ['b0'],
                   ['b1'],
                   ['b2']]:
         with self._init(problem.get_factory()) as sp:
             with ScenarioTreeManagerSolverFactory(sp, _default_test_options) as manager:
                 results = manager.solve_bundles(check_status=False,
                                                 bundles=names)
             problem.validate_solve(self, sp, results, names=names)
         with self._init(problem.get_factory()) as sp:
             with ScenarioTreeManagerSolverFactory(sp, _default_test_options) as manager:
                 results = manager.solve_subproblems(check_status=False,
                                                     subproblems=names)
             problem.validate_solve(self, sp, results, names=names)
         with self._init(problem.get_factory()) as sp:
             with ScenarioTreeManagerSolverFactory(sp, _default_test_options) as manager:
                 results = manager.solve_bundles(check_status=True,
                                                 bundles=names)
             problem.validate_solve(self, sp, results, names=names)
         with self._init(problem.get_factory()) as sp:
             with ScenarioTreeManagerSolverFactory(sp, _default_test_options) as manager:
                 job = manager.solve_bundles(async=True,
                                             check_status=True,
                                             bundles=names)
                 results = job.complete()
             problem.validate_solve(self, sp, results, names=names)
         with self._init(problem.get_factory()) as sp:
             with ScenarioTreeManagerSolverFactory(sp, _default_test_options) as manager:
                 job = manager.solve_bundles(async=True,
                                             check_status=False,
                                             bundles=names)
                 results = job.complete()
             problem.validate_solve(self, sp, results, names=names)
Beispiel #2
0
 def _declare_options(cls, options=None):
     if options is None:
         options = PySPConfigBlock()
     safe_declare_common_option(options,
                                "verbose",
                                ap_group=_admm_group_label)
     ScenarioTreeManagerSolverFactory.register_options(
         options, options_prefix="subproblem_", setup_argparse=False)
     return options
Beispiel #3
0
 def _declare_options(cls, options=None):
     if options is None:
         options = PySPConfigBlock()
     safe_declare_common_option(options,
                                "verbose",
                                ap_group=_admm_group_label)
     ScenarioTreeManagerSolverFactory.register_options(
         options,
         options_prefix="subproblem_",
         setup_argparse=False)
     return options
Beispiel #4
0
def run_evaluate_xhat_register_options(options=None):
    if options is None:
        options = PySPConfigBlock()
    safe_register_common_option(options,
                               "disable_gc")
    safe_register_common_option(options,
                               "profile")
    safe_register_common_option(options,
                               "traceback")
    safe_register_common_option(options,
                               "scenario_tree_manager")
    safe_register_common_option(options,
                               "output_scenario_tree_solution")
    safe_register_common_option(options,
                               "solution_saver_extension")
    safe_register_common_option(options,
                               "solution_loader_extension")
    safe_register_unique_option(
        options,
        "disable_solution_loader_check",
        PySPConfigValue(
            False,
            domain=bool,
            description=(
                "Indicates that no solution loader extension is required to "
                "run this script, e.g., because the scenario tree manager "
                "is somehow pre-populated with a solution."
            ),
            doc=None,
            visibility=0),
        ap_group=_extension_options_group_title)
    safe_register_unique_option(
        options,
        "output_scenario_costs",
        PySPConfigValue(
            None,
            domain=_domain_must_be_str,
            description=(
                "A file name where individual scenario costs from the solution "
                "will be stored. The format is determined from the extension used "
                "in the filename. Recognized extensions: [.csv, .json, .yaml]"
            ),
            doc=None,
            visibility=0))
    ScenarioTreeManagerFactory.register_options(options)
    ScenarioTreeManagerSolverFactory.register_options(options,
                                                      options_prefix="subproblem_")

    return options
Beispiel #5
0
    def __init__(self, manager, *args, **kwds):
        super(ADMMAlgorithm, self).__init__(*args, **kwds)

        if not isinstance(manager, ScenarioTreeManager):
            raise TypeError("%s requires an instance of the "
                            "ScenarioTreeManagerSolver interface as the "
                            "second argument" % (self.__class__.__name__))
        if not manager.initialized:
            raise ValueError("%s requires a scenario tree "
                             "manager that has been fully initialized" %
                             (self.__class__.__name__))

        self._manager = manager
        self._manager_solver = ScenarioTreeManagerSolverFactory(
            self._manager, self._options, options_prefix="subproblem_")

        self.initialize_subproblems()
Beispiel #6
0
def run_evaluate_xhat_register_options(options=None):
    if options is None:
        options = PySPConfigBlock()
    safe_register_common_option(options, "disable_gc")
    safe_register_common_option(options, "profile")
    safe_register_common_option(options, "traceback")
    safe_register_common_option(options, "scenario_tree_manager")
    safe_register_common_option(options, "output_scenario_tree_solution")
    safe_register_common_option(options, "solution_saver_extension")
    safe_register_common_option(options, "solution_loader_extension")
    safe_register_unique_option(
        options,
        "disable_solution_loader_check",
        PySPConfigValue(
            False,
            domain=bool,
            description=(
                "Indicates that no solution loader extension is required to "
                "run this script, e.g., because the scenario tree manager "
                "is somehow pre-populated with a solution."),
            doc=None,
            visibility=0),
        ap_group=_extension_options_group_title)
    safe_register_unique_option(
        options, "output_scenario_costs",
        PySPConfigValue(
            None,
            domain=_domain_must_be_str,
            description=
            ("A file name where individual scenario costs from the solution "
             "will be stored. The format is determined from the extension used "
             "in the filename. Recognized extensions: [.csv, .json, .yaml]"),
            doc=None,
            visibility=0))
    ScenarioTreeManagerFactory.register_options(options)
    ScenarioTreeManagerSolverFactory.register_options(
        options, options_prefix="subproblem_")

    return options
    def test_solve_scenarios_infeasible(self):
        problem = _SP_Infeasible
        with self._init(problem.get_factory()) as sp:
            with ScenarioTreeManagerSolverFactory(
                    sp, _default_test_options) as manager:
                results = manager.solve_scenarios(check_status=False)
            problem.validate_solve(self, sp, results)
        with self._init(problem.get_factory()) as sp:
            with ScenarioTreeManagerSolverFactory(
                    sp, _default_test_options) as manager:
                with self.assertRaises(PySPFailedSolveStatus):
                    manager.solve_scenarios(check_status=True)
        with self._init(problem.get_factory()) as sp:
            with ScenarioTreeManagerSolverFactory(
                    sp, _default_test_options) as manager:
                job = manager.solve_scenarios(async_call=True,
                                              check_status=True)
                with self.assertRaises(PySPFailedSolveStatus):
                    job.complete()
        with self._init(problem.get_factory()) as sp:
            with ScenarioTreeManagerSolverFactory(
                    sp, _default_test_options) as manager:
                job = manager.solve_scenarios(async_call=True,
                                              check_status=False)
                results = job.complete()
            problem.validate_solve(self, sp, results)
        with self._init(problem.get_factory()) as sp:
            with ScenarioTreeManagerSolverFactory(
                    sp, _default_test_options) as manager:
                with self.assertRaises(RuntimeError):
                    manager.solve_bundles()

        for names in [None, ['s0'], ['s1'], ['s2']]:
            with self._init(problem.get_factory()) as sp:
                with ScenarioTreeManagerSolverFactory(
                        sp, _default_test_options) as manager:
                    results = manager.solve_scenarios(check_status=False,
                                                      scenarios=names)
                problem.validate_solve(self, sp, results, names=names)
            with self._init(problem.get_factory()) as sp:
                with ScenarioTreeManagerSolverFactory(
                        sp, _default_test_options) as manager:
                    job = manager.solve_scenarios(async_call=True,
                                                  check_status=False,
                                                  scenarios=names)
                    results = job.complete()
                problem.validate_solve(self, sp, results, names=names)
Beispiel #8
0
    def __init__(self, manager, *args, **kwds):
        super(ADMMAlgorithm, self).__init__(*args, **kwds)

        if not isinstance(manager, ScenarioTreeManager):
            raise TypeError("%s requires an instance of the "
                            "ScenarioTreeManagerSolver interface as the "
                            "second argument" % (self.__class__.__name__))
        if not manager.initialized:
            raise ValueError("%s requires a scenario tree "
                             "manager that has been fully initialized"
                             % (self.__class__.__name__))

        self._manager = manager
        self._manager_solver = ScenarioTreeManagerSolverFactory(
            self._manager,
            self._options,
            options_prefix="subproblem_")

        self.initialize_subproblems()
Beispiel #9
0
    has_networkx = True                           #pragma:nocover
except:                                           #pragma:nocover
    has_networkx = False

try:
    import dill
    has_dill = True                               #pragma:nocover
except ImportError:                               #pragma:nocover
    has_dill = False

thisfile = os.path.abspath(__file__)
thisdir = os.path.dirname(thisfile)

_run_verbose = True

_default_test_options = ScenarioTreeManagerSolverFactory.register_options()
_default_test_options.solver = 'glpk'
_default_test_options.solver_io = 'lp'
#_default_test_options.symbolic_solver_labels = True
#_default_test_options.keep_solver_files = True
#_default_test_options.disable_advanced_preprocessing = True

_pyomo_ns_host = '127.0.0.1'
_pyomo_ns_port = None
_pyomo_ns_process = None
_dispatch_srvr_port = None
_dispatch_srvr_process = None
_taskworker_processes = []
def tearDownModule():
    global _pyomo_ns_port
    global _pyomo_ns_process
Beispiel #10
0
class ADMMAlgorithm(PySPConfiguredObject):
    @classmethod
    def _declare_options(cls, options=None):
        if options is None:
            options = PySPConfigBlock()
        safe_declare_common_option(options,
                                   "verbose",
                                   ap_group=_admm_group_label)
        ScenarioTreeManagerSolverFactory.register_options(
            options, options_prefix="subproblem_", setup_argparse=False)
        return options

    def __enter__(self):
        return self

    def __exit__(self, *args):
        self.close()

    def close(self):
        if self._manager is not None:
            self.cleanup_subproblems()
        if self._manager_solver is not None:
            self._manager_solver.close()
        self._manager_solver = None
        self._manager = None

    def __init__(self, manager, *args, **kwds):
        super(ADMMAlgorithm, self).__init__(*args, **kwds)

        if not isinstance(manager, ScenarioTreeManager):
            raise TypeError("%s requires an instance of the "
                            "ScenarioTreeManagerSolver interface as the "
                            "second argument" % (self.__class__.__name__))
        if not manager.initialized:
            raise ValueError("%s requires a scenario tree "
                             "manager that has been fully initialized" %
                             (self.__class__.__name__))

        self._manager = manager
        self._manager_solver = ScenarioTreeManagerSolverFactory(
            self._manager, self._options, options_prefix="subproblem_")

        self.initialize_subproblems()

    def initialize_subproblems(self):
        if self.get_option("verbose"):
            print("Initializing subproblems for admm")
        self._manager.invoke_function(
            "EXTERNAL_initialize_for_admm",
            thisfile,
            invocation_type=InvocationType.PerScenario,
            oneway_call=True)

    def cleanup_subproblems(self):
        if self.get_option("verbose"):
            print("Cleaning up subproblems for admm")
        self._manager.invoke_function(
            "EXTERNAL_cleanup_for_admm",
            thisfile,
            invocation_type=InvocationType.PerScenario,
            oneway_call=True)

    def activate_lagrangian_term(self):
        self._manager.invoke_function(
            "EXTERNAL_activate_lagrangian_term",
            thisfile,
            invocation_type=InvocationType.PerScenario,
            oneway_call=True)

    def deactivate_lagrangian_term(self):
        self._manager.invoke_function(
            "EXTERNAL_deactivate_lagrangian_term",
            thisfile,
            invocation_type=InvocationType.PerScenario,
            oneway_call=True)

    def activate_penalty_term(self):
        self._manager.invoke_function(
            "EXTERNAL_activate_penalty_term",
            thisfile,
            invocation_type=InvocationType.PerScenario,
            oneway_call=True)

    def deactivate_penalty_term(self):
        self._manager.invoke_function(
            "EXTERNAL_deactivate_penalty_term",
            thisfile,
            invocation_type=InvocationType.PerScenario,
            oneway_call=True)

    def activate_probability_weighted_cost_term(self):
        self._manager.invoke_function(
            "EXTERNAL_activate_probability_weighted_cost_term",
            thisfile,
            invocation_type=InvocationType.PerScenario,
            oneway_call=True)

    def deactivate_probability_weighted_cost_term(self):
        self._manager.invoke_function(
            "EXTERNAL_deactivate_probability_weighted_cost_term",
            thisfile,
            invocation_type=InvocationType.PerScenario,
            oneway_call=True)

    def run_x_update(self, x, y, z, rho):
        self._manager.invoke_function(
            "EXTERNAL_update_rho",
            thisfile,
            invocation_type=InvocationType.PerScenario,
            function_args=(rho, ),
            oneway_call=True)
        for scenario in self._manager.scenario_tree.scenarios:
            self._manager.invoke_function(
                "EXTERNAL_update_y",
                thisfile,
                invocation_type=InvocationType.OnScenario(scenario.name),
                function_args=(y[scenario.name], ),
                oneway_call=True)
        self._manager.invoke_function(
            "EXTERNAL_update_z",
            thisfile,
            invocation_type=InvocationType.PerScenario,
            function_args=(z, ),
            oneway_call=True)

        self._manager_solver.solve_scenarios()

        objective = 0.0
        for scenario in self._manager.scenario_tree.scenarios:
            x_scenario = x[scenario.name]
            x_scenario_solution = scenario._x
            objective += scenario._objective
            for tree_node in scenario.node_list[:-1]:
                assert not tree_node.is_leaf_node()
                x_node = x_scenario[tree_node.name]
                x_node_solution = x_scenario_solution[tree_node.name]
                for id_ in tree_node._standard_variable_ids:
                    x_node[id_] = x_node_solution[id_]

        return objective

    def run_z_update(self, x, y, z, rho):
        primal_residual = 0.0
        dual_residual = 0.0
        x_scale = 0.0
        z_scale = 0.0
        for stage in self._manager.scenario_tree.stages[:-1]:
            for tree_node in stage.nodes:
                z_node = z[tree_node.name]
                rho_node = rho[tree_node.name]
                for id_ in tree_node._standard_variable_ids:
                    z_var_prev = z_node[id_]
                    rho_var = rho_node[id_]
                    z_var = 0.0
                    for scenario in tree_node.scenarios:
                        z_var += scenario._x[tree_node.name][id_]
                    z_var /= float(len(tree_node.scenarios))
                    if tree_node.is_variable_binary(id_) or \
                       tree_node.is_variable_integer(id_):
                        z_var = int(round(z_var))
                    dual_residual += len(tree_node.scenarios) * \
                                     rho_var**2 * \
                                     (z_var - z_var_prev)**2
                    for scenario in tree_node.scenarios:
                        x_var = scenario._x[tree_node.name][id_]
                        x_scale += x_var**2
                        primal_residual += (x_var - z_var)**2
                    z_node[id_] = z_var
                    z_scale += z_var**2
        return (math.sqrt(primal_residual), math.sqrt(dual_residual),
                math.sqrt(x_scale), math.sqrt(z_scale))

    def run_y_update(self, x, y, z, rho):
        y_scale = 0.0
        for scenario in self._manager.scenario_tree.scenarios:
            y_scenario = y[scenario.name]
            x_scenario = scenario._x
            for tree_node in scenario.node_list[:-1]:
                assert not tree_node.is_leaf_node()
                rho_node = rho[tree_node.name]
                z_node = z[tree_node.name]
                y_node = y_scenario[tree_node.name]
                x_node = x_scenario[tree_node.name]
                for id_ in tree_node._standard_variable_ids:
                    y_node[id_] += rho_node[id_] * (x_node[id_] - z_node[id_])
                    y_scale += y_node[id_]**2
        return math.sqrt(y_scale)

    def initialize_algorithm_data(self, rho_init=1.0, y_init=0.0, z_init=0.0):

        # used to check dual-feasibility of initial y
        y_sum = {}
        for stage in self._manager.scenario_tree.stages[:-1]:
            for tree_node in stage.nodes:
                y_sum_node = y_sum[tree_node.name] = \
                    dict((id_, 0.0) for id_ in tree_node._standard_variable_ids)

        x = {}
        y = {}
        for scenario in self._manager.scenario_tree.scenarios:
            x_scenario = x[scenario.name] = {}
            y_scenario = y[scenario.name] = {}
            for tree_node in scenario.node_list[:-1]:
                assert not tree_node.is_leaf_node()
                x_node = x_scenario[tree_node.name] = {}
                y_node = y_scenario[tree_node.name] = {}
                y_sum_node = y_sum[tree_node.name]
                for id_ in tree_node._standard_variable_ids:
                    x_node[id_] = None
                    if type(y_init) is dict:
                        y_node[id_] = y_init[scenario.name][
                            tree_node.name][id_]
                    else:
                        y_node[id_] = y_init
                    y_sum_node[id_] += y_node[id_]

        # check dual-feasibility of y
        for stage in self._manager.scenario_tree.stages[:-1]:
            for tree_node in stage.nodes:
                y_sum_node = y_sum[tree_node.name]
                for id_ in tree_node._standard_variable_ids:
                    if abs(y_sum_node[id_]) > 1e-6:
                        name, index = tree_node._variable_ids[id_]
                        raise ValueError(
                            "Initial lagrange multipler estimates for non-"
                            "anticipative variable %s do not sum to zero: %s" %
                            (name + indexToString(index), repr(
                                y_sum_node[id_])))

        rho = {}
        z = {}
        for stage in self._manager.scenario_tree.stages[:-1]:
            for tree_node in stage.nodes:
                z_node = z[tree_node.name] = {}
                rho_node = rho[tree_node.name] = {}
                for id_ in tree_node._standard_variable_ids:
                    if type(rho_init) is dict:
                        rho_node[id_] = rho_init[tree_node.name][id_]
                    else:
                        rho_node[id_] = rho_init
                    if type(z_init) is dict:
                        z_node[id_] = z_init[tree_node.name][id_]
                    else:
                        z_node[id_] = z_init

        return rho, x, y, z

    def compute_nodevector_norm(self, v):
        vnorm = 0.0
        for stage in self._manager.scenario_tree.stages[:-1]:
            for tree_node in stage.nodes:
                v_node = v[tree_node.name]
                for id_ in tree_node._standard_variable_ids:
                    vnorm += v_node[id_]**2
        return math.sqrt(vnorm)
Beispiel #11
0
def run_evaluate_xhat(options, solution_loaders=(), solution_savers=()):

    import pyomo.environ

    start_time = time.time()

    solution_loaders = sort_extensions_by_precedence(solution_loaders)
    solution_savers = sort_extensions_by_precedence(solution_savers)

    with ScenarioTreeManagerFactory(options) as sp:
        sp.initialize()

        loaded = False
        for plugin in solution_loaders:
            ret = plugin.load(sp)
            if not ret:
                print("WARNING: Loader extension %s call did not return True. "
                      "This might indicate failure to load data." % (plugin))
            else:
                loaded = True

        if (not loaded) and (not options.disable_solution_loader_check):
            raise RuntimeError(
                "Either no solution loader extensions were provided or "
                "all solution loader extensions reported a bad return value. "
                "To disable this check use the disable_solution_loader_check "
                "option flag.")

        with ScenarioTreeManagerSolverFactory(
                sp, options, options_prefix="subproblem_") as sp_solver:
            evaluate_current_node_solution(sp, sp_solver)

        objective = sum(scenario.probability * \
                        scenario.get_current_objective()
                        for scenario in sp.scenario_tree.scenarios)
        sp.scenario_tree.snapshotSolutionFromScenarios()

        print("")
        print("***********************************************"
              "************************************************")
        print(">>>THE EXPECTED SUM OF THE STAGE COST VARIABLES="
              +str(sp.scenario_tree.findRootNode().\
                   computeExpectedNodeCost())+"<<<")
        print("***********************************************"
              "************************************************")

        # handle output of solution from the scenario tree.
        print("")
        print("Extensive form solution:")
        sp.scenario_tree.pprintSolution()
        print("")
        print("Extensive form costs:")
        sp.scenario_tree.pprintCosts()

        if options.output_scenario_tree_solution:
            print("Final solution (scenario tree format):")
            sp.scenario_tree.pprintSolution()

        if options.output_scenario_costs is not None:
            if options.output_scenario_costs.endswith('.json'):
                import json
                result = {}
                for scenario in sp.scenario_tree.scenarios:
                    result[str(scenario.name)] = scenario._cost
                with open(options.output_scenario_costs, 'w') as f:
                    json.dump(result, f, indent=2, sort_keys=True)
            elif options.output_scenario_costs.endswith('.yaml'):
                import yaml
                result = {}
                for scenario in sp.scenario_tree.scenarios:
                    result[str(scenario.name)] = scenario._cost
                with open(options.output_scenario_costs, 'w') as f:
                    yaml.dump(result, f)
            else:
                if not options.output_scenario_costs.endswith('.csv'):
                    print("Unrecognized file extension. Using CSV format "
                          "to store scenario costs")
                with open(options.output_scenario_costs, 'w') as f:
                    for scenario in sp.scenario_tree.scenarios:
                        f.write("%s,%r\n" % (scenario.name, scenario._cost))

        for plugin in solution_savers:
            if not plugin.save(sp):
                print("WARNING: Saver extension %s call did not return True. "
                      "This might indicate failure to save data." % (plugin))

    print("")
    print("Total execution time=%.2f seconds" % (time.time() - start_time))

    return 0
Beispiel #12
0
class ADMMAlgorithm(PySPConfiguredObject):

    @classmethod
    def _declare_options(cls, options=None):
        if options is None:
            options = PySPConfigBlock()
        safe_declare_common_option(options,
                                   "verbose",
                                   ap_group=_admm_group_label)
        ScenarioTreeManagerSolverFactory.register_options(
            options,
            options_prefix="subproblem_",
            setup_argparse=False)
        return options

    def __enter__(self):
        return self

    def __exit__(self, *args):
        self.close()

    def close(self):
        if self._manager is not None:
            self.cleanup_subproblems()
        if self._manager_solver is not None:
            self._manager_solver.close()
        self._manager_solver = None
        self._manager = None

    def __init__(self, manager, *args, **kwds):
        super(ADMMAlgorithm, self).__init__(*args, **kwds)

        if not isinstance(manager, ScenarioTreeManager):
            raise TypeError("%s requires an instance of the "
                            "ScenarioTreeManagerSolver interface as the "
                            "second argument" % (self.__class__.__name__))
        if not manager.initialized:
            raise ValueError("%s requires a scenario tree "
                             "manager that has been fully initialized"
                             % (self.__class__.__name__))

        self._manager = manager
        self._manager_solver = ScenarioTreeManagerSolverFactory(
            self._manager,
            self._options,
            options_prefix="subproblem_")

        self.initialize_subproblems()

    def initialize_subproblems(self):
        if self.get_option("verbose"):
            print("Initializing subproblems for admm")
        self._manager.invoke_function(
            "EXTERNAL_initialize_for_admm",
            thisfile,
            invocation_type=InvocationType.PerScenario,
            oneway_call=True)

    def cleanup_subproblems(self):
        if self.get_option("verbose"):
            print("Cleaning up subproblems for admm")
        self._manager.invoke_function(
            "EXTERNAL_cleanup_for_admm",
            thisfile,
            invocation_type=InvocationType.PerScenario,
            oneway_call=True)

    def activate_lagrangian_term(self):
        self._manager.invoke_function(
            "EXTERNAL_activate_lagrangian_term",
            thisfile,
            invocation_type=InvocationType.PerScenario,
            oneway_call=True)

    def deactivate_lagrangian_term(self):
        self._manager.invoke_function(
            "EXTERNAL_deactivate_lagrangian_term",
            thisfile,
            invocation_type=InvocationType.PerScenario,
            oneway_call=True)

    def activate_penalty_term(self):
        self._manager.invoke_function(
            "EXTERNAL_activate_penalty_term",
            thisfile,
            invocation_type=InvocationType.PerScenario,
            oneway_call=True)

    def deactivate_penalty_term(self):
        self._manager.invoke_function(
            "EXTERNAL_deactivate_penalty_term",
            thisfile,
            invocation_type=InvocationType.PerScenario,
            oneway_call=True)

    def activate_probability_weighted_cost_term(self):
        self._manager.invoke_function(
            "EXTERNAL_activate_probability_weighted_cost_term",
            thisfile,
            invocation_type=InvocationType.PerScenario,
            oneway_call=True)

    def deactivate_probability_weighted_cost_term(self):
        self._manager.invoke_function(
            "EXTERNAL_deactivate_probability_weighted_cost_term",
            thisfile,
            invocation_type=InvocationType.PerScenario,
            oneway_call=True)

    def run_x_update(self, x, y, z, rho):
        self._manager.invoke_function(
            "EXTERNAL_update_rho",
            thisfile,
            invocation_type=InvocationType.PerScenario,
            function_args=(rho,),
            oneway_call=True)
        for scenario in self._manager.scenario_tree.scenarios:
            self._manager.invoke_function(
                "EXTERNAL_update_y",
                thisfile,
                invocation_type=InvocationType.OnScenario(scenario.name),
                function_args=(y[scenario.name],),
                oneway_call=True)
        self._manager.invoke_function(
            "EXTERNAL_update_z",
            thisfile,
            invocation_type=InvocationType.PerScenario,
            function_args=(z,),
            oneway_call=True)

        self._manager_solver.solve_scenarios()

        objective = 0.0
        for scenario in self._manager.scenario_tree.scenarios:
            x_scenario = x[scenario.name]
            x_scenario_solution = scenario._x
            objective += scenario._objective
            for tree_node in scenario.node_list[:-1]:
                assert not tree_node.is_leaf_node()
                x_node = x_scenario[tree_node.name]
                x_node_solution = x_scenario_solution[tree_node.name]
                for id_ in tree_node._standard_variable_ids:
                    x_node[id_] = x_node_solution[id_]

        return objective

    def run_z_update(self, x, y, z, rho):
        primal_residual = 0.0
        dual_residual = 0.0
        x_scale = 0.0
        z_scale = 0.0
        for stage in self._manager.scenario_tree.stages[:-1]:
            for tree_node in stage.nodes:
                z_node = z[tree_node.name]
                rho_node = rho[tree_node.name]
                for id_ in tree_node._standard_variable_ids:
                    z_var_prev = z_node[id_]
                    rho_var = rho_node[id_]
                    z_var = 0.0
                    for scenario in tree_node.scenarios:
                        z_var += scenario._x[tree_node.name][id_]
                    z_var /= float(len(tree_node.scenarios))
                    if tree_node.is_variable_binary(id_) or \
                       tree_node.is_variable_integer(id_):
                        z_var = int(round(z_var))
                    dual_residual += len(tree_node.scenarios) * \
                                     rho_var**2 * \
                                     (z_var - z_var_prev)**2
                    for scenario in tree_node.scenarios:
                        x_var = scenario._x[tree_node.name][id_]
                        x_scale += x_var**2
                        primal_residual += (x_var - z_var)**2
                    z_node[id_] = z_var
                    z_scale += z_var**2
        return (math.sqrt(primal_residual),
                math.sqrt(dual_residual),
                math.sqrt(x_scale),
                math.sqrt(z_scale))

    def run_y_update(self, x, y, z, rho):
        y_scale = 0.0
        for scenario in self._manager.scenario_tree.scenarios:
            y_scenario = y[scenario.name]
            x_scenario = scenario._x
            for tree_node in scenario.node_list[:-1]:
                assert not tree_node.is_leaf_node()
                rho_node = rho[tree_node.name]
                z_node = z[tree_node.name]
                y_node = y_scenario[tree_node.name]
                x_node = x_scenario[tree_node.name]
                for id_ in tree_node._standard_variable_ids:
                    y_node[id_] += rho_node[id_] * (x_node[id_] - z_node[id_])
                    y_scale += y_node[id_]**2
        return math.sqrt(y_scale)

    def initialize_algorithm_data(self,
                                  rho_init=1.0,
                                  y_init=0.0,
                                  z_init=0.0):

        # used to check dual-feasibility of initial y
        y_sum = {}
        for stage in self._manager.scenario_tree.stages[:-1]:
            for tree_node in stage.nodes:
                y_sum_node = y_sum[tree_node.name] = \
                    dict((id_, 0.0) for id_ in tree_node._standard_variable_ids)

        x = {}
        y = {}
        for scenario in self._manager.scenario_tree.scenarios:
            x_scenario = x[scenario.name] = {}
            y_scenario = y[scenario.name] = {}
            for tree_node in scenario.node_list[:-1]:
                assert not tree_node.is_leaf_node()
                x_node = x_scenario[tree_node.name] = {}
                y_node = y_scenario[tree_node.name] = {}
                y_sum_node = y_sum[tree_node.name]
                for id_ in tree_node._standard_variable_ids:
                    x_node[id_] = None
                    if type(y_init) is dict:
                        y_node[id_] = y_init[scenario.name][tree_node.name][id_]
                    else:
                        y_node[id_] = y_init
                    y_sum_node[id_] += y_node[id_]

        # check dual-feasibility of y
        for stage in self._manager.scenario_tree.stages[:-1]:
            for tree_node in stage.nodes:
                y_sum_node = y_sum[tree_node.name]
                for id_ in tree_node._standard_variable_ids:
                    if abs(y_sum_node[id_]) > 1e-6:
                        name, index = tree_node._variable_ids[id_]
                        raise ValueError(
                            "Initial lagrange multipler estimates for non-"
                            "anticipative variable %s do not sum to zero: %s"
                            % (name+indexToString(index), repr(y_sum_node[id_])))

        rho = {}
        z = {}
        for stage in self._manager.scenario_tree.stages[:-1]:
            for tree_node in stage.nodes:
                z_node = z[tree_node.name] = {}
                rho_node = rho[tree_node.name] = {}
                for id_ in tree_node._standard_variable_ids:
                    if type(rho_init) is dict:
                        rho_node[id_] = rho_init[tree_node.name][id_]
                    else:
                        rho_node[id_] = rho_init
                    if type(z_init) is dict:
                        z_node[id_] = z_init[tree_node.name][id_]
                    else:
                        z_node[id_] = z_init

        return rho, x, y, z

    def compute_nodevector_norm(self, v):
        vnorm = 0.0
        for stage in self._manager.scenario_tree.stages[:-1]:
            for tree_node in stage.nodes:
                v_node = v[tree_node.name]
                for id_ in tree_node._standard_variable_ids:
                    vnorm += v_node[id_]**2
        return math.sqrt(vnorm)
    has_networkx = True                           #pragma:nocover
except:                                           #pragma:nocover
    has_networkx = False

try:
    import dill
    has_dill = True                               #pragma:nocover
except ImportError:                               #pragma:nocover
    has_dill = False

thisfile = os.path.abspath(__file__)
thisdir = os.path.dirname(thisfile)

_run_verbose = True

_default_test_options = ScenarioTreeManagerSolverFactory.register_options()
_default_test_options.solver = 'glpk'
_default_test_options.solver_io = 'lp'
#_default_test_options.symbolic_solver_labels = True
#_default_test_options.keep_solver_files = True
#_default_test_options.disable_advanced_preprocessing = True

_pyomo_ns_host = '127.0.0.1'
_pyomo_ns_port = None
_pyomo_ns_process = None
_dispatch_srvr_port = None
_dispatch_srvr_process = None
_taskworker_processes = []
def tearDownModule():
    global _pyomo_ns_port
    global _pyomo_ns_process