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

Last change on this file since 1774 was 1774, checked in by jwatson, 10 years ago

Adding some error-checking/diagnostic output to the PySP extensive form writer.

File size: 36.3 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# brain-dead utility for determing if there is a binary to write in the
18# composite model - need to know this, because CPLEX doesn't like empty
19# binary blocks in the LP file.
20def binaries_present(master_model, scenario_instances):
21
22   # check the master model first.
23   for var in master_model._component[_VarBase].values():
24      if isinstance(var.domain, BooleanSet):
25         return True
26
27   # scan the scenario instances next.
28   for scenario_name in scenario_instances.keys():
29      scenario_instance = scenario_instances[scenario_name]
30      for var in scenario_instance._component[_VarBase].values():
31         if isinstance(var.domain, BooleanSet):
32            return True
33
34   return False
35
36# brain-dead utility for determing if there is a binary to write in the
37# composite model - need to know this, because CPLEX doesn't like empty
38# integer blocks in the LP file.
39def integers_present(master_model, scenario_instances):
40
41   # check the master model first.
42   for var in master_model._component[_VarBase].values():
43      if isinstance(var.domain, IntegerSet):
44         return True
45
46   # scan the scenario instances next.
47   for scenario_name in scenario_instances.keys():
48      scenario_instance = scenario_instances[scenario_name]
49      for var in scenario_instance._component[_VarBase].values():
50         if isinstance(var.domain, IntegerSet):
51            return True
52
53   return False
54
55# the main extensive-form writer routine - including read of scenarios/etc.
56def write_ef_from_scratch(model_directory, instance_directory, output_filename):
57
58   start_time = time.time()
59
60   scenario_data_directory_name = instance_directory
61
62   print "Initializing extensive form writer"
63   print ""
64
65   ################################################################################################
66   #### INITIALIZATION ############################################################################
67   ################################################################################################
68   
69   #
70   # create and populate the core model
71   #
72   master_scenario_model = None
73   master_scenario_instance = None
74   
75   try:
76     
77      reference_model_filename = model_directory+os.sep+"ReferenceModel.py"   
78      modelimport = pyutilib.misc.import_file(reference_model_filename)
79      if "model" not in dir(modelimport):
80         print ""
81         print "Exiting ef module: No 'model' object created in module "+reference_model_filename
82         sys.exit(0)
83      if modelimport.model is None:
84         print ""
85         print "Exiting ef module: 'model' object equals 'None' in module "+reference_model_filename
86         sys.exit(0)
87   
88      master_scenario_model = modelimport.model
89
90   except IOError:
91     
92      print "***ERROR: Failed to load scenario reference model from file="+reference_model_filename
93      return
94
95   try:
96     
97      reference_scenario_filename = instance_directory+os.sep+"ReferenceModel.dat"
98      master_scenario_instance = master_scenario_model.create(reference_scenario_filename)
99     
100   except IOError:
101     
102      print "***ERROR: Failed to load scenario reference instance data from file="+reference_instance_filename
103      return           
104
105   #
106   # create and populate the scenario tree model
107   #
108
109   treeimport = pyutilib.misc.import_file(model_directory+os.sep+"ScenarioStructure.py")
110
111   tree_data = treeimport.model.create(instance_directory+os.sep+"ScenarioStructure.dat")
112
113   #
114   # construct the scenario tree
115   #
116   scenario_tree = ScenarioTree(model=master_scenario_instance,
117                                nodes=tree_data.Nodes,
118                                nodechildren=tree_data.Children,
119                                nodestages=tree_data.NodeStage,
120                                nodeprobabilities=tree_data.ConditionalProbability,
121                                stages=tree_data.Stages,
122                                stagevariables=tree_data.StageVariables,
123                                stagecostvariables=tree_data.StageCostVariable,
124                                scenarios=tree_data.Scenarios,
125                                scenarioleafs=tree_data.ScenarioLeafNode,
126                                scenariobaseddata=tree_data.ScenarioBasedData)
127
128   #
129   # print the input tree for validation/information purposes.
130   #
131   scenario_tree.pprint()
132
133   #
134   # validate the tree prior to doing anything serious
135   #
136   print ""
137   if scenario_tree.validate() is False:
138      print "***Scenario tree is invalid****"
139      sys.exit(1)
140   else:
141      print "Scenario tree is valid!"
142   print ""
143
144   #
145   # construct instances for each scenario
146   #
147
148   instances = {}
149   
150   if scenario_tree._scenario_based_data == 1:
151      print "Scenario-based instance initialization enabled"
152   else:
153      print "Node-based instance initialization enabled"
154         
155   for scenario in scenario_tree._scenarios:
156
157      scenario_instance = None
158
159      print "Creating instance for scenario=" + scenario._name
160
161      try:
162         if scenario_tree._scenario_based_data == 1:
163            scenario_data_filename = scenario_data_directory_name + os.sep + scenario._name + ".dat"
164#            print "Data for scenario=" + scenario._name + " loads from file=" + scenario_data_filename
165            scenario_instance = master_scenario_model.create(scenario_data_filename)
166         else:
167            scenario_instance = master_scenario_model.clone()
168            scenario_data = ModelData()
169            current_node = scenario._leaf_node
170            while current_node is not None:
171               node_data_filename = scenario_data_directory_name + os.sep + current_node._name + ".dat"
172#               print "Node data for scenario=" + scenario._name + " partially loading from file=" + node_data_filename
173               scenario_data.add_data_file(node_data_filename)
174               current_node = current_node._parent
175            scenario_data.read(model=scenario_instance)
176            scenario_instance._load_model_data(scenario_data)
177            scenario_instance.presolve()
178      except:
179         print "Encountered exception in model instance creation - traceback:"
180         traceback.print_exc()
181         raise RuntimeError, "Failed to create model instance for scenario=" + scenario._name
182
183      # name each instance with the scenario name, so the prefixes in the EF make sense.
184      scenario_instance.name = scenario._name
185     
186      scenario_instance.presolve()
187      instances[scenario._name] = scenario_instance
188
189   print ""
190
191   ################################################################################################
192   #### CREATE THE MASTER / BINDING INSTANCE ######################################################
193   ################################################################################################
194
195   master_binding_instance = Model()
196   master_binding_instance.name = "MASTER"
197
198   # walk the scenario tree - create variables representing the common values for all scenarios
199   # associated with that node. the constraints will be created later. also create expected-cost
200   # variables for each node, to be computed via constraints/objectives defined in a subsequent pass.
201   # master variables are created for all nodes but those in the last stage. expected cost variables
202   # are, for no particularly good reason other than easy coding, created for nodes in all stages.
203   print "Creating variables for master binding instance"
204
205   for stage in scenario_tree._stages:
206
207      for (stage_variable, index_template, stage_variable_indices) in stage._variables:
208
209         print "Creating master variable and blending constraints for decision variable=", stage_variable, ", indices=", stage_variable_indices
210
211         for tree_node in stage._tree_nodes:
212
213            if stage != scenario_tree._stages[-1]:     
214
215               master_variable_name = tree_node._name + "_" + stage_variable.name
216
217               # because there may be a single stage variable and multiple indices, check
218               # for the existence of the variable at this node - if you don't, you'll
219               # inadvertently over-write what was there previously!
220               master_variable = None
221               try:
222                  master_variable = getattr(master_binding_instance, master_variable_name)
223               except:
224                  # the deepcopy is probably too expensive (and unnecessary) computationally -
225                  # easier to just use the constructor with the stage variable index/bounds/etc.
226                  # NOTE: need to re-assign the master variables for each _varval - they probably
227                  #       point to a bogus model.
228                  new_master_variable = copy.deepcopy(stage_variable)
229                  new_master_variable.name = master_variable_name
230                  new_master_variable._model = master_binding_instance
231                  setattr(master_binding_instance, master_variable_name, new_master_variable)
232
233                  master_variable = new_master_variable
234
235               for index in stage_variable_indices:
236
237                  is_used = True # until proven otherwise                     
238                  for scenario in tree_node._scenarios:
239                     instance = instances[scenario._name]
240                     if getattr(instance,stage_variable.name)[index].status == VarStatus.unused:
241                        is_used = False
242
243                  is_fixed = False # until proven otherwise
244                  for scenario in tree_node._scenarios:
245                     instance = instances[scenario._name]
246                     if getattr(instance,stage_variable.name)[index].fixed is True:
247                        is_fixed = True
248
249                  if (is_used is True) and (is_fixed is False):
250                           
251                     # the following is necessary, specifically to get the name - deepcopy won't reset these attributes.
252                     # and because presolve/simplification is name-based, the names *have* to be different.
253                     master_variable[index].var = master_variable
254                     master_variable[index].name = tree_node._name + "_" + master_variable[index].name
255
256                     for scenario in tree_node._scenarios:
257
258                        scenario_instance = instances[scenario._name]
259                        scenario_variable = getattr(scenario_instance, stage_variable.name)
260                        new_constraint_name = scenario._name + "_" + master_variable_name + "_" + str(index)
261                        new_constraint = Constraint(name=new_constraint_name)
262                        new_expr = master_variable[index] - scenario_variable[index]
263                        new_constraint._initialize_constraint(None, (0.0, new_expr, 0.0), master_binding_instance, new_constraint_name)
264                        new_constraint._model = master_binding_instance
265                        setattr(master_binding_instance, new_constraint_name, new_constraint)
266
267            # create a variable to represent the expected cost at this node -
268            # the constraint to compute this comes later.
269            expected_cost_variable_name = "EXPECTED_COST_" + tree_node._name
270            expected_cost_variable = Var(name=expected_cost_variable_name)
271            expected_cost_variable._model = master_binding_instance
272            setattr(master_binding_instance, expected_cost_variable_name, expected_cost_variable)
273
274   master_binding_instance.presolve()
275
276   # ditto above for the (non-expected) cost variable.
277   for stage in scenario_tree._stages:
278
279      (cost_variable,cost_variable_index) = stage._cost_variable
280
281      print "Creating master variable and blending constraints for cost variable=", cost_variable, ", index=", cost_variable_index     
282
283      for tree_node in stage._tree_nodes:
284
285         new_cost_variable_name = tree_node._name + "_" + cost_variable.name
286
287         # TBD - the following is bad - check to see if it's already there (I suspect some of them are!!!)
288
289         # this is undoubtedly wasteful, in that a cost variable
290         # for each tree node is created with *all* indices.
291         new_cost_variable = copy.deepcopy(cost_variable)
292         new_cost_variable.name = new_cost_variable_name
293         new_cost_variable._model = master_binding_instance
294         setattr(master_binding_instance, new_cost_variable_name, new_cost_variable)
295
296         # the following is necessary, specifically to get the name - deepcopy won't reset these attributes.
297         new_cost_variable[cost_variable_index].var = new_cost_variable
298         if cost_variable_index is not None:
299            # if the variable index is None, the variable is derived from a VarValue, so the
300            # name gets updated automagically.
301            new_cost_variable[cost_variable_index].name = tree_node._name + "_" + new_cost_variable[cost_variable_index].name
302
303         for scenario in tree_node._scenarios:
304
305            scenario_instance = instances[scenario._name]
306            scenario_cost_variable = getattr(scenario_instance, cost_variable.name)
307            new_constraint_name = scenario._name + "_" + new_cost_variable_name + "_" + str(cost_variable_index)
308            new_constraint = Constraint(name=new_constraint_name)
309            new_expr = new_cost_variable[cost_variable_index] - scenario_cost_variable[cost_variable_index]
310            new_constraint._initialize_constraint(None, (0.0, new_expr, 0.0), master_binding_instance, new_constraint_name)
311            new_constraint._model = master_binding_instance
312            setattr(master_binding_instance, new_constraint_name, new_constraint)
313
314   # create the constraints for computing the master per-node cost variables,
315   # i.e., the current node cost and the expected cost of the child nodes.
316   # if the root, then the constraint is just the objective.
317
318   for stage in scenario_tree._stages:
319
320      (stage_cost_variable,stage_cost_variable_index) = stage._cost_variable
321
322      for tree_node in stage._tree_nodes:
323
324         node_expected_cost_variable_name = "EXPECTED_COST_" + tree_node._name
325         node_expected_cost_variable = getattr(master_binding_instance, node_expected_cost_variable_name)
326
327         node_cost_variable_name = tree_node._name + "_" + stage_cost_variable.name
328         node_cost_variable = getattr(master_binding_instance, node_cost_variable_name)                       
329           
330         constraint_expr = node_expected_cost_variable - node_cost_variable[stage_cost_variable_index]
331
332         for child_node in tree_node._children:
333
334            child_node_expected_cost_variable_name = "EXPECTED_COST_" + child_node._name
335            child_node_expected_cost_variable = getattr(master_binding_instance, child_node_expected_cost_variable_name)
336            constraint_expr = constraint_expr - (child_node._conditional_probability * child_node_expected_cost_variable)
337
338         new_constraint_name = "COST" + "_" + node_cost_variable_name + "_" + str(cost_variable_index)
339         new_constraint = Constraint(name=new_constraint_name)
340         new_constraint._initialize_constraint(None, (0.0, constraint_expr, 0.0), master_binding_instance, new_constraint_name)
341         new_constraint._model = master_binding_instance                     
342         setattr(master_binding_instance, new_constraint_name, new_constraint)
343
344         if tree_node._parent is None:
345
346            an_instance = instances[instances.keys()[0]]
347            an_objective = an_instance._component[Objective]
348            opt_sense = an_objective[an_objective.keys()[0]].sense
349
350            new_objective = Objective(name="MASTER", sense=opt_sense)
351            new_objective._data[None].expr = node_expected_cost_variable
352            setattr(master_binding_instance, "MASTER", new_objective)
353
354   master_binding_instance.presolve()
355
356   ################################################################################################
357   #### WRITE THE COMPOSITE MODEL #################################################################
358   ################################################################################################
359
360   print ""
361   print "Starting to write extensive form"
362
363   # create the output file.
364   problem_writer = cpxlp.ProblemWriter_cpxlp()
365   output_file = open(output_filename,"w")
366
367   problem_writer._output_prefixes = True # we always want prefixes
368
369   ################################################################################################
370   #### WRITE THE MASTER OBJECTIVE ################################################################
371   ################################################################################################
372
373   # write the objective for the master binding instance.
374   problem_writer._output_objectives = True
375   problem_writer._output_constraints = False
376   problem_writer._output_variables = False
377
378   print >>output_file, "\\ Begin objective block for master"
379   problem_writer._print_model_LP(master_binding_instance, output_file)
380   print >>output_file, "\\ End objective block for master"
381   print >>output_file, ""
382
383   ################################################################################################
384   #### WRITE THE CONSTRAINTS FOR THE MASTER MODEL AND ALL SCENARIO MODELS ########################
385   ################################################################################################
386
387   print >>output_file, "s.t."
388   print >>output_file, ""
389   
390   problem_writer._output_objectives = False
391   problem_writer._output_constraints = True
392   problem_writer._output_variables = False
393
394   print >>output_file, "\\ Begin constraint block for master"
395   problem_writer._print_model_LP(master_binding_instance, output_file)
396   print >>output_file, "\\ End constraint block for master",
397   print >>output_file, ""
398
399   for scenario_name in instances.keys():
400      instance = instances[scenario_name]
401      print >>output_file, "\\ Begin constraint block for scenario",scenario_name       
402      problem_writer._print_model_LP(instance, output_file)
403      print >>output_file, "\\ End constraint block for scenario",scenario_name
404      print >>output_file, ""
405
406   ################################################################################################
407   #### WRITE THE VARIABLES FOR THE MASTER MODEL AND ALL SCENARIO MODELS ##########################
408   ################################################################################################
409
410   # write the variables for the master binding instance, and then for each scenario.
411   print >>output_file, "bounds"
412   print >>output_file, ""
413   
414   problem_writer._output_objectives = False
415   problem_writer._output_constraints = False
416   problem_writer._output_variables = True
417
418   # first step: write variable bounds
419
420   problem_writer._output_continuous_variables = True
421   problem_writer._output_integer_variables = False
422   problem_writer._output_binary_variables = False
423
424   print >>output_file, "\\ Begin variable bounds block for master"
425   problem_writer._print_model_LP(master_binding_instance, output_file)
426   print >>output_file, "\\ End variable bounds block for master"
427   print >>output_file, ""
428
429   for scenario_name in instances.keys():
430      instance = instances[scenario_name]
431      print >>output_file, "\\ Begin variable bounds block for scenario",scenario_name
432      problem_writer._print_model_LP(instance, output_file)
433      print >>output_file, "\\ End variable bounds block for scenario",scenario_name
434      print >>output_file, ""
435
436   # second step: write integer indicators.
437
438   problem_writer._output_continuous_variables = False
439   problem_writer._output_integer_variables = True
440
441   if integers_present(master_binding_instance, instances) is True:
442
443      print >>output_file, "integer"
444      print >>output_file, ""
445
446      print >>output_file, "\\ Begin integer variable block for master"
447      problem_writer._print_model_LP(master_binding_instance, output_file)
448      print >>output_file, "\\ End integer variable block for master"
449      print >>output_file, ""
450   
451      for scenario_name in instances.keys():
452         instance = instances[scenario_name]
453         print >>output_file, "\\ Begin integer variable block for scenario",scenario_name
454         problem_writer._print_model_LP(instance, output_file)
455         print >>output_file, "\\ End integer variable block for scenario",scenario_name
456         print >>output_file, ""
457
458   # third step: write binary indicators.
459
460   problem_writer._output_integer_variables = False
461   problem_writer._output_binary_variables = True
462
463   if binaries_present(master_binding_instance, instances) is True:
464
465      print >>output_file, "binary"
466      print >>output_file, ""
467
468      print >>output_file, "\\ Begin binary variable block for master"
469      problem_writer._print_model_LP(master_binding_instance, output_file)
470      print >>output_file, "\\ End binary variable block for master"
471      print >>output_file, ""
472   
473      for scenario_name in instances.keys():
474         instance = instances[scenario_name]
475         print >>output_file, "\\ Begin binary variable block for scenario",scenario_name
476         problem_writer._print_model_LP(instance, output_file)
477         print >>output_file, "\\ End integer binary block for scenario",scenario_name
478         print >>output_file, ""
479
480   # wrap up.
481   print >>output_file, "end"
482
483   # clean up.
484   output_file.close()
485
486   print ""
487   print "Output file written to file=",output_filename
488
489   print ""
490   print "Done..."
491
492   end_time = time.time()
493
494   print ""
495   print "Total execution time=%8.2f seconds" %(end_time - start_time)
496   print ""
497
498def write_ef(scenario_tree, instances, output_filename):
499
500   start_time = time.time()
501
502   ################################################################################################
503   #### CREATE THE MASTER / BINDING INSTANCE ######################################################
504   ################################################################################################
505
506   master_binding_instance = Model()
507   master_binding_instance.name = "MASTER"
508
509   # walk the scenario tree - create variables representing the common values for all scenarios
510   # associated with that node. the constraints will be created later. also create expected-cost
511   # variables for each node, to be computed via constraints/objectives defined in a subsequent pass.
512   # master variables are created for all nodes but those in the last stage. expected cost variables
513   # are, for no particularly good reason other than easy coding, created for nodes in all stages.
514   print "Creating variables for master binding instance"
515
516   for stage in scenario_tree._stages:
517
518      for (stage_variable, index_template, stage_variable_indices) in stage._variables:
519
520         print "Creating master variable and blending constraints for decision variable=", stage_variable, ", indices=", index_template
521
522         for tree_node in stage._tree_nodes:
523
524            if stage != scenario_tree._stages[-1]:     
525
526               master_variable_name = tree_node._name + "_" + stage_variable.name
527
528               # because there may be a single stage variable and multiple indices, check
529               # for the existence of the variable at this node - if you don't, you'll
530               # inadvertently over-write what was there previously!
531               master_variable = None
532               try:
533                  master_variable = getattr(master_binding_instance, master_variable_name)
534               except:
535                  # the deepcopy is probably too expensive (and unnecessary) computationally -
536                  # easier to just use the constructor with the stage variable index/bounds/etc.
537                  # NOTE: need to re-assign the master variables for each _varval - they probably
538                  #       point to a bogus model.
539                  new_master_variable = copy.deepcopy(stage_variable)
540                  new_master_variable.name = master_variable_name
541                  new_master_variable._model = master_binding_instance
542                  setattr(master_binding_instance, master_variable_name, new_master_variable)
543
544                  master_variable = new_master_variable
545
546               for index in stage_variable_indices:
547
548                  is_used = True # until proven otherwise                     
549                  for scenario in tree_node._scenarios:
550                     instance = instances[scenario._name]
551                     if getattr(instance,stage_variable.name)[index].status == VarStatus.unused:
552                        is_used = False
553
554                  is_fixed = False # until proven otherwise
555                  for scenario in tree_node._scenarios:
556                     instance = instances[scenario._name]
557                     if getattr(instance,stage_variable.name)[index].fixed is True:
558                        is_fixed = True
559
560                  if (is_used is True) and (is_fixed is False):
561                           
562                     # the following is necessary, specifically to get the name - deepcopy won't reset these attributes.
563                     # and because presolve/simplification is name-based, the names *have* to be different.
564                     master_variable[index].var = master_variable
565                     master_variable[index].name = tree_node._name + "_" + master_variable[index].name
566
567                     for scenario in tree_node._scenarios:
568
569                        scenario_instance = instances[scenario._name]
570                        scenario_variable = getattr(scenario_instance, stage_variable.name)
571                        new_constraint_name = scenario._name + "_" + master_variable_name + "_" + str(index)
572                        new_constraint = Constraint(name=new_constraint_name)
573                        new_expr = master_variable[index] - scenario_variable[index]
574                        new_constraint._initialize_constraint(None, (0.0, new_expr, 0.0), master_binding_instance, new_constraint_name)
575                        new_constraint._model = master_binding_instance
576                        setattr(master_binding_instance, new_constraint_name, new_constraint)
577
578            # create a variable to represent the expected cost at this node -
579            # the constraint to compute this comes later.
580            expected_cost_variable_name = "EXPECTED_COST_" + tree_node._name
581            expected_cost_variable = Var(name=expected_cost_variable_name)
582            expected_cost_variable._model = master_binding_instance
583            setattr(master_binding_instance, expected_cost_variable_name, expected_cost_variable)
584
585   master_binding_instance.presolve()
586
587   # ditto above for the (non-expected) cost variable.
588   for stage in scenario_tree._stages:
589
590      (cost_variable,cost_variable_index) = stage._cost_variable
591
592      print "Creating master variable and blending constraints for cost variable=", cost_variable, ", index=", cost_variable_index     
593
594      for tree_node in stage._tree_nodes:
595
596         new_cost_variable_name = tree_node._name + "_" + cost_variable.name
597
598         # TBD - the following is bad - check to see if it's already there (I suspect some of them are!!!)
599
600         # this is undoubtedly wasteful, in that a cost variable
601         # for each tree node is created with *all* indices.
602         new_cost_variable = copy.deepcopy(cost_variable)
603         new_cost_variable.name = new_cost_variable_name
604         new_cost_variable._model = master_binding_instance
605         setattr(master_binding_instance, new_cost_variable_name, new_cost_variable)
606
607         # the following is necessary, specifically to get the name - deepcopy won't reset these attributes.
608         new_cost_variable[cost_variable_index].var = new_cost_variable
609         if cost_variable_index is not None:
610            # if the variable index is None, the variable is derived from a VarValue, so the
611            # name gets updated automagically.
612            new_cost_variable[cost_variable_index].name = tree_node._name + "_" + new_cost_variable[cost_variable_index].name
613
614         for scenario in tree_node._scenarios:
615
616            scenario_instance = instances[scenario._name]
617            scenario_cost_variable = getattr(scenario_instance, cost_variable.name)
618            new_constraint_name = scenario._name + "_" + new_cost_variable_name + "_" + str(cost_variable_index)
619            new_constraint = Constraint(name=new_constraint_name)
620            new_expr = new_cost_variable[cost_variable_index] - scenario_cost_variable[cost_variable_index]
621            new_constraint._initialize_constraint(None, (0.0, new_expr, 0.0), master_binding_instance, new_constraint_name)
622            new_constraint._model = master_binding_instance
623            setattr(master_binding_instance, new_constraint_name, new_constraint)
624
625   # create the constraints for computing the master per-node cost variables,
626   # i.e., the current node cost and the expected cost of the child nodes.
627   # if the root, then the constraint is just the objective.
628
629   for stage in scenario_tree._stages:
630
631      (stage_cost_variable,stage_cost_variable_index) = stage._cost_variable
632
633      for tree_node in stage._tree_nodes:
634
635         node_expected_cost_variable_name = "EXPECTED_COST_" + tree_node._name
636         node_expected_cost_variable = getattr(master_binding_instance, node_expected_cost_variable_name)
637
638         node_cost_variable_name = tree_node._name + "_" + stage_cost_variable.name
639         node_cost_variable = getattr(master_binding_instance, node_cost_variable_name)                       
640           
641         constraint_expr = node_expected_cost_variable - node_cost_variable[stage_cost_variable_index]
642
643         for child_node in tree_node._children:
644
645            child_node_expected_cost_variable_name = "EXPECTED_COST_" + child_node._name
646            child_node_expected_cost_variable = getattr(master_binding_instance, child_node_expected_cost_variable_name)
647            constraint_expr = constraint_expr - (child_node._conditional_probability * child_node_expected_cost_variable)
648
649         new_constraint_name = "COST" + "_" + node_cost_variable_name + "_" + str(cost_variable_index)
650         new_constraint = Constraint(name=new_constraint_name)
651         new_constraint._initialize_constraint(None, (0.0, constraint_expr, 0.0), master_binding_instance, new_constraint_name)
652         new_constraint._model = master_binding_instance                     
653         setattr(master_binding_instance, new_constraint_name, new_constraint)
654
655         if tree_node._parent is None:
656
657            an_instance = instances[instances.keys()[0]]
658            an_objective = an_instance._component[Objective]
659            opt_sense = an_objective[an_objective.keys()[0]].sense
660
661            new_objective = Objective(name="MASTER", sense=opt_sense)
662            new_objective._data[None].expr = node_expected_cost_variable
663            setattr(master_binding_instance, "MASTER", new_objective)
664
665   master_binding_instance.presolve()
666
667   ################################################################################################
668   #### WRITE THE COMPOSITE MODEL #################################################################
669   ################################################################################################
670
671   print ""
672   print "Starting to write extensive form"
673
674   # create the output file.
675   problem_writer = cpxlp.ProblemWriter_cpxlp()
676   output_file = open(output_filename,"w")
677
678   problem_writer._output_prefixes = True # we always want prefixes
679
680   ################################################################################################
681   #### WRITE THE MASTER OBJECTIVE ################################################################
682   ################################################################################################
683
684   # write the objective for the master binding instance.
685   problem_writer._output_objectives = True
686   problem_writer._output_constraints = False
687   problem_writer._output_variables = False
688
689   print >>output_file, "\\ Begin objective block for master"
690   problem_writer._print_model_LP(master_binding_instance, output_file)
691   print >>output_file, "\\ End objective block for master"
692   print >>output_file, ""
693
694   ################################################################################################
695   #### WRITE THE CONSTRAINTS FOR THE MASTER MODEL AND ALL SCENARIO MODELS ########################
696   ################################################################################################
697
698   print >>output_file, "s.t."
699   print >>output_file, ""
700   
701   problem_writer._output_objectives = False
702   problem_writer._output_constraints = True
703   problem_writer._output_variables = False
704
705   print >>output_file, "\\ Begin constraint block for master"
706   problem_writer._print_model_LP(master_binding_instance, output_file)
707   print >>output_file, "\\ End constraint block for master",
708   print >>output_file, ""
709
710   for scenario_name in instances.keys():
711      instance = instances[scenario_name]
712      print >>output_file, "\\ Begin constraint block for scenario",scenario_name       
713      problem_writer._print_model_LP(instance, output_file)
714      print >>output_file, "\\ End constraint block for scenario",scenario_name
715      print >>output_file, ""
716
717   ################################################################################################
718   #### WRITE THE VARIABLES FOR THE MASTER MODEL AND ALL SCENARIO MODELS ##########################
719   ################################################################################################
720
721   # write the variables for the master binding instance, and then for each scenario.
722   print >>output_file, "bounds"
723   print >>output_file, ""
724   
725   problem_writer._output_objectives = False
726   problem_writer._output_constraints = False
727   problem_writer._output_variables = True
728
729   # first step: write variable bounds
730
731   problem_writer._output_continuous_variables = True
732   problem_writer._output_integer_variables = False
733   problem_writer._output_binary_variables = False
734
735   print >>output_file, "\\ Begin variable bounds block for master"
736   problem_writer._print_model_LP(master_binding_instance, output_file)
737   print >>output_file, "\\ End variable bounds block for master"
738   print >>output_file, ""
739   
740   for scenario_name in instances.keys():
741      instance = instances[scenario_name]
742      print >>output_file, "\\ Begin variable bounds block for scenario",scenario_name
743      problem_writer._print_model_LP(instance, output_file)
744      print >>output_file, "\\ End variable bounds block for scenario",scenario_name
745      print >>output_file, ""
746
747   # second step: write integer indicators.
748
749   problem_writer._output_continuous_variables = False
750   problem_writer._output_integer_variables = True
751
752   if integers_present(master_binding_instance, instances) is True:
753
754      print >>output_file, "integer"
755      print >>output_file, ""
756
757      print >>output_file, "\\ Begin integer variable block for master"
758      problem_writer._print_model_LP(master_binding_instance, output_file)
759      print >>output_file, "\\ End integer variable block for master"
760      print >>output_file, ""
761   
762      for scenario_name in instances.keys():
763         instance = instances[scenario_name]
764         print >>output_file, "\\ Begin integer variable block for scenario",scenario_name
765         problem_writer._print_model_LP(instance, output_file)
766         print >>output_file, "\\ End integer variable block for scenario",scenario_name
767         print >>output_file, ""
768
769   # third step: write binary indicators.
770
771   problem_writer._output_integer_variables = False
772   problem_writer._output_binary_variables = True
773
774   if binaries_present(master_binding_instance, instances) is True:
775
776      print >>output_file, "binary"
777      print >>output_file, ""
778
779      print >>output_file, "\\ Begin binary variable block for master"
780      problem_writer._print_model_LP(master_binding_instance, output_file)
781      print >>output_file, "\\ End binary variable block for master"
782      print >>output_file, ""
783   
784      for scenario_name in instances.keys():
785         instance = instances[scenario_name]
786         print >>output_file, "\\ Begin binary variable block for scenario",scenario_name
787         problem_writer._print_model_LP(instance, output_file)
788         print >>output_file, "\\ End integer binary block for scenario",scenario_name
789         print >>output_file, ""
790
791   # wrap up.
792   print >>output_file, "end"
793
794   # clean up.
795   output_file.close()
796
797   print ""
798   print "Output file written to file=",output_filename
799
800   print ""
801   print "Done..."
802
803   end_time = time.time()
804
805   print ""
806   print "Total execution time=%8.2f seconds" %(end_time - start_time)
807   print ""   
Note: See TracBrowser for help on using the repository browser.