Changeset 1979


Ignore:
Timestamp:
Dec 11, 2009 12:23:17 AM (11 years ago)
Author:
jwatson
Message:

Biggest enhancement: The efwriter command-line script now has the option to output a CVaR-weighted objective term. Not extensively tested, but behaves sane on a number of small test cases.

Improved exception handling and error diagnostics in both the runph and efwriter scripts.

Location:
coopr.pysp/trunk
Files:
5 edited

Legend:

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

    r1774 r1979  
    5454
    5555# the main extensive-form writer routine - including read of scenarios/etc.
    56 def write_ef_from_scratch(model_directory, instance_directory, output_filename):
     56def write_ef_from_scratch(model_directory, instance_directory, output_filename, \
     57                          generate_weighted_cvar, cvar_weight, risk_alpha):
    5758
    5859   start_time = time.time()
     
    6667   #### INITIALIZATION ############################################################################
    6768   ################################################################################################
     69
     70   #
     71   # validate cvar options, if specified.
     72   #
     73   if generate_weighted_cvar is True:
     74      if cvar_weight <= 0.0:
     75         raise RuntimeError, "Weight of CVaR term must be >= 0.0 - value supplied="+str(cvar_weight)
     76      if (risk_alpha <= 0.0) or (risk_alpha >= 1.0):
     77         raise RuntimeError, "CVaR risk alpha must be between 0 and 1, exclusive - value supplied="+str(risk_alpha)
     78
     79      print "Writing CVaR weighted objective"
     80      print "CVaR term weight="+str(cvar_weight)
     81      print "CVaR alpha="+str(risk_alpha)
     82      print ""
    6883   
    6984   #
     
    272287            setattr(master_binding_instance, expected_cost_variable_name, expected_cost_variable)
    273288
     289   # if we're generating the weighted CVaR objective term, create the corresponding variable and
     290   # the master CVaR eta variable.
     291   if generate_weighted_cvar is True:
     292      root_node = scenario_tree._stages[0]._tree_nodes[0]
     293     
     294      cvar_cost_variable_name = "CVAR_COST_" + root_node._name
     295      cvar_cost_variable = Var(name=cvar_cost_variable_name)
     296      cvar_cost_variable._construct(master_binding_instance, None)
     297      setattr(master_binding_instance, cvar_cost_variable_name, cvar_cost_variable)
     298
     299      cvar_eta_variable_name = "CVAR_ETA_" + root_node._name
     300      cvar_eta_variable = Var(name=cvar_eta_variable_name)
     301      cvar_eta_variable._construct(master_binding_instance, None)
     302      setattr(master_binding_instance, cvar_eta_variable_name, cvar_eta_variable)     
     303
    274304   master_binding_instance.presolve()
    275305
     
    348378            opt_sense = an_objective[an_objective.keys()[0]].sense
    349379
     380            opt_expression = node_expected_cost_variable
     381
     382            if generate_weighted_cvar is True:
     383               cvar_cost_variable_name = "CVAR_COST_" + tree_node._name
     384               cvar_cost_variable = getattr(master_binding_instance, cvar_cost_variable_name)
     385               opt_expression += cvar_weight * cvar_cost_variable
     386
    350387            new_objective = Objective(name="MASTER", sense=opt_sense)
    351             new_objective._data[None].expr = node_expected_cost_variable
     388            new_objective._data[None].expr = opt_expression
    352389            setattr(master_binding_instance, "MASTER", new_objective)
     390
     391   # CVaR requires the addition of a variable per scenario to represent the cost excess,
     392   # and a constraint to compute the cost excess relative to eta. we also replicate (following
     393   # what we do for node cost variables) an eta variable for each scenario instance, and
     394   # require equality with the master eta variable via constraints.
     395   if generate_weighted_cvar is True:
     396     
     397      root_node = scenario_tree._stages[0]._tree_nodes[0]
     398
     399      master_cvar_eta_variable_name = "CVAR_ETA_" + root_node._name
     400      master_cvar_eta_variable = getattr(master_binding_instance, master_cvar_eta_variable_name)
     401     
     402      for scenario_name in instances.keys():
     403         scenario_instance = instances[scenario_name]
     404
     405         # unique names are required because the presolve isn't
     406         # aware of the "owning" models for variables.
     407         cvar_excess_variable_name = "CVAR_EXCESS_"+scenario_name
     408         cvar_excess_variable = Var(name=cvar_excess_variable_name, domain=NonNegativeReals)
     409         cvar_excess_variable._construct(scenario_instance, None)
     410         setattr(scenario_instance, cvar_excess_variable_name, cvar_excess_variable)
     411
     412         cvar_eta_variable_name = "CVAR_ETA"
     413         cvar_eta_variable = Var(name=cvar_eta_variable_name)
     414         cvar_eta_variable._construct(scenario_instance, None)
     415         setattr(scenario_instance, cvar_eta_variable_name, cvar_eta_variable)
     416
     417         compute_excess_constraint_name = "COMPUTE_SCENARIO_EXCESS"
     418         compute_excess_constraint = Constraint(name=compute_excess_constraint_name)
     419         compute_excess_expression = cvar_excess_variable
     420         for node in scenario_tree._scenario_map[scenario_name]._node_list:
     421            (cost_variable, cost_variable_idx) = node._stage._cost_variable
     422            compute_excess_expression -= getattr(scenario_instance, cost_variable.name)[cost_variable_idx]
     423         compute_excess_expression += cvar_eta_variable
     424         compute_excess_constraint._initialize_constraint(None, (0.0, compute_excess_expression, None), scenario_instance, compute_excess_constraint_name)
     425         compute_excess_constraint._model = scenario_instance
     426         setattr(scenario_instance, compute_excess_constraint_name, compute_excess_constraint)
     427
     428         eta_equality_constraint_name = "MASTER_ETA_EQUALITY_WITH_" + scenario_instance.name
     429         eta_equality_constraint = Constraint(name=eta_equality_constraint_name)
     430         eta_equality_expr = master_cvar_eta_variable - cvar_eta_variable
     431         eta_equality_constraint._initialize_constraint(None, (0.0, eta_equality_expr, 0.0), master_binding_instance, eta_equality_constraint_name)
     432         eta_equality_constraint._model = master_binding_instance
     433         setattr(master_binding_instance, eta_equality_constraint_name, eta_equality_constraint)
     434
     435      # add the constraint to compute the master CVaR variable value. iterate
     436      # over scenario instances to create the expected excess component first.
     437      cvar_cost_variable_name = "CVAR_COST_" + root_node._name
     438      cvar_cost_variable = getattr(master_binding_instance, cvar_cost_variable_name)
     439      cvar_eta_variable_name = "CVAR_ETA_" + root_node._name
     440      cvar_eta_variable = getattr(master_binding_instance, cvar_eta_variable_name)
     441     
     442      cvar_cost_expression = cvar_cost_variable - cvar_eta_variable
     443     
     444      for scenario_name in instances.keys():
     445         scenario_instance = instances[scenario_name]
     446         scenario_probability = scenario_tree._scenario_map[scenario_name]._probability
     447
     448         scenario_excess_variable_name = "CVAR_EXCESS_"+scenario_name
     449         scenario_excess_variable = getattr(scenario_instance, scenario_excess_variable_name)
     450
     451         cvar_cost_expression = cvar_cost_expression - (scenario_probability * scenario_excess_variable) / (1.0 - risk_alpha)
     452
     453      compute_cvar_cost_constraint_name = "COMPUTE_CVAR_COST"
     454      compute_cvar_cost_constraint = Constraint(name=compute_cvar_cost_constraint_name)
     455      compute_cvar_cost_constraint._initialize_constraint(None, (0.0, cvar_cost_expression, 0.0), master_binding_instance, compute_cvar_cost_constraint_name)
     456      compute_cvar_cost_constraint._model = master_binding_instance
     457      setattr(master_binding_instance, compute_cvar_cost_constraint_name, compute_cvar_cost_constraint)
     458
     459   # after mucking with instances, presolve to collect terms required prior to output.         
     460   # IMPT: Do the scenario instances first, as the master depends on variables in the scenarios.
     461   for scenario_name in instances.keys():
     462      scenario_instance = instances[scenario_name]   
     463      scenario_instance.presolve()         
    353464
    354465   master_binding_instance.presolve()
  • coopr.pysp/trunk/coopr/pysp/ef_writer_script.py

    r1768 r1979  
    4040                  type="string",
    4141                  default=".")
     42parser.add_option("--generate-weighted-cvar",
     43                  help="Add a weighted CVaR term to the primary objective",
     44                  action="store_true",
     45                  dest="generate_weighted_cvar",
     46                  default=False)
     47parser.add_option("--cvar-weight",
     48                  help="The weight associated with the CVaR term in the risk-weighted objective formulation.",
     49                  action="store",
     50                  dest="cvar_weight",
     51                  type="float",
     52                  default=1.0)
     53parser.add_option("--risk-alpha",
     54                  help="The probability threshold associated with cvar (or any future) risk-oriented performance metrics.",
     55                  action="store",
     56                  dest="risk_alpha",
     57                  type="float",
     58                  default=0.95)
    4259parser.add_option("--output-file",
    4360                  help="Specify the name of the extensive form output file",
     
    5572def run_ef_writer(options, args):
    5673
    57    write_ef_from_scratch(options.model_directory, options.instance_directory, options.output_file)
     74   # if the user enabled the addition of the weighted cvar term to the objective,
     75   # then validate the associated parameters.
     76   generate_weighted_cvar = False
     77   cvar_weight = None
     78   risk_alpha = None
     79
     80   if options.generate_weighted_cvar is True:
     81
     82      generate_weighted_cvar = True
     83      cvar_weight = options.cvar_weight
     84      risk_alpha = options.risk_alpha
     85
     86   write_ef_from_scratch(options.model_directory, options.instance_directory, options.output_file, \
     87                         generate_weighted_cvar, cvar_weight, risk_alpha)
    5888
    5989   return
  • coopr.pysp/trunk/coopr/pysp/ph_script.py

    r1956 r1979  
    436436
    437437      if options.user_defined_extension is not None:
    438          print "User-defined PH extension specified - module name="+options.user_defined_extension
    439          try:
    440             __import__(options.user_defined_extension)
    441          except:
    442             raise RuntimeError, "Failed to load user-defined module="+options.user_defined_extension
     438         print "Trying to import user-defined PH extension module="+options.user_defined_extension
     439         # JPW removed the exception handling logic, as the module importer
     440         # can raise a broad array of exceptions.
     441         __import__(options.user_defined_extension)
     442         print "Module successfully loaded"
    443443
    444444      #
  • coopr.pysp/trunk/scripts/efwriter

    r1806 r1979  
    5151    coopr.pysp.ef_writer_script.run()
    5252except ValueError, str:
     53    print "VALUE ERROR:"   
    5354    print str
    5455except IOError, str:
     56    print "IO ERROR:"   
    5557    print str
     58except RuntimeError, str:
     59    print "RUN-TIME ERROR:"   
     60    print str   
    5661except pyutilib.common.ApplicationError, str:
     62    print "APPLICATION ERROR:"   
    5763    print str
    5864except:
  • coopr.pysp/trunk/scripts/runph

    r1806 r1979  
    5959    print "APPLICATION ERROR:"
    6060    print str
     61except RuntimeError, str:
     62    print "RUN-TIME ERROR:"   
     63    print str       
    6164except:
    6265   print "Encountered unhandled exception"
Note: See TracChangeset for help on using the changeset viewer.