Changeset 2418


Ignore:
Timestamp:
Mar 11, 2010 5:49:52 PM (9 years ago)
Author:
jwatson
Message:

More restructuring and simplification of the PySP extensive writer code, which is now rather compact.

Location:
coopr.pysp/trunk/coopr/pysp
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • coopr.pysp/trunk/coopr/pysp/ef.py

    r2414 r2418  
    6868#
    6969
    70 def create_ef_instance(scenario_tree, scenario_instances, generate_weighted_cvar, verbose_output):
     70def create_ef_instance(scenario_tree, scenario_instances,
     71                       verbose_output = False,
     72                       generate_weighted_cvar = False, cvar_weight = None, risk_alpha = None):
     73
     74   #
     75   # validate cvar options, if specified.
     76   #
     77   if generate_weighted_cvar is True:
     78      if (cvar_weight is None) or (cvar_weight <= 0.0):
     79         raise RuntimeError, "Weight of CVaR term must be >= 0.0 - value supplied="+str(cvar_weight)
     80      if (risk_alpha is None) or (risk_alpha <= 0.0) or (risk_alpha >= 1.0):
     81         raise RuntimeError, "CVaR risk alpha must be between 0 and 1, exclusive - value supplied="+str(risk_alpha)
     82
     83      if verbose_output is True:
     84         print "Writing CVaR weighted objective"
     85         print "CVaR term weight="+str(cvar_weight)
     86         print "CVaR alpha="+str(risk_alpha)
     87         print ""
     88
     89   #
     90   # create the new and empty binding instance.
     91   #
    7192
    7293   binding_instance = Model()
     
    86107
    87108         if verbose_output is True:
    88             print "Creating master variable and blending constraints for decision variable=", stage_variable, ", indices=", index_template
     109            print "Creating master variable and blending constraints for decision variable="+stage_variable.name+", indices="+str(index_template)
    89110
    90111         for tree_node in stage._tree_nodes:
     
    109130                  new_master_variable.construct()
    110131                  new_master_variable._model = binding_instance
    111                   setattr(master_binding_instance, master_variable_name, new_master_variable)
     132                  setattr(binding_instance, master_variable_name, new_master_variable)
    112133
    113134                  master_variable = new_master_variable
     
    142163                        new_expr = master_variable[index] - scenario_variable[index]
    143164                        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)
     165                        new_constraint._model = binding_instance
     166                        setattr(binding_instance, new_constraint_name, new_constraint)
    146167
    147168            # create a variable to represent the expected cost at this node -
     
    149170            expected_cost_variable_name = "EXPECTED_COST_" + tree_node._name
    150171            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()
     172            expected_cost_variable._model = binding_instance
     173            setattr(binding_instance, expected_cost_variable_name, expected_cost_variable)
     174
     175   # if we're generating the weighted CVaR objective term, create the
     176   # corresponding variable and the master CVaR eta variable.
     177   if generate_weighted_cvar is True:
     178
     179      root_node = scenario_tree._stages[0]._tree_nodes[0]
     180     
     181      cvar_cost_variable_name = "CVAR_COST_" + root_node._name
     182      cvar_cost_variable = Var(name=cvar_cost_variable_name)
     183      setattr(binding_instance, cvar_cost_variable_name, cvar_cost_variable)
     184      cvar_cost_variable.construct()
     185
     186      cvar_eta_variable_name = "CVAR_ETA_" + root_node._name
     187      cvar_eta_variable = Var(name=cvar_eta_variable_name)
     188      setattr(binding_instance, cvar_eta_variable_name, cvar_eta_variable)     
     189      cvar_eta_variable.construct()
     190
     191   binding_instance.preprocess()
    155192
    156193   # ditto above for the (non-expected) cost variable.
     
    159196      (cost_variable,cost_variable_index) = stage._cost_variable
    160197
    161       if verbose_output:
    162          print "Creating master variable and blending constraints for cost variable=", cost_variable, ", index=", cost_variable_index     
     198      print "Creating master variable and blending constraints for cost variable="+cost_variable.name+", index="+str(cost_variable_index)
    163199
    164200      for tree_node in stage._tree_nodes:
    165201
    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!!!)
     202         # TBD - the following is bad - check to see if it's already there (I suspect some of them are!!!)         
    169203
    170204         # this is undoubtedly wasteful, in that a cost variable
    171          # for each tree node is created with *all* indices.
     205         # for each tree node is created with *all* indices.          
    172206         new_cost_variable_name = tree_node._name + "_" + cost_variable.name
    173207         new_cost_variable_index = cost_variable._index
     
    176210            new_cost_variable = Var(name=new_cost_variable_name)
    177211         else:
    178             new_cost_variable = Var(new_cost_variable_index, new_cost_variable_name)
     212            new_cost_variable = Var(new_cost_variable_index, name=new_cost_variable_name)
    179213         new_cost_variable.construct()
    180          new_cost_variable._model = master_binding_instance
    181          setattr(master_binding_instance, new_cost_variable_name, new_cost_variable)                  
     214         new_cost_variable._model = binding_instance
     215         setattr(binding_instance, new_cost_variable_name, new_cost_variable)         
    182216
    183217         # the following is necessary, specifically to get the name - deepcopy won't reset these attributes.
     
    196230            new_expr = new_cost_variable[cost_variable_index] - scenario_cost_variable[cost_variable_index]
    197231            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)
     232            new_constraint._model = binding_instance
     233            setattr(binding_instance, new_constraint_name, new_constraint)
    200234
    201235   # create the constraints for computing the master per-node cost variables,
     
    210244
    211245         node_expected_cost_variable_name = "EXPECTED_COST_" + tree_node._name
    212          node_expected_cost_variable = getattr(master_binding_instance, node_expected_cost_variable_name)
     246         node_expected_cost_variable = getattr(binding_instance, node_expected_cost_variable_name)
    213247
    214248         node_cost_variable_name = tree_node._name + "_" + stage_cost_variable.name
    215          node_cost_variable = getattr(master_binding_instance, node_cost_variable_name)                       
     249         node_cost_variable = getattr(binding_instance, node_cost_variable_name)                       
    216250           
    217251         constraint_expr = node_expected_cost_variable - node_cost_variable[stage_cost_variable_index]
     
    220254
    221255            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)
     256            child_node_expected_cost_variable = getattr(binding_instance, child_node_expected_cost_variable_name)
    223257            constraint_expr = constraint_expr - (child_node._conditional_probability * child_node_expected_cost_variable)
    224258
     
    226260         new_constraint = Constraint(name=new_constraint_name)
    227261         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)
     262         new_constraint._model = binding_instance                     
     263         setattr(binding_instance, new_constraint_name, new_constraint)
    230264
    231265         if tree_node._parent is None:
     
    235269            opt_sense = an_objective[an_objective.keys()[0]].sense
    236270
     271            opt_expression = node_expected_cost_variable
     272
     273            if generate_weighted_cvar is True:
     274               cvar_cost_variable_name = "CVAR_COST_" + tree_node._name
     275               cvar_cost_variable = getattr(binding_instance, cvar_cost_variable_name)
     276               opt_expression += cvar_weight * cvar_cost_variable           
     277
    237278            new_objective = Objective(name="MASTER", sense=opt_sense)
    238279            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
     280            setattr(binding_instance, "MASTER", new_objective)
     281
     282   # CVaR requires the addition of a variable per scenario to represent the cost excess,
     283   # and a constraint to compute the cost excess relative to eta. we also replicate (following
     284   # what we do for node cost variables) an eta variable for each scenario instance, and
     285   # require equality with the master eta variable via constraints.
     286   if generate_weighted_cvar is True:
     287     
     288      root_node = scenario_tree._stages[0]._tree_nodes[0]
     289
     290      master_cvar_eta_variable_name = "CVAR_ETA_" + root_node._name
     291      master_cvar_eta_variable = getattr(binding_instance, master_cvar_eta_variable_name)
     292     
     293      for scenario_name in scenario_instances.keys():
     294         scenario_instance = scenario_instances[scenario_name]
     295
     296         # unique names are required because the presolve isn't
     297         # aware of the "owning" models for variables.
     298         cvar_excess_variable_name = "CVAR_EXCESS_"+scenario_name
     299         cvar_excess_variable = Var(name=cvar_excess_variable_name, domain=NonNegativeReals)
     300         setattr(scenario_instance, cvar_excess_variable_name, cvar_excess_variable)
     301         cvar_excess_variable.construct()
     302
     303         cvar_eta_variable_name = "CVAR_ETA"
     304         cvar_eta_variable = Var(name=cvar_eta_variable_name)
     305         setattr(scenario_instance, cvar_eta_variable_name, cvar_eta_variable)
     306         cvar_eta_variable.construct()
     307
     308         compute_excess_constraint_name = "COMPUTE_SCENARIO_EXCESS"
     309         compute_excess_constraint = Constraint(name=compute_excess_constraint_name)
     310         compute_excess_expression = cvar_excess_variable
     311         for node in scenario_tree._scenario_map[scenario_name]._node_list:
     312            (cost_variable, cost_variable_idx) = node._stage._cost_variable
     313            compute_excess_expression -= getattr(scenario_instance, cost_variable.name)[cost_variable_idx]
     314         compute_excess_expression += cvar_eta_variable
     315         compute_excess_constraint.add(None, (0.0, compute_excess_expression, None))
     316         compute_excess_constraint._model = scenario_instance
     317         setattr(scenario_instance, compute_excess_constraint_name, compute_excess_constraint)
     318
     319         eta_equality_constraint_name = "MASTER_ETA_EQUALITY_WITH_" + scenario_instance.name
     320         eta_equality_constraint = Constraint(name=eta_equality_constraint_name)
     321         eta_equality_expr = master_cvar_eta_variable - cvar_eta_variable
     322         eta_equality_constraint.add(None, (0.0, eta_equality_expr, 0.0))
     323         eta_equality_constraint._model = binding_instance
     324         setattr(binding_instance, eta_equality_constraint_name, eta_equality_constraint)
     325
     326      # add the constraint to compute the master CVaR variable value. iterate
     327      # over scenario instances to create the expected excess component first.
     328      cvar_cost_variable_name = "CVAR_COST_" + root_node._name
     329      cvar_cost_variable = getattr(binding_instance, cvar_cost_variable_name)
     330      cvar_eta_variable_name = "CVAR_ETA_" + root_node._name
     331      cvar_eta_variable = getattr(binding_instance, cvar_eta_variable_name)
     332     
     333      cvar_cost_expression = cvar_cost_variable - cvar_eta_variable
     334     
     335      for scenario_name in scenario_instances.keys():
     336         scenario_instance = scenario_instances[scenario_name]
     337         scenario_probability = scenario_tree._scenario_map[scenario_name]._probability
     338
     339         scenario_excess_variable_name = "CVAR_EXCESS_"+scenario_name
     340         scenario_excess_variable = getattr(scenario_instance, scenario_excess_variable_name)
     341
     342         cvar_cost_expression = cvar_cost_expression - (scenario_probability * scenario_excess_variable) / (1.0 - risk_alpha)
     343
     344      compute_cvar_cost_constraint_name = "COMPUTE_CVAR_COST"
     345      compute_cvar_cost_constraint = Constraint(name=compute_cvar_cost_constraint_name)
     346      compute_cvar_cost_constraint.add(None, (0.0, cvar_cost_expression, 0.0))
     347      compute_cvar_cost_constraint._model = binding_instance
     348      setattr(binding_instance, compute_cvar_cost_constraint_name, compute_cvar_cost_constraint)
     349
     350   # after mucking with instances, presolve to collect terms required prior to output.         
     351   # IMPT: Do the scenario instances first, as the master depends on variables in the scenarios.
     352   for scenario_name in scenario_instances.keys():
     353      scenario_instance = scenario_instances[scenario_name]   
     354      scenario_instance.preprocess()               
     355
     356   binding_instance.preprocess()
     357
     358   return binding_instance
     359
     360#
     361# write the EF binding instance and all sub-instances. currently only outputs the CPLEX LP file format.
     362#
     363
     364def write_ef(binding_instance, scenario_instances, output_filename):
     365
     366   # create the output file.
     367   problem_writer = cpxlp.ProblemWriter_cpxlp()
     368   output_file = open(output_filename,"w")
     369
     370   problem_writer._output_prefixes = True # we always want prefixes
     371
     372   ################################################################################################
     373   #### WRITE THE MASTER OBJECTIVE ################################################################
     374   ################################################################################################
     375
     376   # write the objective for the master binding instance.
     377   problem_writer._output_objectives = True
     378   problem_writer._output_constraints = False
     379   problem_writer._output_variables = False
     380
     381   print >>output_file, "\\ Begin objective block for master"
     382   problem_writer._print_model_LP(binding_instance, output_file)
     383   print >>output_file, "\\ End objective block for master"
     384   print >>output_file, ""
     385
     386   ################################################################################################
     387   #### WRITE THE CONSTRAINTS FOR THE MASTER MODEL AND ALL SCENARIO MODELS ########################
     388   ################################################################################################
     389
     390   print >>output_file, "s.t."
     391   print >>output_file, ""
     392   
     393   problem_writer._output_objectives = False
     394   problem_writer._output_constraints = True
     395   problem_writer._output_variables = False
     396
     397   print >>output_file, "\\ Begin constraint block for master"
     398   problem_writer._print_model_LP(binding_instance, output_file)
     399   print >>output_file, "\\ End constraint block for master",
     400   print >>output_file, ""
     401
     402   for scenario_name in scenario_instances.keys():
     403      instance = scenario_instances[scenario_name]
     404      print >>output_file, "\\ Begin constraint block for scenario",scenario_name       
     405      problem_writer._print_model_LP(instance, output_file)
     406      print >>output_file, "\\ End constraint block for scenario",scenario_name
     407      print >>output_file, ""
     408
     409   ################################################################################################
     410   #### WRITE THE VARIABLES FOR THE MASTER MODEL AND ALL SCENARIO MODELS ##########################
     411   ################################################################################################
     412
     413   # write the variables for the master binding instance, and then for each scenario.
     414   print >>output_file, "bounds"
     415   print >>output_file, ""
     416   
     417   problem_writer._output_objectives = False
     418   problem_writer._output_constraints = False
     419   problem_writer._output_variables = True
     420
     421   # first step: write variable bounds
     422
     423   problem_writer._output_continuous_variables = True
     424   problem_writer._output_integer_variables = False
     425   problem_writer._output_binary_variables = False
     426
     427   print >>output_file, "\\ Begin variable bounds block for master"
     428   problem_writer._print_model_LP(binding_instance, output_file)
     429   print >>output_file, "\\ End variable bounds block for master"
     430   print >>output_file, ""
     431   
     432   for scenario_name in scenario_instances.keys():
     433      instance = scenario_instances[scenario_name]
     434      print >>output_file, "\\ Begin variable bounds block for scenario",scenario_name
     435      problem_writer._print_model_LP(instance, output_file)
     436      print >>output_file, "\\ End variable bounds block for scenario",scenario_name
     437      print >>output_file, ""
     438
     439   # second step: write integer indicators.
     440
     441   problem_writer._output_continuous_variables = False
     442   problem_writer._output_integer_variables = True
     443
     444   if integers_present(binding_instance, scenario_instances) is True:
     445
     446      print >>output_file, "integer"
     447      print >>output_file, ""
     448
     449      print >>output_file, "\\ Begin integer variable block for master"
     450      problem_writer._print_model_LP(binding_instance, output_file)
     451      print >>output_file, "\\ End integer variable block for master"
     452      print >>output_file, ""
     453   
     454      for scenario_name in scenario_instances.keys():
     455         instance = scenario_instances[scenario_name]
     456         print >>output_file, "\\ Begin integer variable block for scenario",scenario_name
     457         problem_writer._print_model_LP(instance, output_file)
     458         print >>output_file, "\\ End integer variable block for scenario",scenario_name
     459         print >>output_file, ""
     460
     461   # third step: write binary indicators.
     462
     463   problem_writer._output_integer_variables = False
     464   problem_writer._output_binary_variables = True
     465
     466   if binaries_present(binding_instance, scenario_instances) is True:
     467
     468      print >>output_file, "binary"
     469      print >>output_file, ""
     470
     471      print >>output_file, "\\ Begin binary variable block for master"
     472      problem_writer._print_model_LP(binding_instance, output_file)
     473      print >>output_file, "\\ End binary variable block for master"
     474      print >>output_file, ""
     475   
     476      for scenario_name in scenario_instances.keys():
     477         instance = scenario_instances[scenario_name]
     478         print >>output_file, "\\ Begin binary variable block for scenario",scenario_name
     479         problem_writer._print_model_LP(instance, output_file)
     480         print >>output_file, "\\ End integer binary block for scenario",scenario_name
     481         print >>output_file, ""
     482
     483   # wrap up.
     484   print >>output_file, "end"
     485
     486   # clean up.
     487   output_file.close()
     488   
    244489
    245490#
     
    255500   scenario_data_directory_name = instance_directory
    256501
    257    print "Initializing extensive form writer"
    258    print ""
    259 
    260    ################################################################################################
    261    #### INITIALIZATION ############################################################################
    262    ################################################################################################
    263 
    264    #
    265    # validate cvar options, if specified.
    266    #
    267    if generate_weighted_cvar is True:
    268       if cvar_weight <= 0.0:
    269          raise RuntimeError, "Weight of CVaR term must be >= 0.0 - value supplied="+str(cvar_weight)
    270       if (risk_alpha <= 0.0) or (risk_alpha >= 1.0):
    271          raise RuntimeError, "CVaR risk alpha must be between 0 and 1, exclusive - value supplied="+str(risk_alpha)
    272 
    273       print "Writing CVaR weighted objective"
    274       print "CVaR term weight="+str(cvar_weight)
    275       print "CVaR alpha="+str(risk_alpha)
     502   if verbose_output is True:
     503      print "Initializing extensive form writer"
    276504      print ""
    277    
     505
    278506   #
    279507   # create and populate the core model
     
    340568      sys.exit(1)
    341569   else:
    342       print "Scenario tree is valid!"
     570      if verbose_output is True:
     571         print "Scenario tree is valid!"
    343572   print ""
    344573
     
    347576   #
    348577
    349    instances = {}
     578   scenario_instances = {}
    350579   
    351580   if scenario_tree._scenario_based_data == 1:
    352       print "Scenario-based instance initialization enabled"
     581      if verbose_output is True:
     582         print "Scenario-based instance initialization enabled"
    353583   else:
    354       print "Node-based instance initialization enabled"
     584      if verbose_output is True:
     585         print "Node-based instance initialization enabled"
    355586         
    356587   for scenario in scenario_tree._scenarios:
     
    363594         if scenario_tree._scenario_based_data == 1:
    364595            scenario_data_filename = scenario_data_directory_name + os.sep + scenario._name + ".dat"
    365 #            print "Data for scenario=" + scenario._name + " loads from file=" + scenario_data_filename
    366596            scenario_instance = master_scenario_model.create(scenario_data_filename)
    367597         else:
     
    371601            while current_node is not None:
    372602               node_data_filename = scenario_data_directory_name + os.sep + current_node._name + ".dat"
    373 #               print "Node data for scenario=" + scenario._name + " partially loading from file=" + node_data_filename
    374603               scenario_data.add(node_data_filename)
    375604               current_node = current_node._parent
     
    386615     
    387616      scenario_instance.preprocess()
    388       instances[scenario._name] = scenario_instance
    389 
    390    print ""
    391 
    392    ################################################################################################
    393    #### CREATE THE MASTER / BINDING INSTANCE ######################################################
    394    ################################################################################################
    395 
    396    master_binding_instance = Model()
    397    master_binding_instance.name = "MASTER"
    398 
    399    # walk the scenario tree - create variables representing the common values for all scenarios
    400    # associated with that node. the constraints will be created later. also create expected-cost
    401    # variables for each node, to be computed via constraints/objectives defined in a subsequent pass.
    402    # master variables are created for all nodes but those in the last stage. expected cost variables
    403    # are, for no particularly good reason other than easy coding, created for nodes in all stages.
    404    print "Creating variables for master binding instance"
    405 
    406    for stage in scenario_tree._stages:
    407 
    408       for (stage_variable, index_template, stage_variable_indices) in stage._variables:
    409 
    410          print "Creating master variable and blending constraints for decision variable="+stage_variable.name+", indices="+str(stage_variable_indices)
    411 
    412          for tree_node in stage._tree_nodes:
    413 
    414             if stage != scenario_tree._stages[-1]:     
    415 
    416                master_variable_name = tree_node._name + "_" + stage_variable.name
    417 
    418                # because there may be a single stage variable and multiple indices, check
    419                # for the existence of the variable at this node - if you don't, you'll
    420                # inadvertently over-write what was there previously!
    421                master_variable = None
    422                try:
    423                   master_variable = getattr(master_binding_instance, master_variable_name)
    424                except:
    425                   new_master_variable_index = stage_variable._index
    426                   new_master_variable = None
    427                   if (len(new_master_variable_index) is 1) and (None in new_master_variable_index):
    428                      new_master_variable = Var(name=stage_variable.name)
    429                   else:
    430                      new_master_variable = Var(new_master_variable_index, name=stage_variable.name)
    431                   new_master_variable.construct()
    432                   new_master_variable._model = master_binding_instance
    433                   setattr(master_binding_instance, master_variable_name, new_master_variable)
    434 
    435                   # TBD - TECHNICALLY, WE NEED TO COPY BOUNDS - BUT WE REALLY DON'T, AS THEY ARE ON THE PER-INSTNACE VARS!
    436 
    437                   master_variable = new_master_variable
    438 
    439                for index in stage_variable_indices:
    440 
    441                   is_used = True # until proven otherwise                     
    442                   for scenario in tree_node._scenarios:
    443                      instance = instances[scenario._name]
    444                      if getattr(instance,stage_variable.name)[index].status == VarStatus.unused:
    445                         is_used = False
    446 
    447                   is_fixed = False # until proven otherwise
    448                   for scenario in tree_node._scenarios:
    449                      instance = instances[scenario._name]
    450                      if getattr(instance,stage_variable.name)[index].fixed is True:
    451                         is_fixed = True
    452 
    453                   if (is_used is True) and (is_fixed is False):
    454                            
    455                      # the following is necessary, specifically to get the name - deepcopy won't reset these attributes.
    456                      # and because presolve/simplification is name-based, the names *have* to be different.
    457                      master_variable[index].var = master_variable
    458                      master_variable[index].name = tree_node._name + "_" + master_variable[index].name
    459 
    460                      for scenario in tree_node._scenarios:
    461 
    462                         scenario_instance = instances[scenario._name]
    463                         scenario_variable = getattr(scenario_instance, stage_variable.name)
    464                         new_constraint_name = scenario._name + "_" + master_variable_name + "_" + str(index)
    465                         new_constraint = Constraint(name=new_constraint_name)
    466                         new_expr = master_variable[index] - scenario_variable[index]
    467                         new_constraint.add(None, (0.0, new_expr, 0.0))
    468                         new_constraint._model = master_binding_instance
    469                         setattr(master_binding_instance, new_constraint_name, new_constraint)
    470 
    471             # create a variable to represent the expected cost at this node -
    472             # the constraint to compute this comes later.
    473             expected_cost_variable_name = "EXPECTED_COST_" + tree_node._name
    474             expected_cost_variable = Var(name=expected_cost_variable_name)
    475             expected_cost_variable._model = master_binding_instance
    476             setattr(master_binding_instance, expected_cost_variable_name, expected_cost_variable)
    477 
    478    # if we're generating the weighted CVaR objective term, create the corresponding variable and
    479    # the master CVaR eta variable.
    480    if generate_weighted_cvar is True:
    481       root_node = scenario_tree._stages[0]._tree_nodes[0]
    482      
    483       cvar_cost_variable_name = "CVAR_COST_" + root_node._name
    484       cvar_cost_variable = Var(name=cvar_cost_variable_name)
    485       setattr(master_binding_instance, cvar_cost_variable_name, cvar_cost_variable)
    486       cvar_cost_variable.construct()
    487 
    488       cvar_eta_variable_name = "CVAR_ETA_" + root_node._name
    489       cvar_eta_variable = Var(name=cvar_eta_variable_name)
    490       setattr(master_binding_instance, cvar_eta_variable_name, cvar_eta_variable)     
    491       cvar_eta_variable.construct()
    492 
    493    master_binding_instance.preprocess()
    494 
    495    # ditto above for the (non-expected) cost variable.
    496    for stage in scenario_tree._stages:
    497 
    498       (cost_variable,cost_variable_index) = stage._cost_variable
    499 
    500       print "Creating master variable and blending constraints for cost variable="+cost_variable.name+", index="+str(cost_variable_index)
    501 
    502       for tree_node in stage._tree_nodes:
    503 
    504          # TBD - the following is bad - check to see if it's already there (I suspect some of them are!!!)         
    505 
    506          # this is undoubtedly wasteful, in that a cost variable
    507          # for each tree node is created with *all* indices.         
    508          new_cost_variable_name = tree_node._name + "_" + cost_variable.name
    509          new_cost_variable_index = cost_variable._index
    510          new_cost_variable = None
    511          if (len(new_cost_variable_index) is 1) and (None in new_cost_variable_index):
    512             new_cost_variable = Var(name=new_cost_variable_name)
    513          else:
    514             new_cost_variable = Var(new_cost_variable_index, name=new_cost_variable_name)
    515          new_cost_variable.construct()
    516          new_cost_variable._model = master_binding_instance
    517          setattr(master_binding_instance, new_cost_variable_name, new_cost_variable)         
    518 
    519          # the following is necessary, specifically to get the name - deepcopy won't reset these attributes.
    520          new_cost_variable[cost_variable_index].var = new_cost_variable
    521          if cost_variable_index is not None:
    522             # if the variable index is None, the variable is derived from a VarValue, so the
    523             # name gets updated automagically.
    524             new_cost_variable[cost_variable_index].name = tree_node._name + "_" + new_cost_variable[cost_variable_index].name
    525 
    526          for scenario in tree_node._scenarios:
    527 
    528             scenario_instance = instances[scenario._name]
    529             scenario_cost_variable = getattr(scenario_instance, cost_variable.name)
    530             new_constraint_name = scenario._name + "_" + new_cost_variable_name + "_" + str(cost_variable_index)
    531             new_constraint = Constraint(name=new_constraint_name)
    532             new_expr = new_cost_variable[cost_variable_index] - scenario_cost_variable[cost_variable_index]
    533             new_constraint.add(None, (0.0, new_expr, 0.0))
    534             new_constraint._model = master_binding_instance
    535             setattr(master_binding_instance, new_constraint_name, new_constraint)
    536 
    537    # create the constraints for computing the master per-node cost variables,
    538    # i.e., the current node cost and the expected cost of the child nodes.
    539    # if the root, then the constraint is just the objective.
    540 
    541    for stage in scenario_tree._stages:
    542 
    543       (stage_cost_variable,stage_cost_variable_index) = stage._cost_variable
    544 
    545       for tree_node in stage._tree_nodes:
    546 
    547          node_expected_cost_variable_name = "EXPECTED_COST_" + tree_node._name
    548          node_expected_cost_variable = getattr(master_binding_instance, node_expected_cost_variable_name)
    549 
    550          node_cost_variable_name = tree_node._name + "_" + stage_cost_variable.name
    551          node_cost_variable = getattr(master_binding_instance, node_cost_variable_name)                       
    552            
    553          constraint_expr = node_expected_cost_variable - node_cost_variable[stage_cost_variable_index]
    554 
    555          for child_node in tree_node._children:
    556 
    557             child_node_expected_cost_variable_name = "EXPECTED_COST_" + child_node._name
    558             child_node_expected_cost_variable = getattr(master_binding_instance, child_node_expected_cost_variable_name)
    559             constraint_expr = constraint_expr - (child_node._conditional_probability * child_node_expected_cost_variable)
    560 
    561          new_constraint_name = "COST" + "_" + node_cost_variable_name + "_" + str(cost_variable_index)
    562          new_constraint = Constraint(name=new_constraint_name)
    563          new_constraint.add(None, (0.0, constraint_expr, 0.0))
    564          new_constraint._model = master_binding_instance                     
    565          setattr(master_binding_instance, new_constraint_name, new_constraint)
    566 
    567          if tree_node._parent is None:
    568 
    569             an_instance = instances[instances.keys()[0]]
    570             an_objective = an_instance.active_components(Objective)
    571             opt_sense = an_objective[an_objective.keys()[0]].sense
    572 
    573             opt_expression = node_expected_cost_variable
    574 
    575             if generate_weighted_cvar is True:
    576                cvar_cost_variable_name = "CVAR_COST_" + tree_node._name
    577                cvar_cost_variable = getattr(master_binding_instance, cvar_cost_variable_name)
    578                opt_expression += cvar_weight * cvar_cost_variable
    579 
    580             new_objective = Objective(name="MASTER", sense=opt_sense)
    581             new_objective._data[None].expr = opt_expression
    582             setattr(master_binding_instance, "MASTER", new_objective)
    583 
    584    # CVaR requires the addition of a variable per scenario to represent the cost excess,
    585    # and a constraint to compute the cost excess relative to eta. we also replicate (following
    586    # what we do for node cost variables) an eta variable for each scenario instance, and
    587    # require equality with the master eta variable via constraints.
    588    if generate_weighted_cvar is True:
    589      
    590       root_node = scenario_tree._stages[0]._tree_nodes[0]
    591 
    592       master_cvar_eta_variable_name = "CVAR_ETA_" + root_node._name
    593       master_cvar_eta_variable = getattr(master_binding_instance, master_cvar_eta_variable_name)
    594      
    595       for scenario_name in instances.keys():
    596          scenario_instance = instances[scenario_name]
    597 
    598          # unique names are required because the presolve isn't
    599          # aware of the "owning" models for variables.
    600          cvar_excess_variable_name = "CVAR_EXCESS_"+scenario_name
    601          cvar_excess_variable = Var(name=cvar_excess_variable_name, domain=NonNegativeReals)
    602          setattr(scenario_instance, cvar_excess_variable_name, cvar_excess_variable)
    603          cvar_excess_variable.construct()
    604 
    605          cvar_eta_variable_name = "CVAR_ETA"
    606          cvar_eta_variable = Var(name=cvar_eta_variable_name)
    607          setattr(scenario_instance, cvar_eta_variable_name, cvar_eta_variable)
    608          cvar_eta_variable.construct()
    609 
    610          compute_excess_constraint_name = "COMPUTE_SCENARIO_EXCESS"
    611          compute_excess_constraint = Constraint(name=compute_excess_constraint_name)
    612          compute_excess_expression = cvar_excess_variable
    613          for node in scenario_tree._scenario_map[scenario_name]._node_list:
    614             (cost_variable, cost_variable_idx) = node._stage._cost_variable
    615             compute_excess_expression -= getattr(scenario_instance, cost_variable.name)[cost_variable_idx]
    616          compute_excess_expression += cvar_eta_variable
    617          compute_excess_constraint.add(None, (0.0, compute_excess_expression, None))
    618          compute_excess_constraint._model = scenario_instance
    619          setattr(scenario_instance, compute_excess_constraint_name, compute_excess_constraint)
    620 
    621          eta_equality_constraint_name = "MASTER_ETA_EQUALITY_WITH_" + scenario_instance.name
    622          eta_equality_constraint = Constraint(name=eta_equality_constraint_name)
    623          eta_equality_expr = master_cvar_eta_variable - cvar_eta_variable
    624          eta_equality_constraint.add(None, (0.0, eta_equality_expr, 0.0))
    625          eta_equality_constraint._model = master_binding_instance
    626          setattr(master_binding_instance, eta_equality_constraint_name, eta_equality_constraint)
    627 
    628       # add the constraint to compute the master CVaR variable value. iterate
    629       # over scenario instances to create the expected excess component first.
    630       cvar_cost_variable_name = "CVAR_COST_" + root_node._name
    631       cvar_cost_variable = getattr(master_binding_instance, cvar_cost_variable_name)
    632       cvar_eta_variable_name = "CVAR_ETA_" + root_node._name
    633       cvar_eta_variable = getattr(master_binding_instance, cvar_eta_variable_name)
    634      
    635       cvar_cost_expression = cvar_cost_variable - cvar_eta_variable
    636      
    637       for scenario_name in instances.keys():
    638          scenario_instance = instances[scenario_name]
    639          scenario_probability = scenario_tree._scenario_map[scenario_name]._probability
    640 
    641          scenario_excess_variable_name = "CVAR_EXCESS_"+scenario_name
    642          scenario_excess_variable = getattr(scenario_instance, scenario_excess_variable_name)
    643 
    644          cvar_cost_expression = cvar_cost_expression - (scenario_probability * scenario_excess_variable) / (1.0 - risk_alpha)
    645 
    646       compute_cvar_cost_constraint_name = "COMPUTE_CVAR_COST"
    647       compute_cvar_cost_constraint = Constraint(name=compute_cvar_cost_constraint_name)
    648       compute_cvar_cost_constraint.add(None, (0.0, cvar_cost_expression, 0.0))
    649       compute_cvar_cost_constraint._model = master_binding_instance
    650       setattr(master_binding_instance, compute_cvar_cost_constraint_name, compute_cvar_cost_constraint)
    651 
    652    # after mucking with instances, presolve to collect terms required prior to output.         
    653    # IMPT: Do the scenario instances first, as the master depends on variables in the scenarios.
    654    for scenario_name in instances.keys():
    655       scenario_instance = instances[scenario_name]   
    656       scenario_instance.preprocess()         
    657 
    658    master_binding_instance.preprocess()
    659 
    660    ################################################################################################
    661    #### WRITE THE COMPOSITE MODEL #################################################################
    662    ################################################################################################
     617      scenario_instances[scenario._name] = scenario_instance
     618
     619   print ""
     620
     621   binding_instance = create_ef_instance(scenario_tree, scenario_instances,
     622                                         verbose_output = verbose_output,
     623                                         generate_weighted_cvar = generate_weighted_cvar,
     624                                         cvar_weight = cvar_weight,
     625                                         risk_alpha = risk_alpha)   
    663626
    664627   print ""
    665628   print "Starting to write extensive form"
    666629
    667    # create the output file.
    668    problem_writer = cpxlp.ProblemWriter_cpxlp()
    669    output_file = open(output_filename,"w")
    670 
    671    problem_writer._output_prefixes = True # we always want prefixes
    672 
    673    ################################################################################################
    674    #### WRITE THE MASTER OBJECTIVE ################################################################
    675    ################################################################################################
    676 
    677    # write the objective for the master binding instance.
    678    problem_writer._output_objectives = True
    679    problem_writer._output_constraints = False
    680    problem_writer._output_variables = False
    681 
    682    print >>output_file, "\\ Begin objective block for master"
    683    problem_writer._print_model_LP(master_binding_instance, output_file)
    684    print >>output_file, "\\ End objective block for master"
    685    print >>output_file, ""
    686 
    687    ################################################################################################
    688    #### WRITE THE CONSTRAINTS FOR THE MASTER MODEL AND ALL SCENARIO MODELS ########################
    689    ################################################################################################
    690 
    691    print >>output_file, "s.t."
    692    print >>output_file, ""
    693    
    694    problem_writer._output_objectives = False
    695    problem_writer._output_constraints = True
    696    problem_writer._output_variables = False
    697 
    698    print >>output_file, "\\ Begin constraint block for master"
    699    problem_writer._print_model_LP(master_binding_instance, output_file)
    700    print >>output_file, "\\ End constraint block for master",
    701    print >>output_file, ""
    702 
    703    for scenario_name in instances.keys():
    704       instance = instances[scenario_name]
    705       print >>output_file, "\\ Begin constraint block for scenario",scenario_name       
    706       problem_writer._print_model_LP(instance, output_file)
    707       print >>output_file, "\\ End constraint block for scenario",scenario_name
    708       print >>output_file, ""
    709 
    710    ################################################################################################
    711    #### WRITE THE VARIABLES FOR THE MASTER MODEL AND ALL SCENARIO MODELS ##########################
    712    ################################################################################################
    713 
    714    # write the variables for the master binding instance, and then for each scenario.
    715    print >>output_file, "bounds"
    716    print >>output_file, ""
    717    
    718    problem_writer._output_objectives = False
    719    problem_writer._output_constraints = False
    720    problem_writer._output_variables = True
    721 
    722    # first step: write variable bounds
    723 
    724    problem_writer._output_continuous_variables = True
    725    problem_writer._output_integer_variables = False
    726    problem_writer._output_binary_variables = False
    727 
    728    print >>output_file, "\\ Begin variable bounds block for master"
    729    problem_writer._print_model_LP(master_binding_instance, output_file)
    730    print >>output_file, "\\ End variable bounds block for master"
    731    print >>output_file, ""
    732 
    733    for scenario_name in instances.keys():
    734       instance = instances[scenario_name]
    735       print >>output_file, "\\ Begin variable bounds block for scenario",scenario_name
    736       problem_writer._print_model_LP(instance, output_file)
    737       print >>output_file, "\\ End variable bounds block for scenario",scenario_name
    738       print >>output_file, ""
    739 
    740    # second step: write integer indicators.
    741 
    742    problem_writer._output_continuous_variables = False
    743    problem_writer._output_integer_variables = True
    744 
    745    if integers_present(master_binding_instance, instances) is True:
    746 
    747       print >>output_file, "integer"
    748       print >>output_file, ""
    749 
    750       print >>output_file, "\\ Begin integer variable block for master"
    751       problem_writer._print_model_LP(master_binding_instance, output_file)
    752       print >>output_file, "\\ End integer variable block for master"
    753       print >>output_file, ""
    754    
    755       for scenario_name in instances.keys():
    756          instance = instances[scenario_name]
    757          print >>output_file, "\\ Begin integer variable block for scenario",scenario_name
    758          problem_writer._print_model_LP(instance, output_file)
    759          print >>output_file, "\\ End integer variable block for scenario",scenario_name
    760          print >>output_file, ""
    761 
    762    # third step: write binary indicators.
    763 
    764    problem_writer._output_integer_variables = False
    765    problem_writer._output_binary_variables = True
    766 
    767    if binaries_present(master_binding_instance, instances) is True:
    768 
    769       print >>output_file, "binary"
    770       print >>output_file, ""
    771 
    772       print >>output_file, "\\ Begin binary variable block for master"
    773       problem_writer._print_model_LP(master_binding_instance, output_file)
    774       print >>output_file, "\\ End binary variable block for master"
    775       print >>output_file, ""
    776    
    777       for scenario_name in instances.keys():
    778          instance = instances[scenario_name]
    779          print >>output_file, "\\ Begin binary variable block for scenario",scenario_name
    780          problem_writer._print_model_LP(instance, output_file)
    781          print >>output_file, "\\ End integer binary block for scenario",scenario_name
    782          print >>output_file, ""
    783 
    784    # wrap up.
    785    print >>output_file, "end"
    786 
    787    # clean up.
    788    output_file.close()
     630   write_ef(binding_instance, scenario_instances, output_filename)   
    789631
    790632   print ""
     
    804646   start_time = time.time()
    805647
    806    binding_instance = create_ef_instance(scenario_tree, scenario_instances, False, True)
    807 
    808    ################################################################################################
    809    #### WRITE THE COMPOSITE MODEL #################################################################
    810    ################################################################################################
     648   binding_instance = create_ef_instance(scenario_tree, scenario_instances)
    811649
    812650   print ""
    813651   print "Starting to write extensive form"
    814652
    815    # create the output file.
    816    problem_writer = cpxlp.ProblemWriter_cpxlp()
    817    output_file = open(output_filename,"w")
    818 
    819    problem_writer._output_prefixes = True # we always want prefixes
    820 
    821    ################################################################################################
    822    #### WRITE THE MASTER OBJECTIVE ################################################################
    823    ################################################################################################
    824 
    825    # write the objective for the master binding instance.
    826    problem_writer._output_objectives = True
    827    problem_writer._output_constraints = False
    828    problem_writer._output_variables = False
    829 
    830    print >>output_file, "\\ Begin objective block for master"
    831    problem_writer._print_model_LP(binding_instance, output_file)
    832    print >>output_file, "\\ End objective block for master"
    833    print >>output_file, ""
    834 
    835    ################################################################################################
    836    #### WRITE THE CONSTRAINTS FOR THE MASTER MODEL AND ALL SCENARIO MODELS ########################
    837    ################################################################################################
    838 
    839    print >>output_file, "s.t."
    840    print >>output_file, ""
    841    
    842    problem_writer._output_objectives = False
    843    problem_writer._output_constraints = True
    844    problem_writer._output_variables = False
    845 
    846    print >>output_file, "\\ Begin constraint block for master"
    847    problem_writer._print_model_LP(binding_instance, output_file)
    848    print >>output_file, "\\ End constraint block for master",
    849    print >>output_file, ""
    850 
    851    for scenario_name in scenario_instances.keys():
    852       instance = scenario_instances[scenario_name]
    853       print >>output_file, "\\ Begin constraint block for scenario",scenario_name       
    854       problem_writer._print_model_LP(instance, output_file)
    855       print >>output_file, "\\ End constraint block for scenario",scenario_name
    856       print >>output_file, ""
    857 
    858    ################################################################################################
    859    #### WRITE THE VARIABLES FOR THE MASTER MODEL AND ALL SCENARIO MODELS ##########################
    860    ################################################################################################
    861 
    862    # write the variables for the master binding instance, and then for each scenario.
    863    print >>output_file, "bounds"
    864    print >>output_file, ""
    865    
    866    problem_writer._output_objectives = False
    867    problem_writer._output_constraints = False
    868    problem_writer._output_variables = True
    869 
    870    # first step: write variable bounds
    871 
    872    problem_writer._output_continuous_variables = True
    873    problem_writer._output_integer_variables = False
    874    problem_writer._output_binary_variables = False
    875 
    876    print >>output_file, "\\ Begin variable bounds block for master"
    877    problem_writer._print_model_LP(binding_instance, output_file)
    878    print >>output_file, "\\ End variable bounds block for master"
    879    print >>output_file, ""
    880    
    881    for scenario_name in scenario_instances.keys():
    882       instance = scenario_instances[scenario_name]
    883       print >>output_file, "\\ Begin variable bounds block for scenario",scenario_name
    884       problem_writer._print_model_LP(instance, output_file)
    885       print >>output_file, "\\ End variable bounds block for scenario",scenario_name
    886       print >>output_file, ""
    887 
    888    # second step: write integer indicators.
    889 
    890    problem_writer._output_continuous_variables = False
    891    problem_writer._output_integer_variables = True
    892 
    893    if integers_present(binding_instance, scenario_instances) is True:
    894 
    895       print >>output_file, "integer"
    896       print >>output_file, ""
    897 
    898       print >>output_file, "\\ Begin integer variable block for master"
    899       problem_writer._print_model_LP(binding_instance, output_file)
    900       print >>output_file, "\\ End integer variable block for master"
    901       print >>output_file, ""
    902    
    903       for scenario_name in scenario_instances.keys():
    904          instance = scenario_instances[scenario_name]
    905          print >>output_file, "\\ Begin integer variable block for scenario",scenario_name
    906          problem_writer._print_model_LP(instance, output_file)
    907          print >>output_file, "\\ End integer variable block for scenario",scenario_name
    908          print >>output_file, ""
    909 
    910    # third step: write binary indicators.
    911 
    912    problem_writer._output_integer_variables = False
    913    problem_writer._output_binary_variables = True
    914 
    915    if binaries_present(binding_instance, scenario_instances) is True:
    916 
    917       print >>output_file, "binary"
    918       print >>output_file, ""
    919 
    920       print >>output_file, "\\ Begin binary variable block for master"
    921       problem_writer._print_model_LP(binding_instance, output_file)
    922       print >>output_file, "\\ End binary variable block for master"
    923       print >>output_file, ""
    924    
    925       for scenario_name in scenario_instances.keys():
    926          instance = scenario_instances[scenario_name]
    927          print >>output_file, "\\ Begin binary variable block for scenario",scenario_name
    928          problem_writer._print_model_LP(instance, output_file)
    929          print >>output_file, "\\ End integer binary block for scenario",scenario_name
    930          print >>output_file, ""
    931 
    932    # wrap up.
    933    print >>output_file, "end"
    934 
    935    # clean up.
    936    output_file.close()
     653   write_ef(binding_instance, scenario_instances, output_filename)
    937654
    938655   print ""
  • coopr.pysp/trunk/coopr/pysp/phinit.py

    r2405 r2418  
    531531      print "Writing EF for remainder problem"
    532532      print ""
    533       write_ef(ph._scenario_tree, ph._instances, os.path.expanduser(options.ef_output_file))
     533      create_and_write_ef(ph._scenario_tree, ph._instances, os.path.expanduser(options.ef_output_file))
    534534
    535535   #
Note: See TracChangeset for help on using the changeset viewer.