Changeset 3038
- Timestamp:
- Sep 22, 2010 5:12:01 PM (11 years ago)
- Location:
- coopr.pysp/trunk/coopr/pysp
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
coopr.pysp/trunk/coopr/pysp/ef.py
r2993 r3038 69 69 # instances are associated with the extensive form. this might be something we 70 70 # encapsulate at some later time. 71 # NOTE: if cvar terms are generated, then the input scenario tree is modified accordingly, 72 # i.e., with the addition of the "eta" variable at the root node and the excess 73 # variables at (for lack of a better place - they are per-scenario, but are not 74 # blended) the second stage. 71 75 # 72 76 … … 89 93 print "CVaR alpha="+str(risk_alpha) 90 94 print "" 95 96 # update the scenario tree with cvar-specific variable names, so 97 # they will get cloned accordingly in the master instance. 98 first_stage = scenario_tree._stages[0] 99 second_stage = scenario_tree._stages[1] 100 root_node = first_stage._tree_nodes[0] 101 102 # NOTE: because we currently don't have access to the reference 103 # instance in this method, temporarily (and largely orphaned) 104 # variables are constructed to supply to the scenario tree. 105 # this decision should be ultimately revisited. 106 cvar_eta_variable_name = "CVAR_ETA" 107 cvar_eta_variable = Var(name=cvar_eta_variable_name) 108 cvar_eta_variable.construct() 109 110 first_stage.add_variable(cvar_eta_variable, "*", [None]) 111 112 cvar_excess_variable_name = "CVAR_EXCESS" 113 cvar_excess_variable = Var(name=cvar_excess_variable_name) 114 cvar_excess_variable.construct() 115 116 second_stage.add_variable(cvar_excess_variable, "*", [None]) 117 118 # create the eta and excess variable on a per-scenario basis, 119 # in addition to the constraint relating to the two. 120 for scenario_name, scenario_instance in scenario_instances.items(): 121 122 cvar_excess_variable_name = "CVAR_EXCESS" 123 cvar_excess_variable = Var(name=cvar_excess_variable_name, domain=NonNegativeReals) 124 cvar_excess_variable.construct() 125 setattr(scenario_instance, cvar_excess_variable_name, cvar_excess_variable) 126 127 cvar_eta_variable_name = "CVAR_ETA" 128 cvar_eta_variable = Var(name=cvar_eta_variable_name) 129 cvar_eta_variable.construct() 130 setattr(scenario_instance, cvar_eta_variable_name, cvar_eta_variable) 131 132 compute_excess_constraint_name = "COMPUTE_SCENARIO_EXCESS" 133 compute_excess_constraint = Constraint(name=compute_excess_constraint_name) 134 compute_excess_expression = cvar_excess_variable 135 for node in scenario_tree._scenario_map[scenario_name]._node_list: 136 (cost_variable, cost_variable_idx) = node._stage._cost_variable 137 compute_excess_expression -= getattr(scenario_instance, cost_variable.name)[cost_variable_idx] 138 compute_excess_expression += cvar_eta_variable 139 compute_excess_constraint.add(None, (0.0, compute_excess_expression, None)) 140 compute_excess_constraint._model = scenario_instance 141 setattr(scenario_instance, compute_excess_constraint_name, compute_excess_constraint) 142 143 # re-process the scenario instance due to the newly added constraints/variables associated 144 # with CVaR. a complete preprocess is overkill, of course - the correct approach would be 145 # to just preprocess those newly added variables and constraints. 146 scenario_instance.preprocess() 91 147 92 148 # … … 118 174 if stage != scenario_tree._stages[-1]: 119 175 120 master_variable_name = tree_node._name + "_" + stage_variable.name176 master_variable_name = stage_variable.name 121 177 122 178 # because there may be a single stage variable and multiple indices, check … … 156 212 if (is_used is True) and (is_fixed is False): 157 213 158 # the following is necessary, specifically to get the name - deepcopy won't reset these attributes.159 # and because presolve/simplification is name-based, the names *have* to be different.160 master_variable[index].var = master_variable161 master_variable[index].name = tree_node._name + "_" + master_variable[index].name162 163 214 for scenario in tree_node._scenarios: 164 215 scenario_instance = scenario_instances[scenario._name] … … 181 232 setattr(binding_instance, expected_cost_variable_name, expected_cost_variable) 182 233 183 # if we're generating the weighted CVaR objective term, create the184 # corresponding variable and the master CVaR eta variable.185 234 if generate_weighted_cvar is True: 186 235 187 root_node = scenario_tree._stages[0]._tree_nodes[0]188 189 236 cvar_cost_variable_name = "CVAR_COST_" + root_node._name 190 237 cvar_cost_variable = Var(name=cvar_cost_variable_name) 238 cvar_cost_variable.construct() 191 239 setattr(binding_instance, cvar_cost_variable_name, cvar_cost_variable) 192 cvar_cost_variable.construct()193 194 cvar_eta_variable_name = "CVAR_ETA_" + root_node._name195 cvar_eta_variable = Var(name=cvar_eta_variable_name)196 setattr(binding_instance, cvar_eta_variable_name, cvar_eta_variable)197 cvar_eta_variable.construct()198 240 199 241 binding_instance.preprocess() … … 245 287 # i.e., the current node cost and the expected cost of the child nodes. 246 288 # if the root, then the constraint is just the objective. 247 248 289 for stage in scenario_tree._stages: 249 290 … … 284 325 cvar_cost_variable = getattr(binding_instance, cvar_cost_variable_name) 285 326 if cvar_weight == 0.0: 327 # if the cvar weight is 0, then we're only doing cvar - no mean. 286 328 opt_expression = cvar_cost_variable 287 329 else: … … 298 340 if generate_weighted_cvar is True: 299 341 300 root_node = scenario_tree._stages[0]._tree_nodes[0]301 302 master_cvar_eta_variable_name = "CVAR_ETA_" + root_node._name303 master_cvar_eta_variable = getattr(binding_instance, master_cvar_eta_variable_name)304 305 for scenario_name in scenario_instances.keys():306 scenario_instance = scenario_instances[scenario_name]307 308 # unique names are required because the presolve isn't309 # aware of the "owning" models for variables.310 cvar_excess_variable_name = "CVAR_EXCESS_"+scenario_name311 cvar_excess_variable = Var(name=cvar_excess_variable_name, domain=NonNegativeReals)312 setattr(scenario_instance, cvar_excess_variable_name, cvar_excess_variable)313 cvar_excess_variable.construct()314 315 cvar_eta_variable_name = "CVAR_ETA"316 cvar_eta_variable = Var(name=cvar_eta_variable_name)317 setattr(scenario_instance, cvar_eta_variable_name, cvar_eta_variable)318 cvar_eta_variable.construct()319 320 compute_excess_constraint_name = "COMPUTE_SCENARIO_EXCESS"321 compute_excess_constraint = Constraint(name=compute_excess_constraint_name)322 compute_excess_expression = cvar_excess_variable323 for node in scenario_tree._scenario_map[scenario_name]._node_list:324 (cost_variable, cost_variable_idx) = node._stage._cost_variable325 compute_excess_expression -= getattr(scenario_instance, cost_variable.name)[cost_variable_idx]326 compute_excess_expression += cvar_eta_variable327 compute_excess_constraint.add(None, (0.0, compute_excess_expression, None))328 compute_excess_constraint._model = scenario_instance329 setattr(scenario_instance, compute_excess_constraint_name, compute_excess_constraint)330 331 eta_equality_constraint_name = "MASTER_ETA_EQUALITY_WITH_" + scenario_instance.name332 eta_equality_constraint = Constraint(name=eta_equality_constraint_name)333 eta_equality_expr = master_cvar_eta_variable - cvar_eta_variable334 eta_equality_constraint.add(None, (0.0, eta_equality_expr, 0.0))335 eta_equality_constraint._model = binding_instance336 setattr(binding_instance, eta_equality_constraint_name, eta_equality_constraint)337 338 # re-process the scenario instance due to the newly added constraints/variables associated339 # with CVaR. a complete preprocess is overkill, of course - the correct approach would be340 # to just preprocess those newly added variables and constraints.341 scenario_instance.preprocess()342 343 342 # add the constraint to compute the master CVaR variable value. iterate 344 343 # over scenario instances to create the expected excess component first. 345 344 cvar_cost_variable_name = "CVAR_COST_" + root_node._name 346 345 cvar_cost_variable = getattr(binding_instance, cvar_cost_variable_name) 347 cvar_eta_variable_name = "CVAR_ETA _" + root_node._name346 cvar_eta_variable_name = "CVAR_ETA" 348 347 cvar_eta_variable = getattr(binding_instance, cvar_eta_variable_name) 349 348 350 349 cvar_cost_expression = cvar_cost_variable - cvar_eta_variable 351 350 352 for scenario_name in scenario_instances.keys():353 scenario_instance = scenario_instances[scenario_name] 351 for scenario_name, scenario_instance in scenario_instances.items(): 352 354 353 scenario_probability = scenario_tree._scenario_map[scenario_name]._probability 355 354 356 scenario_excess_variable_name = "CVAR_EXCESS _"+scenario_name355 scenario_excess_variable_name = "CVAR_EXCESS" 357 356 scenario_excess_variable = getattr(scenario_instance, scenario_excess_variable_name) 358 357 -
coopr.pysp/trunk/coopr/pysp/scenariotree.py
r2852 r3038 23 23 24 24 # 25 # initialize the _solutions attribute of a tree node. 26 # 27 28 def _initialize_solutions(self): 25 # update the _solutions attribute of a tree node, given a specific 26 # variable/match-template/variable-index triple. 27 # 28 def _update_solution_map(self, variable, match_template, variable_indices): 29 30 # don't bother copying bounds for variables, as the values stored 31 # here are computed elsewhere - and that entity is responsible for 32 # ensuring feasibility. this also leaves room for specifying infeasible 33 # or partial solutions. 34 new_variable_index = variable._index 35 new_variable_name = variable.name 36 new_variable = None 37 if (len(new_variable_index) is 1) and (None in new_variable_index): 38 new_variable = Var(name=new_variable_name) 39 else: 40 new_variable = Var(new_variable_index, name=new_variable_name) 41 new_variable.construct() 42 43 # by default, deactive all variable values - we're copying the 44 # full index set of a variable, which is necessarily wasteful and 45 # incorrect. then, do a second pass and activate those indicies 46 # that are actually associated with this tree node. 47 for index in new_variable_index: 48 new_variable[index].deactivate() 49 50 for index in variable_indices: 51 new_variable[index].activate() 52 53 self._solutions[new_variable_name] = new_variable 54 55 # 56 # initialize the _solutions attribute of a tree node, from scratch. 57 # 58 59 def _initialize_solution_map(self): 60 61 # clear whatever was there before. 62 self._solutions = {} 29 63 30 64 # NOTE: Given the expense, this should really be optional - don't … … 36 70 # is an issue (space is the most likely issue) 37 71 for variable, match_template, variable_indices in self._stage._variables: 38 39 # don't bother copying bounds for variables, as the values stored 40 # here are computed elsewhere - and that entity is responsible for 41 # ensuring feasibility. this also leaves room for specifying infeasible 42 # or partial solutions. 43 new_variable_index = variable._index 44 new_variable_name = variable.name 45 new_variable = None 46 if (len(new_variable_index) is 1) and (None in new_variable_index): 47 new_variable = Var(name=new_variable_name) 48 else: 49 new_variable = Var(new_variable_index, name=new_variable_name) 50 new_variable.construct() 51 52 # by default, deactive all variable values - we're copying the 53 # full index set of a variable, which is necessarily wasteful and 54 # incorrect. then, do a second pass and activate those indicies 55 # that are actually associated with this tree node. 56 for index in new_variable_index: 57 new_variable[index].deactivate() 58 59 for index in variable_indices: 60 new_variable[index].activate() 61 62 self._solutions[new_variable_name] = new_variable 63 64 self._solutions_initialized = True 72 self._update_solution_map(variable, match_template, variable_indices) 73 74 self._solution_map_initialized = True 65 75 66 76 … … 92 102 93 103 # a flag indicating whether the _solutions attribute has been properly initialized. 94 self._solution s_initialized = False104 self._solution_map_initialized = False 95 105 96 106 # solution (variable) values for this node. assumed to be distinct … … 101 111 102 112 if initialize_solution is True: 103 self._initialize_solution s()113 self._initialize_solution_map() 104 114 105 115 # … … 110 120 def snapshotSolutionFromAverages(self): 111 121 112 if self._solution s_initialized is False:113 self._initialize_solution s()122 if self._solution_map_initialized is False: 123 self._initialize_solution_map() 114 124 115 125 for variable_name, variable in self._solutions.items(): … … 134 144 def snapshotSolutionFromInstances(self, scenario_instance_map): 135 145 136 if self._solution s_initialized is False:137 self._initialize_solution s()146 if self._solution_map_initialized is False: 147 self._initialize_solution_map() 138 148 139 149 for variable_name, variable in self._solutions.items(): … … 174 184 """ 175 185 def __init__(self, *args, **kwds): 186 176 187 self._name = "" 177 self._tree_nodes = [] # a collection of ScenarioTreeNodes 178 # a collection of pairs consisting of (1) references to pyomo model Vars, (2) the original match template string (for output purposes), 179 # and (3) a *list* of the corresponding indices. 180 # the variables are references to those objects belonging to the instance in the parent ScenarioTree. 188 189 # a collection of ScenarioTreeNode objects. 190 self._tree_nodes = [] 191 192 # a collection of triples consisting of (1) a reference to a Pyomo model Var object, (2) the original match 193 # template string (for output purposes), and (3) a *list* of the corresponding indices. the variables are 194 # references to those objects belonging to the Pyomo reference scenario instance associated with the parent 195 # ScenarioTree of this Stage. 181 196 # NOTE: if the variable index is none, it is assumed that the entire variable is blended. 182 197 self._variables = [] 183 # a tuple consisting of (1) a reference to a pyomo model Var that computes the stage-specific cost and (2) the corresponding index. 184 # the index *is* the sole index in the cost variable, as the cost variable refers to a single variable index. 198 199 # a tuple consisting of (1) a reference to a pyomo model Var that computes the stage-specific cost and (2) the corresponding 200 # index. the index *is* the sole index in the cost variable, as the cost variable refers to a single variable index. 185 201 self._cost_variable = (None, None) 202 203 # 204 # add a new variable to the stage, which will include updating the solution maps for each associated ScenarioTreeNode. 205 # 206 def add_variable(self, variable, match_template, indices): 207 208 self._variables.append((variable, match_template, indices)) 209 210 for tree_node in self._tree_nodes: 211 tree_node._update_solution_map(variable, match_template, indices) 186 212 187 213 class Scenario(object): … … 190 216 """ 191 217 def __init__(self, *args, **kwds): 218 192 219 self._name = None 193 220 self._leaf_node = None # allows for construction of node list … … 328 355 """ 329 356 def __init__(self, *args, **kwds): 330 self._name = None # TBD - some arbitrary identifier 331 self._reference_instance = None # TBD - the reference (deterministic) base model 357 358 self._name = None # some arbitrary identifier 359 self._reference_instance = None # the reference (deterministic) base model 332 360 333 361 # the core objects defining the scenario tree. … … 341 369 self._scenario_map = {} 342 370 343 # mapping of stages to sets of variables which belong in the corresponding stage.344 self._stage_variables = {}345 346 371 # a boolean indicating how data for scenario instances is specified. 347 372 # possibly belongs elsewhere, e.g., in the PH algorithm. 348 373 self._scenario_based_data = None 349 350 # every stage has a cost variable - this is a variable/index pair.351 self._cost_variable = None352 374 353 375 scenario_tree_instance = None
Note: See TracChangeset
for help on using the changeset viewer.