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

Last change on this file since 1768 was 1768, checked in by wehart, 11 years ago

Rework of Coopr to use the new PyUtilib? package decomposition.

NOTE: to use Coopr with this update, we need to work with a new version of coopr_install.

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