source: coopr.pysp/trunk/coopr/pysp/ef.py @ 2413

Last change on this file since 2413 was 2413, checked in by jwatson, 9 years ago

PySP EF restructuring / refactoring

File size: 42.5 KB
Line 
1import pyutilib
2import sys
3import os
4import time
5import traceback
6import copy
7
8from coopr.pysp.scenariotree import *
9from coopr.pysp.convergence import *
10from coopr.pysp.ph import *
11
12from coopr.pyomo.base import *
13from coopr.pyomo.io import *
14
15from coopr.pyomo.base.var import _VarValue, _VarBase
16
17#
18# brain-dead utility for determing if there is a binary to write in the
19# composite model - need to know this, because CPLEX doesn't like empty
20# binary blocks in the LP file.
21#
22
23def binaries_present(master_model, scenario_instances):
24
25   # check the master model first.
26   for var in master_model.active_components(Var).values():
27      if isinstance(var.domain, BooleanSet):
28         return True
29
30   # scan the scenario instances next.
31   for scenario_name in scenario_instances.keys():
32      scenario_instance = scenario_instances[scenario_name]
33      for var in scenario_instance.active_components(Var).values():
34         if isinstance(var.domain, BooleanSet):
35            return True
36
37   return False
38
39#
40# brain-dead utility for determing if there is a binary to write in the
41# composite model - need to know this, because CPLEX doesn't like empty
42# integer blocks in the LP file.
43#
44
45def integers_present(master_model, scenario_instances):
46
47   # check the master model first.
48   for var in master_model.active_components(Var).values():
49      if isinstance(var.domain, IntegerSet):
50         return True
51
52   # scan the scenario instances next.
53   for scenario_name in scenario_instances.keys():
54      scenario_instance = scenario_instances[scenario_name]
55      for var in scenario_instance.active_components(Var).values():
56         if isinstance(var.domain, IntegerSet):
57            return True
58
59   return False
60
61#
62# a routine to create the extensive form, given an input scenario tree and instances.
63# IMPT: unlike scenario instances, the extensive form instance is *not* self-contained.
64#       in particular, it has binding constraints that cross the binding instance and
65#       the scenario instances. it is up to the caller to keep track of which scenario
66#       instances are associated with the extensive form. this might be something we
67#       encapsulate at some later time.
68#
69
70def create_ef_instance(scenario_tree, scenario_instances, generate_weighted_cvar, verbose_output):
71
72   binding_instance = Model()
73   binding_instance.name = "MASTER"
74
75   # walk the scenario tree - create variables representing the common values for all scenarios
76   # associated with that node. the constraints will be created later. also create expected-cost
77   # variables for each node, to be computed via constraints/objectives defined in a subsequent pass.
78   # master variables are created for all nodes but those in the last stage. expected cost variables
79   # are, for no particularly good reason other than easy coding, created for nodes in all stages.
80   if verbose_output is True:
81      print "Creating variables for master binding instance"
82
83   for stage in scenario_tree._stages:
84
85      for (stage_variable, index_template, stage_variable_indices) in stage._variables:
86
87         if verbose_output is True:
88            print "Creating master variable and blending constraints for decision variable=", stage_variable, ", indices=", index_template
89
90         for tree_node in stage._tree_nodes:
91
92            if stage != scenario_tree._stages[-1]:     
93
94               master_variable_name = tree_node._name + "_" + stage_variable.name
95
96               # because there may be a single stage variable and multiple indices, check
97               # for the existence of the variable at this node - if you don't, you'll
98               # inadvertently over-write what was there previously!
99               master_variable = None
100               try:
101                  master_variable = getattr(binding_instance, master_variable_name)
102               except:
103                  new_master_variable_index = stage_variable._index
104                  new_master_variable = None
105                  if (len(new_master_variable_index) is 1) and (None in new_master_variable_index):
106                     new_master_variable = Var(name=stage_variable.name)
107                  else:
108                     new_master_variable = Var(new_master_variable_index, name=stage_variable.name)
109                  new_master_variable.construct()
110                  new_master_variable._model = binding_instance
111                  setattr(master_binding_instance, master_variable_name, new_master_variable)
112
113                  master_variable = new_master_variable
114
115               for index in stage_variable_indices:
116
117                  is_used = True # until proven otherwise                     
118                  for scenario in tree_node._scenarios:
119                     instance = scenario_instances[scenario._name]
120                     if getattr(instance,stage_variable.name)[index].status == VarStatus.unused:
121                        is_used = False
122
123                  is_fixed = False # until proven otherwise
124                  for scenario in tree_node._scenarios:
125                     instance = scenario_instances[scenario._name]
126                     if getattr(instance,stage_variable.name)[index].fixed is True:
127                        is_fixed = True
128
129                  if (is_used is True) and (is_fixed is False):
130                           
131                     # the following is necessary, specifically to get the name - deepcopy won't reset these attributes.
132                     # and because presolve/simplification is name-based, the names *have* to be different.
133                     master_variable[index].var = master_variable
134                     master_variable[index].name = tree_node._name + "_" + master_variable[index].name
135
136                     for scenario in tree_node._scenarios:
137
138                        scenario_instance = scenario_instances[scenario._name]
139                        scenario_variable = getattr(scenario_instance, stage_variable.name)
140                        new_constraint_name = scenario._name + "_" + master_variable_name + "_" + str(index)
141                        new_constraint = Constraint(name=new_constraint_name)
142                        new_expr = master_variable[index] - scenario_variable[index]
143                        new_constraint.add(None, (0.0, new_expr, 0.0))
144                        new_constraint._model = master_binding_instance
145                        setattr(master_binding_instance, new_constraint_name, new_constraint)
146
147            # create a variable to represent the expected cost at this node -
148            # the constraint to compute this comes later.
149            expected_cost_variable_name = "EXPECTED_COST_" + tree_node._name
150            expected_cost_variable = Var(name=expected_cost_variable_name)
151            expected_cost_variable._model = master_binding_instance
152            setattr(master_binding_instance, expected_cost_variable_name, expected_cost_variable)
153
154   master_binding_instance.preprocess()
155
156   # ditto above for the (non-expected) cost variable.
157   for stage in scenario_tree._stages:
158
159      (cost_variable,cost_variable_index) = stage._cost_variable
160
161      if verbose_output:
162         print "Creating master variable and blending constraints for cost variable=", cost_variable, ", index=", cost_variable_index     
163
164      for tree_node in stage._tree_nodes:
165
166         new_cost_variable_name = tree_node._name + "_" + cost_variable.name
167
168         # TBD - the following is bad - check to see if it's already there (I suspect some of them are!!!)
169
170         # this is undoubtedly wasteful, in that a cost variable
171         # for each tree node is created with *all* indices.
172         new_cost_variable_name = tree_node._name + "_" + cost_variable.name
173         new_cost_variable_index = cost_variable._index
174         new_cost_variable = None
175         if (len(new_cost_variable_index) is 1) and (None in new_cost_variable_index):
176            new_cost_variable = Var(name=new_cost_variable_name)
177         else:
178            new_cost_variable = Var(new_cost_variable_index, new_cost_variable_name)
179         new_cost_variable.construct()
180         new_cost_variable._model = master_binding_instance
181         setattr(master_binding_instance, new_cost_variable_name, new_cost_variable)                 
182
183         # the following is necessary, specifically to get the name - deepcopy won't reset these attributes.
184         new_cost_variable[cost_variable_index].var = new_cost_variable
185         if cost_variable_index is not None:
186            # if the variable index is None, the variable is derived from a VarValue, so the
187            # name gets updated automagically.
188            new_cost_variable[cost_variable_index].name = tree_node._name + "_" + new_cost_variable[cost_variable_index].name
189
190         for scenario in tree_node._scenarios:
191
192            scenario_instance = scenario_instances[scenario._name]
193            scenario_cost_variable = getattr(scenario_instance, cost_variable.name)
194            new_constraint_name = scenario._name + "_" + new_cost_variable_name + "_" + str(cost_variable_index)
195            new_constraint = Constraint(name=new_constraint_name)
196            new_expr = new_cost_variable[cost_variable_index] - scenario_cost_variable[cost_variable_index]
197            new_constraint.add(None, (0.0, new_expr, 0.0))
198            new_constraint._model = master_binding_instance
199            setattr(master_binding_instance, new_constraint_name, new_constraint)
200
201   # create the constraints for computing the master per-node cost variables,
202   # i.e., the current node cost and the expected cost of the child nodes.
203   # if the root, then the constraint is just the objective.
204
205   for stage in scenario_tree._stages:
206
207      (stage_cost_variable,stage_cost_variable_index) = stage._cost_variable
208
209      for tree_node in stage._tree_nodes:
210
211         node_expected_cost_variable_name = "EXPECTED_COST_" + tree_node._name
212         node_expected_cost_variable = getattr(master_binding_instance, node_expected_cost_variable_name)
213
214         node_cost_variable_name = tree_node._name + "_" + stage_cost_variable.name
215         node_cost_variable = getattr(master_binding_instance, node_cost_variable_name)                       
216           
217         constraint_expr = node_expected_cost_variable - node_cost_variable[stage_cost_variable_index]
218
219         for child_node in tree_node._children:
220
221            child_node_expected_cost_variable_name = "EXPECTED_COST_" + child_node._name
222            child_node_expected_cost_variable = getattr(master_binding_instance, child_node_expected_cost_variable_name)
223            constraint_expr = constraint_expr - (child_node._conditional_probability * child_node_expected_cost_variable)
224
225         new_constraint_name = "COST" + "_" + node_cost_variable_name + "_" + str(cost_variable_index)
226         new_constraint = Constraint(name=new_constraint_name)
227         new_constraint.add(None, (0.0, constraint_expr, 0.0))
228         new_constraint._model = master_binding_instance                     
229         setattr(master_binding_instance, new_constraint_name, new_constraint)
230
231         if tree_node._parent is None:
232
233            an_instance = scenario_instances[scenario_instances.keys()[0]]
234            an_objective = an_instance.active_components(Objective)
235            opt_sense = an_objective[an_objective.keys()[0]].sense
236
237            new_objective = Objective(name="MASTER", sense=opt_sense)
238            new_objective._data[None].expr = node_expected_cost_variable
239            setattr(master_binding_instance, "MASTER", new_objective)
240
241   master_binding_instance.preprocess()
242
243   return master_binding_instance
244
245#
246# the main extensive-form writer routine - including read of scenarios/etc.
247#
248
249def write_ef_from_scratch(model_directory, instance_directory, output_filename, \
250                          generate_weighted_cvar, cvar_weight, risk_alpha):
251
252   start_time = time.time()
253
254   scenario_data_directory_name = instance_directory
255
256   print "Initializing extensive form writer"
257   print ""
258
259   ################################################################################################
260   #### INITIALIZATION ############################################################################
261   ################################################################################################
262
263   #
264   # validate cvar options, if specified.
265   #
266   if generate_weighted_cvar is True:
267      if cvar_weight <= 0.0:
268         raise RuntimeError, "Weight of CVaR term must be >= 0.0 - value supplied="+str(cvar_weight)
269      if (risk_alpha <= 0.0) or (risk_alpha >= 1.0):
270         raise RuntimeError, "CVaR risk alpha must be between 0 and 1, exclusive - value supplied="+str(risk_alpha)
271
272      print "Writing CVaR weighted objective"
273      print "CVaR term weight="+str(cvar_weight)
274      print "CVaR alpha="+str(risk_alpha)
275      print ""
276   
277   #
278   # create and populate the core model
279   #
280   master_scenario_model = None
281   master_scenario_instance = None
282   
283   try:
284     
285      reference_model_filename = model_directory+os.sep+"ReferenceModel.py"   
286      modelimport = pyutilib.misc.import_file(reference_model_filename)
287      if "model" not in dir(modelimport):
288         print ""
289         print "Exiting ef module: No 'model' object created in module "+reference_model_filename
290         sys.exit(0)
291      if modelimport.model is None:
292         print ""
293         print "Exiting ef module: 'model' object equals 'None' in module "+reference_model_filename
294         sys.exit(0)
295   
296      master_scenario_model = modelimport.model
297
298   except IOError:
299     
300      print "***ERROR: Failed to load scenario reference model from file="+reference_model_filename
301      return
302
303   try:
304     
305      reference_scenario_filename = instance_directory+os.sep+"ReferenceModel.dat"
306      master_scenario_instance = master_scenario_model.create(reference_scenario_filename)
307     
308   except IOError:
309     
310      print "***ERROR: Failed to load scenario reference instance data from file="+reference_scenario_filename
311      return           
312
313   #
314   # create and populate the scenario tree model
315   #
316
317   from coopr.pysp.util.scenariomodels import scenario_tree_model
318
319   scenario_tree_instance = scenario_tree_model.create(instance_directory+os.sep+"ScenarioStructure.dat")
320
321   #
322   # construct the scenario tree
323   #
324   scenario_tree = ScenarioTree(scenarioinstance=master_scenario_instance,
325                                scenariotreeinstance=scenario_tree_instance)
326
327   #
328   # print the input tree for validation/information purposes.
329   #
330   scenario_tree.pprint()
331
332   #
333   # validate the tree prior to doing anything serious
334   #
335   print ""
336   if scenario_tree.validate() is False:
337      print "***Scenario tree is invalid****"
338      sys.exit(1)
339   else:
340      print "Scenario tree is valid!"
341   print ""
342
343   #
344   # construct instances for each scenario
345   #
346
347   instances = {}
348   
349   if scenario_tree._scenario_based_data == 1:
350      print "Scenario-based instance initialization enabled"
351   else:
352      print "Node-based instance initialization enabled"
353         
354   for scenario in scenario_tree._scenarios:
355
356      scenario_instance = None
357
358      print "Creating instance for scenario=" + scenario._name
359
360      try:
361         if scenario_tree._scenario_based_data == 1:
362            scenario_data_filename = scenario_data_directory_name + os.sep + scenario._name + ".dat"
363#            print "Data for scenario=" + scenario._name + " loads from file=" + scenario_data_filename
364            scenario_instance = master_scenario_model.create(scenario_data_filename)
365         else:
366            scenario_instance = master_scenario_model.clone()
367            scenario_data = ModelData()
368            current_node = scenario._leaf_node
369            while current_node is not None:
370               node_data_filename = scenario_data_directory_name + os.sep + current_node._name + ".dat"
371#               print "Node data for scenario=" + scenario._name + " partially loading from file=" + node_data_filename
372               scenario_data.add(node_data_filename)
373               current_node = current_node._parent
374            scenario_data.read(model=scenario_instance)
375            scenario_instance._load_model_data(scenario_data)
376            scenario_instance.preprocess()
377      except:
378         print "Encountered exception in model instance creation - traceback:"
379         traceback.print_exc()
380         raise RuntimeError, "Failed to create model instance for scenario=" + scenario._name
381
382      # name each instance with the scenario name, so the prefixes in the EF make sense.
383      scenario_instance.name = scenario._name
384     
385      scenario_instance.preprocess()
386      instances[scenario._name] = scenario_instance
387
388   print ""
389
390   ################################################################################################
391   #### CREATE THE MASTER / BINDING INSTANCE ######################################################
392   ################################################################################################
393
394   master_binding_instance = Model()
395   master_binding_instance.name = "MASTER"
396
397   # walk the scenario tree - create variables representing the common values for all scenarios
398   # associated with that node. the constraints will be created later. also create expected-cost
399   # variables for each node, to be computed via constraints/objectives defined in a subsequent pass.
400   # master variables are created for all nodes but those in the last stage. expected cost variables
401   # are, for no particularly good reason other than easy coding, created for nodes in all stages.
402   print "Creating variables for master binding instance"
403
404   for stage in scenario_tree._stages:
405
406      for (stage_variable, index_template, stage_variable_indices) in stage._variables:
407
408         print "Creating master variable and blending constraints for decision variable="+stage_variable.name+", indices="+str(stage_variable_indices)
409
410         for tree_node in stage._tree_nodes:
411
412            if stage != scenario_tree._stages[-1]:     
413
414               master_variable_name = tree_node._name + "_" + stage_variable.name
415
416               # because there may be a single stage variable and multiple indices, check
417               # for the existence of the variable at this node - if you don't, you'll
418               # inadvertently over-write what was there previously!
419               master_variable = None
420               try:
421                  master_variable = getattr(master_binding_instance, master_variable_name)
422               except:
423                  new_master_variable_index = stage_variable._index
424                  new_master_variable = None
425                  if (len(new_master_variable_index) is 1) and (None in new_master_variable_index):
426                     new_master_variable = Var(name=stage_variable.name)
427                  else:
428                     new_master_variable = Var(new_master_variable_index, name=stage_variable.name)
429                  new_master_variable.construct()
430                  new_master_variable._model = master_binding_instance
431                  setattr(master_binding_instance, master_variable_name, new_master_variable)
432
433                  # TBD - TECHNICALLY, WE NEED TO COPY BOUNDS - BUT WE REALLY DON'T, AS THEY ARE ON THE PER-INSTNACE VARS!
434
435                  master_variable = new_master_variable
436
437               for index in stage_variable_indices:
438
439                  is_used = True # until proven otherwise                     
440                  for scenario in tree_node._scenarios:
441                     instance = instances[scenario._name]
442                     if getattr(instance,stage_variable.name)[index].status == VarStatus.unused:
443                        is_used = False
444
445                  is_fixed = False # until proven otherwise
446                  for scenario in tree_node._scenarios:
447                     instance = instances[scenario._name]
448                     if getattr(instance,stage_variable.name)[index].fixed is True:
449                        is_fixed = True
450
451                  if (is_used is True) and (is_fixed is False):
452                           
453                     # the following is necessary, specifically to get the name - deepcopy won't reset these attributes.
454                     # and because presolve/simplification is name-based, the names *have* to be different.
455                     master_variable[index].var = master_variable
456                     master_variable[index].name = tree_node._name + "_" + master_variable[index].name
457
458                     for scenario in tree_node._scenarios:
459
460                        scenario_instance = instances[scenario._name]
461                        scenario_variable = getattr(scenario_instance, stage_variable.name)
462                        new_constraint_name = scenario._name + "_" + master_variable_name + "_" + str(index)
463                        new_constraint = Constraint(name=new_constraint_name)
464                        new_expr = master_variable[index] - scenario_variable[index]
465                        new_constraint.add(None, (0.0, new_expr, 0.0))
466                        new_constraint._model = master_binding_instance
467                        setattr(master_binding_instance, new_constraint_name, new_constraint)
468
469            # create a variable to represent the expected cost at this node -
470            # the constraint to compute this comes later.
471            expected_cost_variable_name = "EXPECTED_COST_" + tree_node._name
472            expected_cost_variable = Var(name=expected_cost_variable_name)
473            expected_cost_variable._model = master_binding_instance
474            setattr(master_binding_instance, expected_cost_variable_name, expected_cost_variable)
475
476   # if we're generating the weighted CVaR objective term, create the corresponding variable and
477   # the master CVaR eta variable.
478   if generate_weighted_cvar is True:
479      root_node = scenario_tree._stages[0]._tree_nodes[0]
480     
481      cvar_cost_variable_name = "CVAR_COST_" + root_node._name
482      cvar_cost_variable = Var(name=cvar_cost_variable_name)
483      setattr(master_binding_instance, cvar_cost_variable_name, cvar_cost_variable)
484      cvar_cost_variable.construct()
485
486      cvar_eta_variable_name = "CVAR_ETA_" + root_node._name
487      cvar_eta_variable = Var(name=cvar_eta_variable_name)
488      setattr(master_binding_instance, cvar_eta_variable_name, cvar_eta_variable)     
489      cvar_eta_variable.construct()
490
491   master_binding_instance.preprocess()
492
493   # ditto above for the (non-expected) cost variable.
494   for stage in scenario_tree._stages:
495
496      (cost_variable,cost_variable_index) = stage._cost_variable
497
498      print "Creating master variable and blending constraints for cost variable="+cost_variable.name+", index="+str(cost_variable_index)
499
500      for tree_node in stage._tree_nodes:
501
502         # TBD - the following is bad - check to see if it's already there (I suspect some of them are!!!)         
503
504         # this is undoubtedly wasteful, in that a cost variable
505         # for each tree node is created with *all* indices.         
506         new_cost_variable_name = tree_node._name + "_" + cost_variable.name
507         new_cost_variable_index = cost_variable._index
508         new_cost_variable = None
509         if (len(new_cost_variable_index) is 1) and (None in new_cost_variable_index):
510            new_cost_variable = Var(name=new_cost_variable_name)
511         else:
512            new_cost_variable = Var(new_cost_variable_index, name=new_cost_variable_name)
513         new_cost_variable.construct()
514         new_cost_variable._model = master_binding_instance
515         setattr(master_binding_instance, new_cost_variable_name, new_cost_variable)         
516
517         # the following is necessary, specifically to get the name - deepcopy won't reset these attributes.
518         new_cost_variable[cost_variable_index].var = new_cost_variable
519         if cost_variable_index is not None:
520            # if the variable index is None, the variable is derived from a VarValue, so the
521            # name gets updated automagically.
522            new_cost_variable[cost_variable_index].name = tree_node._name + "_" + new_cost_variable[cost_variable_index].name
523
524         for scenario in tree_node._scenarios:
525
526            scenario_instance = instances[scenario._name]
527            scenario_cost_variable = getattr(scenario_instance, cost_variable.name)
528            new_constraint_name = scenario._name + "_" + new_cost_variable_name + "_" + str(cost_variable_index)
529            new_constraint = Constraint(name=new_constraint_name)
530            new_expr = new_cost_variable[cost_variable_index] - scenario_cost_variable[cost_variable_index]
531            new_constraint.add(None, (0.0, new_expr, 0.0))
532            new_constraint._model = master_binding_instance
533            setattr(master_binding_instance, new_constraint_name, new_constraint)
534
535   # create the constraints for computing the master per-node cost variables,
536   # i.e., the current node cost and the expected cost of the child nodes.
537   # if the root, then the constraint is just the objective.
538
539   for stage in scenario_tree._stages:
540
541      (stage_cost_variable,stage_cost_variable_index) = stage._cost_variable
542
543      for tree_node in stage._tree_nodes:
544
545         node_expected_cost_variable_name = "EXPECTED_COST_" + tree_node._name
546         node_expected_cost_variable = getattr(master_binding_instance, node_expected_cost_variable_name)
547
548         node_cost_variable_name = tree_node._name + "_" + stage_cost_variable.name
549         node_cost_variable = getattr(master_binding_instance, node_cost_variable_name)                       
550           
551         constraint_expr = node_expected_cost_variable - node_cost_variable[stage_cost_variable_index]
552
553         for child_node in tree_node._children:
554
555            child_node_expected_cost_variable_name = "EXPECTED_COST_" + child_node._name
556            child_node_expected_cost_variable = getattr(master_binding_instance, child_node_expected_cost_variable_name)
557            constraint_expr = constraint_expr - (child_node._conditional_probability * child_node_expected_cost_variable)
558
559         new_constraint_name = "COST" + "_" + node_cost_variable_name + "_" + str(cost_variable_index)
560         new_constraint = Constraint(name=new_constraint_name)
561         new_constraint.add(None, (0.0, constraint_expr, 0.0))
562         new_constraint._model = master_binding_instance                     
563         setattr(master_binding_instance, new_constraint_name, new_constraint)
564
565         if tree_node._parent is None:
566
567            an_instance = instances[instances.keys()[0]]
568            an_objective = an_instance.active_components(Objective)
569            opt_sense = an_objective[an_objective.keys()[0]].sense
570
571            opt_expression = node_expected_cost_variable
572
573            if generate_weighted_cvar is True:
574               cvar_cost_variable_name = "CVAR_COST_" + tree_node._name
575               cvar_cost_variable = getattr(master_binding_instance, cvar_cost_variable_name)
576               opt_expression += cvar_weight * cvar_cost_variable
577
578            new_objective = Objective(name="MASTER", sense=opt_sense)
579            new_objective._data[None].expr = opt_expression
580            setattr(master_binding_instance, "MASTER", new_objective)
581
582   # CVaR requires the addition of a variable per scenario to represent the cost excess,
583   # and a constraint to compute the cost excess relative to eta. we also replicate (following
584   # what we do for node cost variables) an eta variable for each scenario instance, and
585   # require equality with the master eta variable via constraints.
586   if generate_weighted_cvar is True:
587     
588      root_node = scenario_tree._stages[0]._tree_nodes[0]
589
590      master_cvar_eta_variable_name = "CVAR_ETA_" + root_node._name
591      master_cvar_eta_variable = getattr(master_binding_instance, master_cvar_eta_variable_name)
592     
593      for scenario_name in instances.keys():
594         scenario_instance = instances[scenario_name]
595
596         # unique names are required because the presolve isn't
597         # aware of the "owning" models for variables.
598         cvar_excess_variable_name = "CVAR_EXCESS_"+scenario_name
599         cvar_excess_variable = Var(name=cvar_excess_variable_name, domain=NonNegativeReals)
600         setattr(scenario_instance, cvar_excess_variable_name, cvar_excess_variable)
601         cvar_excess_variable.construct()
602
603         cvar_eta_variable_name = "CVAR_ETA"
604         cvar_eta_variable = Var(name=cvar_eta_variable_name)
605         setattr(scenario_instance, cvar_eta_variable_name, cvar_eta_variable)
606         cvar_eta_variable.construct()
607
608         compute_excess_constraint_name = "COMPUTE_SCENARIO_EXCESS"
609         compute_excess_constraint = Constraint(name=compute_excess_constraint_name)
610         compute_excess_expression = cvar_excess_variable
611         for node in scenario_tree._scenario_map[scenario_name]._node_list:
612            (cost_variable, cost_variable_idx) = node._stage._cost_variable
613            compute_excess_expression -= getattr(scenario_instance, cost_variable.name)[cost_variable_idx]
614         compute_excess_expression += cvar_eta_variable
615         compute_excess_constraint.add(None, (0.0, compute_excess_expression, None))
616         compute_excess_constraint._model = scenario_instance
617         setattr(scenario_instance, compute_excess_constraint_name, compute_excess_constraint)
618
619         eta_equality_constraint_name = "MASTER_ETA_EQUALITY_WITH_" + scenario_instance.name
620         eta_equality_constraint = Constraint(name=eta_equality_constraint_name)
621         eta_equality_expr = master_cvar_eta_variable - cvar_eta_variable
622         eta_equality_constraint.add(None, (0.0, eta_equality_expr, 0.0))
623         eta_equality_constraint._model = master_binding_instance
624         setattr(master_binding_instance, eta_equality_constraint_name, eta_equality_constraint)
625
626      # add the constraint to compute the master CVaR variable value. iterate
627      # over scenario instances to create the expected excess component first.
628      cvar_cost_variable_name = "CVAR_COST_" + root_node._name
629      cvar_cost_variable = getattr(master_binding_instance, cvar_cost_variable_name)
630      cvar_eta_variable_name = "CVAR_ETA_" + root_node._name
631      cvar_eta_variable = getattr(master_binding_instance, cvar_eta_variable_name)
632     
633      cvar_cost_expression = cvar_cost_variable - cvar_eta_variable
634     
635      for scenario_name in instances.keys():
636         scenario_instance = instances[scenario_name]
637         scenario_probability = scenario_tree._scenario_map[scenario_name]._probability
638
639         scenario_excess_variable_name = "CVAR_EXCESS_"+scenario_name
640         scenario_excess_variable = getattr(scenario_instance, scenario_excess_variable_name)
641
642         cvar_cost_expression = cvar_cost_expression - (scenario_probability * scenario_excess_variable) / (1.0 - risk_alpha)
643
644      compute_cvar_cost_constraint_name = "COMPUTE_CVAR_COST"
645      compute_cvar_cost_constraint = Constraint(name=compute_cvar_cost_constraint_name)
646      compute_cvar_cost_constraint.add(None, (0.0, cvar_cost_expression, 0.0))
647      compute_cvar_cost_constraint._model = master_binding_instance
648      setattr(master_binding_instance, compute_cvar_cost_constraint_name, compute_cvar_cost_constraint)
649
650   # after mucking with instances, presolve to collect terms required prior to output.         
651   # IMPT: Do the scenario instances first, as the master depends on variables in the scenarios.
652   for scenario_name in instances.keys():
653      scenario_instance = instances[scenario_name]   
654      scenario_instance.preprocess()         
655
656   master_binding_instance.preprocess()
657
658   ################################################################################################
659   #### WRITE THE COMPOSITE MODEL #################################################################
660   ################################################################################################
661
662   print ""
663   print "Starting to write extensive form"
664
665   # create the output file.
666   problem_writer = cpxlp.ProblemWriter_cpxlp()
667   output_file = open(output_filename,"w")
668
669   problem_writer._output_prefixes = True # we always want prefixes
670
671   ################################################################################################
672   #### WRITE THE MASTER OBJECTIVE ################################################################
673   ################################################################################################
674
675   # write the objective for the master binding instance.
676   problem_writer._output_objectives = True
677   problem_writer._output_constraints = False
678   problem_writer._output_variables = False
679
680   print >>output_file, "\\ Begin objective block for master"
681   problem_writer._print_model_LP(master_binding_instance, output_file)
682   print >>output_file, "\\ End objective block for master"
683   print >>output_file, ""
684
685   ################################################################################################
686   #### WRITE THE CONSTRAINTS FOR THE MASTER MODEL AND ALL SCENARIO MODELS ########################
687   ################################################################################################
688
689   print >>output_file, "s.t."
690   print >>output_file, ""
691   
692   problem_writer._output_objectives = False
693   problem_writer._output_constraints = True
694   problem_writer._output_variables = False
695
696   print >>output_file, "\\ Begin constraint block for master"
697   problem_writer._print_model_LP(master_binding_instance, output_file)
698   print >>output_file, "\\ End constraint block for master",
699   print >>output_file, ""
700
701   for scenario_name in instances.keys():
702      instance = instances[scenario_name]
703      print >>output_file, "\\ Begin constraint block for scenario",scenario_name       
704      problem_writer._print_model_LP(instance, output_file)
705      print >>output_file, "\\ End constraint block for scenario",scenario_name
706      print >>output_file, ""
707
708   ################################################################################################
709   #### WRITE THE VARIABLES FOR THE MASTER MODEL AND ALL SCENARIO MODELS ##########################
710   ################################################################################################
711
712   # write the variables for the master binding instance, and then for each scenario.
713   print >>output_file, "bounds"
714   print >>output_file, ""
715   
716   problem_writer._output_objectives = False
717   problem_writer._output_constraints = False
718   problem_writer._output_variables = True
719
720   # first step: write variable bounds
721
722   problem_writer._output_continuous_variables = True
723   problem_writer._output_integer_variables = False
724   problem_writer._output_binary_variables = False
725
726   print >>output_file, "\\ Begin variable bounds block for master"
727   problem_writer._print_model_LP(master_binding_instance, output_file)
728   print >>output_file, "\\ End variable bounds block for master"
729   print >>output_file, ""
730
731   for scenario_name in instances.keys():
732      instance = instances[scenario_name]
733      print >>output_file, "\\ Begin variable bounds block for scenario",scenario_name
734      problem_writer._print_model_LP(instance, output_file)
735      print >>output_file, "\\ End variable bounds block for scenario",scenario_name
736      print >>output_file, ""
737
738   # second step: write integer indicators.
739
740   problem_writer._output_continuous_variables = False
741   problem_writer._output_integer_variables = True
742
743   if integers_present(master_binding_instance, instances) is True:
744
745      print >>output_file, "integer"
746      print >>output_file, ""
747
748      print >>output_file, "\\ Begin integer variable block for master"
749      problem_writer._print_model_LP(master_binding_instance, output_file)
750      print >>output_file, "\\ End integer variable block for master"
751      print >>output_file, ""
752   
753      for scenario_name in instances.keys():
754         instance = instances[scenario_name]
755         print >>output_file, "\\ Begin integer variable block for scenario",scenario_name
756         problem_writer._print_model_LP(instance, output_file)
757         print >>output_file, "\\ End integer variable block for scenario",scenario_name
758         print >>output_file, ""
759
760   # third step: write binary indicators.
761
762   problem_writer._output_integer_variables = False
763   problem_writer._output_binary_variables = True
764
765   if binaries_present(master_binding_instance, instances) is True:
766
767      print >>output_file, "binary"
768      print >>output_file, ""
769
770      print >>output_file, "\\ Begin binary variable block for master"
771      problem_writer._print_model_LP(master_binding_instance, output_file)
772      print >>output_file, "\\ End binary variable block for master"
773      print >>output_file, ""
774   
775      for scenario_name in instances.keys():
776         instance = instances[scenario_name]
777         print >>output_file, "\\ Begin binary variable block for scenario",scenario_name
778         problem_writer._print_model_LP(instance, output_file)
779         print >>output_file, "\\ End integer binary block for scenario",scenario_name
780         print >>output_file, ""
781
782   # wrap up.
783   print >>output_file, "end"
784
785   # clean up.
786   output_file.close()
787
788   print ""
789   print "Output file written to file=",output_filename
790
791   print ""
792   print "Done..."
793
794   end_time = time.time()
795
796   print ""
797   print "Total execution time=%8.2f seconds" %(end_time - start_time)
798   print ""
799
800def create_and_write_ef(scenario_tree, scenario_instances, output_filename):
801
802   start_time = time.time()
803
804   binding_instance = create_ef_instance(scenario_tree, scenario_instances, False, True)
805
806   ################################################################################################
807   #### WRITE THE COMPOSITE MODEL #################################################################
808   ################################################################################################
809
810   print ""
811   print "Starting to write extensive form"
812
813   # create the output file.
814   problem_writer = cpxlp.ProblemWriter_cpxlp()
815   output_file = open(output_filename,"w")
816
817   problem_writer._output_prefixes = True # we always want prefixes
818
819   ################################################################################################
820   #### WRITE THE MASTER OBJECTIVE ################################################################
821   ################################################################################################
822
823   # write the objective for the master binding instance.
824   problem_writer._output_objectives = True
825   problem_writer._output_constraints = False
826   problem_writer._output_variables = False
827
828   print >>output_file, "\\ Begin objective block for master"
829   problem_writer._print_model_LP(binding_instance, output_file)
830   print >>output_file, "\\ End objective block for master"
831   print >>output_file, ""
832
833   ################################################################################################
834   #### WRITE THE CONSTRAINTS FOR THE MASTER MODEL AND ALL SCENARIO MODELS ########################
835   ################################################################################################
836
837   print >>output_file, "s.t."
838   print >>output_file, ""
839   
840   problem_writer._output_objectives = False
841   problem_writer._output_constraints = True
842   problem_writer._output_variables = False
843
844   print >>output_file, "\\ Begin constraint block for master"
845   problem_writer._print_model_LP(binding_instance, output_file)
846   print >>output_file, "\\ End constraint block for master",
847   print >>output_file, ""
848
849   for scenario_name in scenario_instances.keys():
850      instance = scenario_instances[scenario_name]
851      print >>output_file, "\\ Begin constraint block for scenario",scenario_name       
852      problem_writer._print_model_LP(instance, output_file)
853      print >>output_file, "\\ End constraint block for scenario",scenario_name
854      print >>output_file, ""
855
856   ################################################################################################
857   #### WRITE THE VARIABLES FOR THE MASTER MODEL AND ALL SCENARIO MODELS ##########################
858   ################################################################################################
859
860   # write the variables for the master binding instance, and then for each scenario.
861   print >>output_file, "bounds"
862   print >>output_file, ""
863   
864   problem_writer._output_objectives = False
865   problem_writer._output_constraints = False
866   problem_writer._output_variables = True
867
868   # first step: write variable bounds
869
870   problem_writer._output_continuous_variables = True
871   problem_writer._output_integer_variables = False
872   problem_writer._output_binary_variables = False
873
874   print >>output_file, "\\ Begin variable bounds block for master"
875   problem_writer._print_model_LP(binding_instance, output_file)
876   print >>output_file, "\\ End variable bounds block for master"
877   print >>output_file, ""
878   
879   for scenario_name in scenario_instances.keys():
880      instance = scenario_instances[scenario_name]
881      print >>output_file, "\\ Begin variable bounds block for scenario",scenario_name
882      problem_writer._print_model_LP(instance, output_file)
883      print >>output_file, "\\ End variable bounds block for scenario",scenario_name
884      print >>output_file, ""
885
886   # second step: write integer indicators.
887
888   problem_writer._output_continuous_variables = False
889   problem_writer._output_integer_variables = True
890
891   if integers_present(binding_instance, scenario_instances) is True:
892
893      print >>output_file, "integer"
894      print >>output_file, ""
895
896      print >>output_file, "\\ Begin integer variable block for master"
897      problem_writer._print_model_LP(binding_instance, output_file)
898      print >>output_file, "\\ End integer variable block for master"
899      print >>output_file, ""
900   
901      for scenario_name in scenario_instances.keys():
902         instance = scenario_instances[scenario_name]
903         print >>output_file, "\\ Begin integer variable block for scenario",scenario_name
904         problem_writer._print_model_LP(instance, output_file)
905         print >>output_file, "\\ End integer variable block for scenario",scenario_name
906         print >>output_file, ""
907
908   # third step: write binary indicators.
909
910   problem_writer._output_integer_variables = False
911   problem_writer._output_binary_variables = True
912
913   if binaries_present(binding_instance, scenario_instances) is True:
914
915      print >>output_file, "binary"
916      print >>output_file, ""
917
918      print >>output_file, "\\ Begin binary variable block for master"
919      problem_writer._print_model_LP(binding_instance, output_file)
920      print >>output_file, "\\ End binary variable block for master"
921      print >>output_file, ""
922   
923      for scenario_name in scenario_instances.keys():
924         instance = scenario_instances[scenario_name]
925         print >>output_file, "\\ Begin binary variable block for scenario",scenario_name
926         problem_writer._print_model_LP(instance, output_file)
927         print >>output_file, "\\ End integer binary block for scenario",scenario_name
928         print >>output_file, ""
929
930   # wrap up.
931   print >>output_file, "end"
932
933   # clean up.
934   output_file.close()
935
936   print ""
937   print "Output file written to file=",output_filename
938
939   print ""
940   print "Done..."
941
942   end_time = time.time()
943
944   print ""
945   print "Total execution time=%8.2f seconds" %(end_time - start_time)
946   print ""   
Note: See TracBrowser for help on using the repository browser.