1 | # _________________________________________________________________________ |
---|
2 | # |
---|
3 | # Coopr: A COmmon Optimization Python Repository |
---|
4 | # Copyright (c) 2010 Sandia Corporation. |
---|
5 | # This software is distributed under the BSD License. |
---|
6 | # Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, |
---|
7 | # the U.S. Government retains certain rights in this software. |
---|
8 | # For more information, see the Coopr README.txt file. |
---|
9 | # _________________________________________________________________________ |
---|
10 | |
---|
11 | |
---|
12 | __all__ = [] |
---|
13 | |
---|
14 | import Pyro.core |
---|
15 | import Pyro.naming |
---|
16 | |
---|
17 | from coopr.opt.parallel.manager import * |
---|
18 | from coopr.opt.parallel.solver import * |
---|
19 | from coopr.pyomo import * |
---|
20 | from pyutilib.component.core import alias |
---|
21 | |
---|
22 | try: |
---|
23 | import cPickle as pickle |
---|
24 | except ImportError: |
---|
25 | import pickle |
---|
26 | |
---|
27 | # a solver manager that communicates with remote PH solver servers |
---|
28 | # via the Pyro RMI mechanism. |
---|
29 | |
---|
30 | class PHSolverManager(AsynchronousSolverManager): |
---|
31 | |
---|
32 | alias('ph') |
---|
33 | |
---|
34 | def __init__(self): |
---|
35 | """Constructor""" |
---|
36 | |
---|
37 | AsynchronousSolverManager.__init__(self) |
---|
38 | |
---|
39 | # fire up Pyro. |
---|
40 | Pyro.core.initClient(banner=0) |
---|
41 | |
---|
42 | # locate the name server and cache it. |
---|
43 | self._locator = Pyro.naming.NameServerLocator() |
---|
44 | self._ns = None |
---|
45 | try: |
---|
46 | self._ns = self._locator.getNS() |
---|
47 | except Pyro.errors.NamingError: |
---|
48 | raise RuntimeError, "PHSolverManager failed to locate Pyro name server" |
---|
49 | |
---|
50 | # the PH solver server object proxies are cached for speed. |
---|
51 | # map is from scenario name to proxy object. |
---|
52 | self._solver_proxy = {} |
---|
53 | |
---|
54 | # |
---|
55 | # a utility to identify (and create if necessary) the |
---|
56 | # appropriate proxy object for a given scenario. |
---|
57 | # |
---|
58 | |
---|
59 | def _identify_proxy(self, scenario_name): |
---|
60 | |
---|
61 | proxy = None |
---|
62 | if scenario_name in self._solver_proxy.keys(): |
---|
63 | proxy = self._solver_proxy[scenario_name] |
---|
64 | else: |
---|
65 | uri = None |
---|
66 | try: |
---|
67 | uri = self._ns.resolve(scenario_name) |
---|
68 | except Pyro.errors.NamingError: |
---|
69 | raise RuntimeError, "***ERROR: Failed to locate PH solver server capable of processing scenario="+scenario_name |
---|
70 | sys.exit(0) |
---|
71 | |
---|
72 | proxy = Pyro.core.getProxyForURI(uri) |
---|
73 | self._solver_proxy[scenario_name] = proxy |
---|
74 | return proxy |
---|
75 | |
---|
76 | def clear(self): |
---|
77 | """ |
---|
78 | Clear manager state |
---|
79 | """ |
---|
80 | AsynchronousSolverManager.clear(self) |
---|
81 | self._ah_list = [] |
---|
82 | self._opt = None |
---|
83 | |
---|
84 | def _perform_queue(self, ah, *args, **kwds): |
---|
85 | """ |
---|
86 | Perform the queue operation. This method returns the ActionHandle, |
---|
87 | and the ActionHandle status indicates whether the queue was successful. |
---|
88 | """ |
---|
89 | |
---|
90 | # extract the instance and the scenario name. |
---|
91 | if len(args) != 1: |
---|
92 | raise RuntimeError, "Only one argument to _perform_queue method of class PHSolverManager expected - "+str(len(args))+" were supplied" |
---|
93 | scenario_instance = args[0] |
---|
94 | if isinstance(scenario_instance, Model) is False: |
---|
95 | raise RuntimeError, "Argument supplied to _perform_queue method of class PHSolverManager must be a Model instance - type supplied="+str(type(scenario_instance)) |
---|
96 | scenario_name = scenario_instance.name |
---|
97 | |
---|
98 | # process any keywordds - we generally don't expect any. |
---|
99 | if 'opt' in kwds: |
---|
100 | self._opt = kwds['opt'] |
---|
101 | del kwds['opt'] |
---|
102 | if self._opt is None: |
---|
103 | raise ActionManagerError, "Undefined solver" |
---|
104 | |
---|
105 | # TBD - we don't actually transfer any solver options |
---|
106 | # at the moment, but we will soon! |
---|
107 | |
---|
108 | proxy = self._identify_proxy(scenario_name) |
---|
109 | encoded_result = proxy.solve(scenario_name) |
---|
110 | self.results[ah.id] = pickle.loads(encoded_result) |
---|
111 | ah.status = ActionStatus.done |
---|
112 | self._ah_list.append(ah) |
---|
113 | return ah |
---|
114 | |
---|
115 | def _perform_wait_any(self): |
---|
116 | """ |
---|
117 | Perform the wait_any operation. This method returns an |
---|
118 | ActionHandle with the results of waiting. If None is returned |
---|
119 | then the ActionManager assumes that it can call this method again. |
---|
120 | Note that an ActionHandle can be returned with a dummy value, |
---|
121 | to indicate an error. |
---|
122 | """ |
---|
123 | if len(self._ah_list) > 0: |
---|
124 | return self._ah_list.pop() |
---|
125 | return ActionHandle(error=True, explanation="No queued evaluations available in the PH solver manager, which only executes solvers synchronously") |
---|
126 | |
---|
127 | def enable_ph_objective(self, scenario_instance): |
---|
128 | |
---|
129 | proxy = self._identify_proxy(scenario_instance.name) |
---|
130 | proxy.enable_ph_objective() |
---|
131 | |
---|
132 | def transmit_weights_and_averages(self, scenario_instance, new_weights, new_averages): |
---|
133 | |
---|
134 | proxy = self._identify_proxy(scenario_instance.name) |
---|
135 | proxy.update_weights_and_averages(scenario_instance.name, new_weights, new_averages) |
---|
136 | |
---|
137 | def transmit_rhos(self, scenario_instance, new_rhos): |
---|
138 | |
---|
139 | proxy = self._identify_proxy(scenario_instance.name) |
---|
140 | proxy.update_rhos(scenario_instance.name, new_rhos) |
---|
141 | |
---|
142 | def transmit_tree_node_statistics(self, scenario_instance, tree_node_minimums, tree_node_maximums): |
---|
143 | |
---|
144 | proxy = self._identify_proxy(scenario_instance.name) |
---|
145 | proxy.update_tree_node_statistics(scenario_instance.name, tree_node_minimums, tree_node_maximums) |
---|
146 | |
---|