def test_ama_creator(self): options = _get_base_options() ama_options = { "EF-2stage": True, } ama_options.update(options['opt']) ama_object = ama.from_module(refmodelname, options=ama_options, use_command_line=False)
def test_ama_running(self): options = _get_base_options() ama_options = {"EF-2stage": True} ama_options.update(options['opt']) ama_object = ama.from_module(refmodelname, ama_options, use_command_line=False) ama_object.run() obj = round_pos_sig(ama_object.EF_Obj, 2) self.assertEqual(obj, -130000)
def main(): solution_files = {"first_stage_solution":"farmer_first_stage.csv", } ama_options = {"EF-2stage": True, # We are solving directly the EF "write_solution":solution_files} #The module can be a local file ama = amalgomator.from_module("afarmer", ama_options) ama.run() print("first_stage_solution=", ama.first_stage_solution) print("inner bound=", ama.best_inner_bound) print("outer bound=", ama.best_outer_bound)
def xhat_generator_farmer(scenario_names, solvername="gurobi", solver_options=None, crops_multiplier=1): '''Farmer example applied to sequential sampling. Given scenario names and options, create the scenarios and compute the xhat that is minimizing the approximate probleme associatd with these scenarios. Parameters ---------- scenario_names: int Names of the scenario we use solvername: str, optional Name of the solver used. The default is "gurobi". solver_options: dict, optional Solving options. The default is None. crops_multiplier: int, optional A parameter of the farmer model. The default is 1. Returns ------- xhat: xhat object (dict containing a 'ROOT' key with a np.array) A generated xhat. ''' num_scens = len(scenario_names) ama_options = { "EF-2stage": True, "EF_solver_name": solvername, "EF_solver_options": solver_options, "use_integer": False, "crops_multiplier": crops_multiplier, "num_scens": num_scens, "_mpisppy_probability": 1/num_scens, } #We use from_module to build easily an Amalgomator object ama = amalgomator.from_module("mpisppy.tests.examples.farmer", ama_options,use_command_line=False) #Correcting the building by putting the right scenarios. ama.scenario_names = scenario_names ama.run() # get the xhat xhat = sputils.nonant_cache_from_ef(ama.ef) return xhat
def xhat_generator_apl1p(scenario_names, solvername="gurobi", solver_options=None): ''' For sequential sampling. Takes scenario names as input and provide the best solution for the approximate problem associated with the scenarios. Parameters ---------- scenario_names: int Names of the scenario we use solvername: str, optional Name of the solver used. The default is "gurobi" solver_options: dict, optional Solving options. The default is None. Returns ------- xhat: str A generated xhat, solution to the approximate problem induced by scenario_names. ''' num_scens = len(scenario_names) ama_options = { "EF-2stage": True, "EF_solver_name": solvername, "EF_solver_options": solver_options, "num_scens": num_scens, "_mpisppy_probability": 1 / num_scens, } #We use from_module to build easily an Amalgomator object ama = amalgomator.from_module("mpisppy.tests.examples.apl1p", ama_options, use_command_line=False) #Correcting the building by putting the right scenarios. ama.scenario_names = scenario_names ama.run() # get the xhat xhat = sputils.nonant_cache_from_ef(ama.ef) return xhat
def main(): solution_files = { "first_stage_solution": "uc_first_stage.csv", #"tree_solution":"uc_ama_full_solution" #It takes too long to right the full solution } ama_options = { "2stage": True, # 2stage vs. mstage "cylinders": ['ph', 'xhatshuffle', 'lagranger'], "extensions": ['fixer'], "id_fix_list_fct": id_fix_list_fct, #Needed for fixer, but not passed in baseparsers "write_solution": solution_files } ama = amalgomator.from_module("uc_funcs", ama_options) ama.run() if ama.on_hub: print("first_stage_solution=", ama.first_stage_solution) print("inner bound=", ama.best_inner_bound) print("outer bound=", ama.best_outer_bound)
ama_extraargs.add_argument( "--MMW-num-batches", help="number of batches used for MMW confidence interval (default 1)", dest="num_batches", type=int, default=1) ama_extraargs.add_argument( "--MMW-batch-size", help="batch size used for MMW confidence interval (default None)", dest="batch_size", type=int, default=None) #None means take batch_size=num_scens ama_object = ama.from_module(refmodel, ama_options, extraargs=ama_extraargs) ama_object.run() if global_rank == 0: print("inner bound=", ama_object.best_inner_bound) # This the xhat of the left term of LHS of MMW (9) print("outer bound=", ama_object.best_outer_bound) ########### get the nonants (the xhat) nonant_cache = sputils.nonant_cache_from_ef(ama_object.ef) ciutils.write_xhat(nonant_cache, path="xhat.npy") #Set parameters for run() options = ama_object.options
if __name__ == "__main__": bfs = [4, 3, 2] num_scens = np.prod(bfs) #To check with a full tree ama_options = { "EF-mstage": True, "EF_solver_name": "gurobi_direct", "num_scens": num_scens, "_mpisppy_probability": 1 / num_scens, "BFs": bfs, "mudev": 0, "sigmadev": 80 } refmodel = "mpisppy.tests.examples.aircond_submodels" # WARNING: Change this in SPInstances #We use from_module to build easily an Amalgomator object ama = amalgomator.from_module(refmodel, ama_options, use_command_line=False) ama.run() print(f"inner bound=", ama.best_inner_bound) print(f"outer bound=", ama.best_outer_bound) from mpisppy.confidence_intervals.mmw_ci import MMWConfidenceIntervals options = ama.options options['solver_options'] = options['EF_solver_options'] xhat = sputils.nonant_cache_from_ef(ama.ef)['ROOT'] num_batches = 10 batch_size = 100 mmw = MMWConfidenceIntervals(refmodel, options,
def xhat_generator_aircond(scenario_names, solvername="gurobi", solver_options=None, BFs=[3, 2, 3], mudev=0, sigmadev=40, start_seed=0): ''' For sequential sampling. Takes scenario names as input and provide the best solution for the approximate problem associated with the scenarios. Parameters ---------- scenario_names: int Names of the scenario we use solvername: str, optional Name of the solver used. The default is "gurobi" solver_options: dict, optional Solving options. The default is None. BFs: list, optional Branching factors of the scenario 3. The default is [3,2,3] (a 4 stage model with 18 different scenarios) mudev: float, optional The average deviation of demand between two stages; The default is 0. sigma_dev: float, optional The standard deviation from mudev for the demand difference between two stages. The default is 40. start_seed: int, optional The starting seed, used to create different sample scenario trees. The default is 0. Returns ------- xhat: str A generated xhat, solution to the approximate problem induced by scenario_names. NOTE: This tool only works when the file is in mpisppy. In SPInstances, you must change the from_module line. ''' num_scens = len(scenario_names) ama_options = { "EF-mstage": True, "EF_solver_name": solvername, "EF_solver_options": solver_options, "num_scens": num_scens, "_mpisppy_probability": 1 / num_scens, "BFs": BFs, "mudev": mudev, "start_seed": start_seed, "sigmadev": sigmadev } #We use from_module to build easily an Amalgomator object ama = amalgomator.from_module("mpisppy.tests.examples.aircond_submodels", ama_options, use_command_line=False) #Correcting the building by putting the right scenarios. ama.scenario_names = scenario_names ama.verbose = False ama.run() # get the xhat xhat = sputils.nonant_cache_from_ef(ama.ef) return {'ROOT': xhat['ROOT']}
return xhats, seed if __name__ == "__main__": BFs = [3, 2, 4, 4] num_scens = np.prod(BFs) mname = "mpisppy.tests.examples.aircond_submodels" ama_options = { "EF-mstage": True, "num_scens": num_scens, "_mpisppy_probability": 1 / num_scens, "BFs": BFs, } #We use from_module to build easily an Amalgomator object ama = amalgomator.from_module(mname, ama_options, use_command_line=False) ama.run() # get the xhat xhat_one = sputils.nonant_cache_from_ef(ama.ef)['ROOT'] #----------Find a feasible solution for a single scenario------------- scenario = ama.ef.scen0 seed = sputils.number_of_nodes(BFs) options = dict() #We take default aircond options xhats, seed = feasible_solution(mname, scenario, xhat_one, BFs, seed, options) print(xhats) #----------Find feasible solutions for every scenario ------------
return None else: if verbose and self.cylinder_rank == 0: print(" Feasible xhat found") return self.Eobjective(verbose=verbose) if __name__ == "__main__": #============================== # hardwired by dlw for debugging (this main is like MMW, but strange) import mpisppy.tests.examples.farmer as refmodel import mpisppy.utils.amalgomator as ama # do the right term of MMW (9) using the first scenarios ama_options = {"EF-2stage": True} # 2stage vs. mstage ama_object = ama.from_module("mpisppy.tests.examples.farmer", ama_options) ama_object.run() print(f"inner bound=", ama_object.best_inner_bound) # This the right term of LHS of MMW (9) print(f"outer bound=", ama_object.best_outer_bound) ############### now get an xhat using different scenarios # (use use the ama args to get problem parameters) ScenCount = ama_object.options['num_scens'] scenario_creator = refmodel.scenario_creator scenario_denouement = refmodel.scenario_denouement crops_multiplier = ama_object.options['crops_multiplier'] solvername = ama_object.options['EF_solver_name'] scenario_creator_kwargs = { "use_integer": False,
def gap_estimators(xhat_one, mname, solving_type="EF-2stage", scenario_names=None, sample_options=None, ArRP=1, scenario_creator_kwargs={}, scenario_denouement=None, solvername='gurobi', solver_options=None, verbose=True, objective_gap=False ): ''' Given a xhat, scenario names, a scenario creator and options, gap_estimators creates a scenario tree and the associatd estimators G and s from ยง2 of [bm2011]. Returns G and s evaluated at xhat. If ArRP>1, G and s are pooled, from a number ArRP of estimators, computed with different scenario trees. Parameters ---------- xhat_one : dict A candidate first stage solution mname: str Name of the reference model, e.g. 'mpisppy.tests.examples.farmer'. solving_type: str, optional The way we solve the approximate problem. Can be "EF-2stage" (default) or "EF-mstage". scenario_names: list, optional List of scenario names used to compute G_n and s_n. Default is None Must be specified for 2 stage, but can be missing for multistage sample_options: dict, optional Only for multistage. Must contain a 'seed' and a 'BFs' attribute, specifying the starting seed and the branching factors of the scenario tree ArRP:int,optional Number of batches (we create a ArRP model). Default is 1 (one batch). scenario_creator_kwargs: dict, optional Additional arguments for scenario_creator. Default is {} scenario_denouement: function, optional Function to run after scenario creation. Default is None. solvername : str, optional Solver. Default is 'gurobi' solver_options: dict, optional Solving options. Default is None verbose: bool, optional Should it print the gap estimator ? Default is True objective_gap: bool, optional Returns a gap estimate around approximate objective value BFs: list, optional Only for multistage. List of branching factors of the sample scenario tree. Returns ------- G_k and s_k, gap estimator and associated standard deviation estimator. ''' if solving_type not in ["EF-2stage","EF-mstage"]: raise RuntimeError("Only EF solve for the approximate problem is supported yet.") else: is_multi = (solving_type=="EF-mstage") if is_multi: try: BFs = sample_options['BFs'] start = sample_options['seed'] except (TypeError,KeyError,RuntimeError): raise RuntimeError('For multistage problems, sample_options must be a dict with BFs and seed attributes.') else: start = sputils.extract_num(scenario_names[0]) if ArRP>1: #Special case : ArRP, G and s are pooled from r>1 estimators. if is_multi: raise RuntimeError("Pooled estimators are not supported for multistage problems yet.") n = len(scenario_names) if(n%ArRP != 0): raise RuntimeWarning("You put as an input a number of scenarios"+\ f" which is not a mutliple of {ArRP}.") n = n- n%ArRP G =[] s = [] for k in range(ArRP): scennames = scenario_names[k*(n//ArRP):(k+1)*(n//ArRP)] tmp = gap_estimators(xhat_one, mname, solvername=solvername, scenario_names=scennames, ArRP=1, scenario_creator_kwargs=scenario_creator_kwargs, scenario_denouement=scenario_denouement, solver_options=solver_options, solving_type=solving_type ) G.append(tmp['G']) s.append(tmp['s']) #Pooling G = np.mean(G) s = np.linalg.norm(s)/np.sqrt(n//ArRP) return {"G": G, "s": s, "seed": start} #A1RP #We start by computing the optimal solution to the approximate problem induced by our scenarios if is_multi: #Sample a scenario tree: this is a subtree, but starting from stage 1 samp_tree = sample_tree.SampleSubtree(mname, xhats =[], root_scen=None, starting_stage=1, BFs=BFs, seed=start, options=scenario_creator_kwargs, solvername=solvername, solver_options=solver_options) samp_tree.run() start += sputils.number_of_nodes(BFs) ama_object = samp_tree.ama else: #We use amalgomator to do it ama_options = dict(scenario_creator_kwargs) ama_options['start'] = start ama_options['num_scens'] = len(scenario_names) ama_options['EF_solver_name'] = solvername ama_options['EF_solver_options'] = solver_options ama_options[solving_type] = True ama_object = ama.from_module(mname, ama_options,use_command_line=False) ama_object.scenario_names = scenario_names ama_object.verbose = False ama_object.run() start += len(scenario_names) #Optimal solution of the approximate problem zstar = ama_object.best_outer_bound #Associated policies xstars = sputils.nonant_cache_from_ef(ama_object.ef) #Then, we evaluate the fonction value induced by the scenario at xstar. if is_multi: # Find feasible policies (i.e. xhats) for every non-leaf nodes if len(samp_tree.ef._ef_scenario_names)>1: local_scenarios = {sname:getattr(samp_tree.ef,sname) for sname in samp_tree.ef._ef_scenario_names} else: local_scenarios = {samp_tree.ef._ef_scenario_names[0]:samp_tree.ef} xhats,start = sample_tree.walking_tree_xhats(mname, local_scenarios, xhat_one['ROOT'], BFs, start, scenario_creator_kwargs, solvername=solvername, solver_options=solver_options) #Compute then the average function value with this policy scenario_creator_kwargs = samp_tree.ama.kwargs all_nodenames = sputils.create_nodenames_from_BFs(BFs) else: #In a 2 stage problem, the only non-leaf is the ROOT node xhats = xhat_one all_nodenames = None xhat_eval_options = {"iter0_solver_options": None, "iterk_solver_options": None, "display_timing": False, "solvername": solvername, "verbose": False, "solver_options":solver_options} ev = xhat_eval.Xhat_Eval(xhat_eval_options, scenario_names, ama_object.scenario_creator, scenario_denouement, scenario_creator_kwargs=scenario_creator_kwargs, all_nodenames = all_nodenames) #Evaluating xhat and xstar and getting the value of the objective function #for every (local) scenario ev.evaluate(xhats) objs_at_xhat = ev.objs_dict ev.evaluate(xstars) objs_at_xstar = ev.objs_dict eval_scen_at_xhat = [] eval_scen_at_xstar = [] scen_probs = [] for k,s in ev.local_scenarios.items(): eval_scen_at_xhat.append(objs_at_xhat[k]) eval_scen_at_xstar.append(objs_at_xstar[k]) scen_probs.append(s._mpisppy_probability) scen_gaps = np.array(eval_scen_at_xhat)-np.array(eval_scen_at_xstar) local_gap = np.dot(scen_gaps,scen_probs) local_ssq = np.dot(scen_gaps**2,scen_probs) local_prob_sqnorm = np.linalg.norm(scen_probs)**2 local_obj_at_xhat = np.dot(eval_scen_at_xhat,scen_probs) local_estim = np.array([local_gap,local_ssq,local_prob_sqnorm,local_obj_at_xhat]) global_estim = np.zeros(4) ev.mpicomm.Allreduce(local_estim, global_estim, op=mpi.SUM) G,ssq, prob_sqnorm,obj_at_xhat = global_estim if global_rank==0 and verbose: print(f"G = {G}") sample_var = (ssq - G**2)/(1-prob_sqnorm) #Unbiased sample variance s = np.sqrt(sample_var) use_relative_error = (np.abs(zstar)>1) G = correcting_numeric(G,objfct=obj_at_xhat, relative_error=use_relative_error) if objective_gap: if is_multi: return {"G":G,"s":s,"zhats": [obj_at_xhat], "seed":start} else: return {"G":G,"s":s,"zhats": eval_scen_at_xhat, "seed":start} else: return {"G":G,"s":s,"seed":start}