From e58bf243d9378981b9c3003012dde87a0e4d66c3 Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 20 Feb 2019 10:56:48 -0500 Subject: [PATCH 1/3] changes to sbfl_utility --- algorithm/s_bfl.py | 11 +++ algorithm/s_bfl_utility.py | 151 ++++++++++++++++++++++--------------- 2 files changed, 102 insertions(+), 60 deletions(-) diff --git a/algorithm/s_bfl.py b/algorithm/s_bfl.py index 87857a3..a0a3240 100644 --- a/algorithm/s_bfl.py +++ b/algorithm/s_bfl.py @@ -33,6 +33,7 @@ def input(self, input_data, sysnum, t_lim = 10, jit=False, **kwargs): self.csk, self.d, self.hf, self.hs, self.U, self.UE, self.UE_jit) = self.params.values() def solve(self): + # variable names let's make it clear T = list(range(1, len(self.d))) F = list(range(len(self.cfs))) S = list(range(len(self.csk))) @@ -143,13 +144,18 @@ def solve(self): m.write(f'warm_starts/base_sys{self.sysnum}.mst') cost_total_lb = m.objBound + # Total cost cost_total = m.objVal gap = (cost_total - cost_total_lb) / cost_total + # what does cost locations mean? cost_loc = w.prod({(s, k): self.csk[s][k] for s in S for k in K}).getValue() cost_op = zfs.sum().getValue() * self.c_op cfs_dict = {(t, f, s): self.cfs[f][s] for t, f, s in setprod(T, F, S)} + + # cost of transporting from f to s in time t cost_tran_fs = zfs.prod(cfs_dict).getValue() + # what does the b stand for? cost_tran_sb = zs.prod({(t, s): self.cs[s] for t in T for s in S}).getValue() if self.jit: @@ -165,6 +171,11 @@ def solve(self): K_cnt = dict(Counter(k for s in S for k in K if w[s, k].x > 0.5)) jit_amount = z_jit.sum().getValue() if self.jit else np.nan + # why do we need to send the user every variable value? + # is there a cleaner way to do this? + # maybe a function for getting all the variables that are active and convert to lat, lng? + # getActiveRoutes() + # Binary encoding of open ssls solution = [[v.VarName, v.X] for v in m.getVars() if v.X > 1e-6] summary = dict() summary['others'] = { diff --git a/algorithm/s_bfl_utility.py b/algorithm/s_bfl_utility.py index 4474a9f..5698224 100644 --- a/algorithm/s_bfl_utility.py +++ b/algorithm/s_bfl_utility.py @@ -37,6 +37,21 @@ def create_data(raw_data, sysnum, mode="paper", seed=None, out_file=None, plot_coords : bool, optional plot all the coordinates. + Variable name replacements + T = num_weeks_horizon + F = num_farms + S = num_ssls + a = harvested + cfs = farm_ssl_trans_cost + cs = ssl_refinery_trans_cost + csk = fixed_cost_ssls + ck = cost_ssls + hf = farm_holding_cost + hs = ssl_holding_cost + d = demand + u = upperbound_inventory + ue = upperbound_equip_proc_rate + Returns ------- all_data : dict @@ -54,28 +69,29 @@ def create_data(raw_data, sysnum, mode="paper", seed=None, out_file=None, else: raise TypeError('raw_data must be str (filename) or dict.') - T = raw['horizon'] - F = raw['num_fields'] - S = raw['num_ssls'] + num_weeks_horizon = raw['horizon'] + num_farms = raw['num_fields'] + num_ssls = raw['num_ssls'] # ========== coordinates, harvest, demand data ========== radius = raw['field']['radius'] np.random.seed(seed=seed) if mode == "paper": - sites = np.random.uniform(-radius, radius, size=(2 * (F + S), 2)) + # generates random ssl locations + sites = np.random.uniform(-radius, radius, size=(2 * (num_farms + num_ssls), 2)) sits_in = sites[np.sum(sites * sites, axis=1) <= radius**2] - coord_f = sits_in[:F] - coord_s = sits_in[-S:] + coord_farms = sits_in[:num_farms] + coord_ssls = sits_in[-num_ssls:] elif mode == "coordinates": - coord_f = np.array(list(raw["Coord_f"].values())) - coord_s = np.array(list(raw["Coord_s"].values())) - assert len(coord_f) == F - assert len(coord_s) == S + coord_farms = np.array(list(raw["Coord_f"].values())) + coord_ssls = np.array(list(raw["Coord_s"].values())) + assert len(coord_farms) == num_farms + assert len(coord_ssls) == num_ssls if plot_coords: l1, = plt.plot(0, 'g^', markersize=7) - l2, = plt.plot(*coord_s.T, 'ro', markersize=2) - l3, = plt.plot(*coord_f.T, 'bx', markersize=3) + l2, = plt.plot(*coord_ssls.T, 'ro', markersize=2) + l3, = plt.plot(*coord_farms.T, 'bx', markersize=3) plt.legend([l3, l2, l1], ['Farm', 'SSL', 'Bio-refinery']) circles = [ plt.Circle((0, 0), @@ -94,19 +110,22 @@ def create_data(raw_data, sysnum, mode="paper", seed=None, out_file=None, proportion_devoted = raw['field']['proportion_devoted'] # 1 sqkm = 100 ha total_supply = 100 * pi * radius**2 * proportion_devoted * dry_yield - a_weight = np.zeros(T + 1, dtype=int) + # what is the a_weight? Is it just a way of configuring the matrix? + a_weight = np.zeros(num_weeks_horizon + 1, dtype=int) a_weight[1:len(harvest_progress) + 1] = harvest_progress weekly_supply = a_weight / a_weight.sum() * total_supply - field_weight = np.random.uniform(1, 10, size=F) + field_weight = np.random.uniform(1, 10, size=num_farms) field_weight = field_weight / field_weight.sum() - a = weekly_supply[:, None] * field_weight[None] - a = a.round(0).astype(int) + + #if a is the amount harvested in farm f at time t why is it a single number here? + harvested = weekly_supply[:, None] * field_weight[None] + harvested = harvested.round(0).astype(int) total_demand = raw['demand'] - d = [0] + [int(total_demand / T)] * T + demand = [0] + [int(total_demand / num_weeks_horizon)] * num_weeks_horizon # =================== system dependet data ========================== - tran_coef = raw['cost']['transport_coef'] + tran_coef = raw['cost']['transport_coef'] #raw is the input file equipments = raw['cost']['equipment'] config = raw['configurations'][sysnum] dry_part = 1 - raw['moisture'] @@ -116,37 +135,45 @@ def create_data(raw_data, sysnum, mode="paper", seed=None, out_file=None, K = [(i, *j) for i in ssl_sizes for j in equip_arr] if 'whole_stalk' in config: - hf = raw['price'] / raw['degrade']['whole_stalk'] + # farm_unit_holding_cost + farm_holding_cost = raw['price'] / raw['degrade']['whole_stalk'] else: - hf = raw['price'] / raw['degrade']['chopped'] + farm_holding_cost = raw['price'] / raw['degrade']['chopped'] if 'bunker' in config: - hs = raw['price'] / raw['degrade']['in_bunker'] + # ssl_unit_holding_cost + ssl_holding_cost = raw['price'] / raw['degrade']['in_bunker'] elif 'bagger' in config or 'module_former' in config: - hs = raw['price'] / raw['degrade']['in_bag'] + ssl_holding_cost = raw['price'] / raw['degrade']['in_bag'] else: - hs = raw['price'] / raw['degrade']['chopped'] + ssl_holding_cost = raw['price'] / raw['degrade']['chopped'] - c_op = 0 + # c_op = operating cost? + operating_cost = 0 for e in config[1:]: if e == 'bunker': continue - c_op += equipments[e][3] - c_op /= dry_part - c_op_jit = equipments['loadout'][3] - c_op_jit += equipments['chopper'][3] if 'chopper' in config else 0 - c_op_jit /= dry_part + operating_cost += equipments[e][3] + operating_cost /= dry_part + operating_cost_jit = equipments['loadout'][3] + operating_cost_jit += equipments['chopper'][3] if 'chopper' in config else 0 + operating_cost_jit /= dry_part - cfs_rate = raw['cost']['base_infield'] / dry_part - cfs_rate *= tran_coef['whole_stalk'] if 'whole_stalk' in config else 1 - cfs = cdist(coord_f, coord_s) * cfs_rate + # cost per Mg to transport from farm f to ssl s + farm_ssl_trans_cost_rate = raw['cost']['base_infield'] / dry_part + farm_ssl_trans_cost_rate *= tran_coef['whole_stalk'] if 'whole_stalk' in config else 1 + farm_ssl_trans_cost = cdist(coord_farms, coord_ssls) * farm_ssl_trans_cost_rate - cs_jit_rate = cs_rate = raw['cost']['base_highway'] / dry_part - cs_rate *= tran_coef['compressed'] if 'press' in config else 1 - cs_rate *= tran_coef['in_module'] if 'module_former' in config else 1 - cs = np.linalg.norm(coord_s, axis=1) * cs_rate - cs_jit = np.linalg.norm(coord_s, axis=1) * cs_jit_rate + # Cost per Mg to send from ssl to refinery + ssl_refinery_trans_cost_jit_rate = ssl_refinery_trans_cost_rate = raw['cost']['base_highway'] / dry_part + ssl_refinery_trans_cost_rate *= tran_coef['compressed'] if 'press' in config else 1 + ssl_refinery_trans_cost_rate *= tran_coef['in_module'] if 'module_former' in config else 1 + + # use geolocation here, backward compatable (works with all ways it used to run) + ssl_refinery_trans_cost = np.linalg.norm(coord_ssls, axis=1) * ssl_refinery_trans_cost_rate + ssl_refinery_jit_trans_cost = np.linalg.norm(coord_ssls, axis=1) * ssl_refinery_trans_cost_jit_rate + # UE upperbound equipment processing rate UE, UE_jit = dict(), dict() for v in equip_arr: caps_jit = [ @@ -162,47 +189,49 @@ def create_data(raw_data, sysnum, mode="paper", seed=None, out_file=None, UE[v] = int(min(caps_other) * dry_part) UE_jit[v] = int(min(caps_jit) * dry_part) - own_cost = {'bunker': raw['cost']['bunker_annual_own'] / 52 * T} + # what is own_cost? owner cost? owner of what? + own_cost = {'bunker': raw['cost']['bunker_annual_own'] / 52 * num_weeks_horizon} for k, v in equipments.items(): depreciation = (v[0] - v[2]) / v[1] interest = v[0] * raw['interest_rate'] insurance_tax = (v[0] + v[2]) / 2 * ( raw['insurance_rate'] + raw['tax_rate']) - own_cost[k] = (depreciation + interest + insurance_tax) / 52 * T + own_cost[k] = (depreciation + interest + insurance_tax) / 52 * num_weeks_horizon - ck = dict() + # cost per type of ssl + cost_ssls = dict() for k in K: - ssl_cost = k[0] * raw['cost']['ssl_annual_own'] / 52 * T + ssl_cost = k[0] * raw['cost']['ssl_annual_own'] / 52 * num_weeks_horizon equip_cost = [k[i + 1] * own_cost[e] for i, e in enumerate(config[1:])] - ck[k] = int(ssl_cost + sum(equip_cost)) + cost_ssls[k] = int(ssl_cost + sum(equip_cost)) # =================== output data ========================== all_data = { 'Configuration': config, - 'Coord_f': {i: v.tolist() - for i, v in enumerate(coord_f)}, - 'Coord_s': {i: v.tolist() - for i, v in enumerate(coord_s)}, + 'Coord_farms': {i: v.tolist() + for i, v in enumerate(coord_farms)}, + 'Coord_ssls': {i: v.tolist() + for i, v in enumerate(coord_ssls)}, 'K': {i: list(k) for i, k in enumerate(K)}, 'Seed': seed, 'Sysnum': sysnum, - 'a': a.tolist(), - 'c_op': c_op, - 'c_op_jit': c_op_jit, + 'harvested': harvested.tolist(), + 'operating_cost': operating_cost, + 'operating_cost_jit': operating_cost_jit, + # what is this the "price" of? 'c_pen': raw['price'] * 3, - 'cfs': np.round(cfs, 2).tolist(), - 'cs': np.round(cs, 2).tolist(), - 'cs_jit': np.round(cs_jit, 2).tolist(), - 'csk': [list(ck.values())] * S, - 'd': d, - 'hf': hf, - 'hs': hs, - 'u': np.repeat(ssl_sizes, len(equip_arr)).tolist(), - 'ue': list(UE.values()) * len(ssl_sizes), - 'ue_jit': list(UE_jit.values()) * len(ssl_sizes) + 'farm_ssl_trans_cost': np.round(farm_ssl_trans_cost, 2).tolist(), + 'ssl_refinery_trans_cost': np.round(ssl_refinery_trans_cost, 2).tolist(), + 'ssl_refinery_jit_trans_cost': np.round(ssl_refinery_jit_trans_cost, 2).tolist(), + 'fixed_cost_ssls': [list(cost_ssls.values())] * num_ssls, + 'demand': demand, + 'farm_holding_cost': farm_holding_cost, + 'ssl_holding_cost': ssl_holding_cost, + 'upperbound_inventory': np.repeat(ssl_sizes, len(equip_arr)).tolist(), + 'upperbound_equip_proc_rate': list(UE.values()) * len(ssl_sizes), + 'upperbound_equip_proc_rate_jit': list(UE_jit.values()) * len(ssl_sizes) } - # %% if out_file is not None: with open(out_file, 'w') as f: if out_file.split('.')[-1] == 'json': @@ -235,9 +264,11 @@ def cli_s_bfl(): parser.add_argument( '-t', '--t_lim', + # not sure about this metaVar metavar='T', type=float, default=60, + # Looks like T was used for another purpose here help='set computation time limit T in seconds (default: 60)') parser.add_argument( '--seed', From bbcdee5b94a196ca3fd617039193029abc6d1c93 Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 20 Feb 2019 12:32:59 -0500 Subject: [PATCH 2/3] Changed names working test for backwards compatability --- algorithm/s_bfl.py | 99 +++++++++++++++++++++++++--------------------- myapp.py | 40 +++++++++---------- 2 files changed, 75 insertions(+), 64 deletions(-) diff --git a/algorithm/s_bfl.py b/algorithm/s_bfl.py index a0a3240..1ff47c2 100644 --- a/algorithm/s_bfl.py +++ b/algorithm/s_bfl.py @@ -29,37 +29,48 @@ def input(self, input_data, sysnum, t_lim = 10, jit=False, **kwargs): self.jit = jit self.sysnum = sysnum self.params = create_data(input_data, self.sysnum, **kwargs) - (*_, self.a, self.c_op, self.c_op_jit, self.c_pen, self.cfs, self.cs, self.cs_jit, - self.csk, self.d, self.hf, self.hs, self.U, self.UE, self.UE_jit) = self.params.values() + (*_, self.harvested, self.operating_cost, self.operating_cost_jit, self.c_pen, self.farm_ssl_trans_cost, self.ssl_refinery_trans_cost, self.ssl_refinery_jit_trans_cost, + self.fixed_cost_ssls, self.demand, self.farm_holding_cost, self.ssl_holding_cost, self.upperbound_inventory, self.upperbound_equip_proc_rate, self.upperbound_equip_proc_rate_jit) = self.params.values() def solve(self): - # variable names let's make it clear - T = list(range(1, len(self.d))) - F = list(range(len(self.cfs))) - S = list(range(len(self.csk))) - K = list(range(len(self.U))) - a = np.array(self.a) - M = a.sum(axis=0) - c_zfs = (np.array(self.cfs) + self.c_op).tolist() - c_z_jit = (np.array(self.cs_jit)[None] + np.array(self.cfs) + self.c_op_jit).tolist() + # T, F, S, K : Set of time periods, farms, potential SSL sites, and available types of SSLs, respectively + # t, f, s, k : element of T, F, S, K + T = list(range(1, len(self.demand))) + F = list(range(len(self.farm_ssl_trans_cost))) + S = list(range(len(self.fixed_cost_ssls))) + K = list(range(len(self.upperbound_inventory))) + + harvested = np.array(self.harvested) + M = harvested.sum(axis=0) + farm_ssl_cost_per_period = (np.array(self.farm_ssl_trans_cost) + self.operating_cost).tolist() + jit_trans_costs = (np.array(self.ssl_refinery_jit_trans_cost)[None] + np.array(self.farm_ssl_trans_cost) + self.operating_cost_jit).tolist() logger.info("Parameters created. Begin building model.") m = Model('ms1m_base') + # ++++++ Linear Programming Notation ++++++ # ====== Create vars and objectives ====== - w = m.addVars(S, K, obj=self.csk, vtype='B', name='w') + + # w[s][k] = 1 => is an ssl of type k is built at site s; otherwise 0 + w = m.addVars(S, K, obj=self.fixed_cost_ssls, vtype='B', name='w') + + # y[f][s] = 1 => if farm f supplies ssl s; 0 otherwise y = m.addVars(F, S, vtype='B', name='y') - zfs = m.addVars(T, F, S, obj=c_zfs * len(T), name='zfs') - zs = m.addVars(T, S, obj=self.cs * len(T), name='zs') - Is = m.addVars([0] + T, S, obj=self.hs, name='Is') - If = m.addVars([0] + T, F, obj=self.hf, name='If') + + shipped_farm_ssl = m.addVars(T, F, S, obj=farm_ssl_cost_per_period * len(T), name='shipped_farm_ssl') + shipped_ssl_refinery = m.addVars(T, S, obj=self.ssl_refinery_trans_cost * len(T), name='shipped_ssl_refinery') + + # Note: inventory levels taken at the end of period t + inventory_level_ssl = m.addVars([0] + T, S, obj=self.ssl_holding_cost, name='inventory_level_ssl') + inventory_level_farm = m.addVars([0] + T, F, obj=self.farm_holding_cost, name='inventory_level_farm') + if self.jit: - z_jit = m.addVars(T, F, S, obj=c_z_jit * len(T), name='z_jit') + z_jit = m.addVars(T, F, S, obj=jit_trans_costs * len(T), name='z_jit') penalty = m.addVars(T, obj=self.c_pen, name='penalty') - m.setAttr('UB', Is.select(0, '*'), [0] * len(S)) - m.setAttr('UB', If.select(0, '*'), [0] * len(F)) + m.setAttr('UB', inventory_level_ssl.select(0, '*'), [0] * len(S)) + m.setAttr('UB', inventory_level_farm.select(0, '*'), [0] * len(F)) m.ModelSense = GRB.MINIMIZE @@ -67,42 +78,42 @@ def solve(self): m.addConstrs((w.sum(s, '*') <= 1 for s in S), name='c1') m.addConstrs((y[f, s] <= w.sum(s, '*') for f in F for s in S), name='c2') m.addConstrs((y.sum(f, '*') == 1 for f in F), name='c3') - m.addConstrs((Is[t, s] == Is[t - 1, s] - zs[t, s] + zfs.sum(t, '*', s) + m.addConstrs((inventory_level_ssl[t, s] == inventory_level_ssl[t - 1, s] - shipped_ssl_refinery[t, s] + shipped_farm_ssl.sum(t, '*', s) for t in T for s in S), name='c4') - m.addConstrs((Is[t, s] <= quicksum([self.U[k] * w[s, k] for k in K]) for t in T + m.addConstrs((inventory_level_ssl[t, s] <= quicksum([self.upperbound_inventory[k] * w[s, k] for k in K]) for t in T for s in S), name='c7') - m.addConstrs((zfs.sum(t, '*', s) <= quicksum([self.UE[k] * w[s, k] for k in K]) + m.addConstrs((shipped_farm_ssl.sum(t, '*', s) <= quicksum([self.upperbound_equip_proc_rate[k] * w[s, k] for k in K]) for t in T for s in S), name='c9a') if not self.jit: - m.addConstrs((If[t, f] == If[t - 1, f] + a[t, f] - zfs.sum(t, f, '*') + m.addConstrs((inventory_level_farm[t, f] == inventory_level_farm[t - 1, f] + harvested[t, f] - shipped_farm_ssl.sum(t, f, '*') for t in T for f in F), name='c5') - m.addConstrs((zs.sum(t, '*') + penalty[t] == self.d[t] for t in T), + m.addConstrs((shipped_ssl_refinery.sum(t, '*') + penalty[t] == self.demand[t] for t in T), name='c6') m.addConstrs( - (zfs.sum('*', f, s) <= M[f] * y[f, s] for f in F for s in S), + (shipped_farm_ssl.sum('*', f, s) <= M[f] * y[f, s] for f in F for s in S), name='c8') m.addConstrs( - (zfs.sum(t, '*', s) <= quicksum([self.UE_jit[k] * w[s, k] for k in K]) + (shipped_farm_ssl.sum(t, '*', s) <= quicksum([self.upperbound_equip_proc_rate_jit[k] * w[s, k] for k in K]) for t in T for s in S), name='c9b') else: - m.addConstrs((If[t, f] == If[t - 1, f] + a[t, f] - zfs.sum(t, f, '*') - + m.addConstrs((inventory_level_farm[t, f] == inventory_level_farm[t - 1, f] + harvested[t, f] - shipped_farm_ssl.sum(t, f, '*') - z_jit.sum(t, f, '*') for t in T for f in F), name='c5') m.addConstrs( - (z_jit.sum(t, '*', '*') + zs.sum(t, '*') + penalty[t] == self.d[t] + (z_jit.sum(t, '*', '*') + shipped_ssl_refinery.sum(t, '*') + penalty[t] == self.demand[t] for t in T), name='c6') m.addConstrs( - (z_jit.sum('*', f, s) + zfs.sum('*', f, s) <= M[f] * y[f, s] + (z_jit.sum('*', f, s) + shipped_farm_ssl.sum('*', f, s) <= M[f] * y[f, s] for f in F for s in S), name='c8') - m.addConstrs((z_jit.sum(t, '*', s) + zfs.sum(t, '*', s) <= quicksum( - [self.UE_jit[k] * w[s, k] for k in K]) for t in T for s in S), + m.addConstrs((z_jit.sum(t, '*', s) + shipped_farm_ssl.sum(t, '*', s) <= quicksum( + [self.upperbound_equip_proc_rate_jit[k] * w[s, k] for k in K]) for t in T for s in S), name='c9b') logger.info("Model created. Begin solving.") @@ -148,25 +159,25 @@ def solve(self): cost_total = m.objVal gap = (cost_total - cost_total_lb) / cost_total # what does cost locations mean? - cost_loc = w.prod({(s, k): self.csk[s][k] for s in S for k in K}).getValue() + cost_loc = w.prod({(s, k): self.fixed_cost_ssls[s][k] for s in S for k in K}).getValue() - cost_op = zfs.sum().getValue() * self.c_op - cfs_dict = {(t, f, s): self.cfs[f][s] for t, f, s in setprod(T, F, S)} + cost_op = shipped_farm_ssl.sum().getValue() * self.operating_cost + cfs_dict = {(t, f, s): self.farm_ssl_trans_cost[f][s] for t, f, s in setprod(T, F, S)} # cost of transporting from f to s in time t - cost_tran_fs = zfs.prod(cfs_dict).getValue() + cost_tran_fs = shipped_farm_ssl.prod(cfs_dict).getValue() # what does the b stand for? - cost_tran_sb = zs.prod({(t, s): self.cs[s] + cost_tran_sb = shipped_ssl_refinery.prod({(t, s): self.ssl_refinery_trans_cost[s] for t in T for s in S}).getValue() if self.jit: - cost_op += z_jit.sum().getValue() * self.c_op_jit + cost_op += z_jit.sum().getValue() * self.operating_cost_jit cost_tran_fs += z_jit.prod(cfs_dict).getValue() - cost_tran_sb += z_jit.prod({(t, f, s): self.cs_jit[s] + cost_tran_sb += z_jit.prod({(t, f, s): self.ssl_refinery_jit_trans_cost[s] for t in T for f in F for s in S}).getValue() - cost_inv_S = Is.sum().getValue() * self.hs - cost_inv_F = If.sum().getValue() * self.hf + cost_inv_S = inventory_level_ssl.sum().getValue() * self.ssl_holding_cost + cost_inv_F = inventory_level_farm.sum().getValue() * self.farm_holding_cost K_cnt = dict(Counter(k for s in S for k in K if w[s, k].x > 0.5)) jit_amount = z_jit.sum().getValue() if self.jit else np.nan @@ -200,14 +211,14 @@ def solve(self): 'inv_f': cost_inv_F, 'inv_s': cost_inv_S, } - a_sum = float(a.sum()) + harvested_sum = float(harvested.sum()) summary['per_dry_Mg'] = { - k: v / a_sum + k: v / harvested_sum for k, v in summary['cost'].items() } summary['trans_amount'] = { - 'base_fs': zfs.sum().getValue(), - 'base_sb': zs.sum().getValue(), + 'base_fs': shipped_farm_ssl.sum().getValue(), + 'base_sb': shipped_ssl_refinery.sum().getValue(), 'jit': jit_amount } diff --git a/myapp.py b/myapp.py index d2aefd0..c36b495 100644 --- a/myapp.py +++ b/myapp.py @@ -11,9 +11,9 @@ from flask import Flask, render_template, request, send_from_directory, jsonify, send_file from algorithm.tsp import tsp from algorithm.s_bfl import s_bfl -from email_credentials import credentials -from flask_mail import Mail -from flask_mail import Message +# from email_credentials import credentials +# from flask_mail import Mail +# from flask_mail import Message from flask_cors import CORS class CustomFlask(Flask): @@ -27,20 +27,20 @@ class CustomFlask(Flask): app = CustomFlask(__name__,template_folder='') # This replaces your existing "app = Flask(__name__)" CORS(app) -c = credentials() -c.setPassword() +# c = credentials() +# c.setPassword() -app.config.update( - DEBUG = True, - MAIL_SERVER = 'smtp.gmail.com', - MAIL_PORT = 465, - MAIL_USE_SSL = True, - MAIL_USERNAME = 'robert.b.shelton.42@gmail.com', - MAIL_PASSWORD = c.password, -) +# app.config.update( +# DEBUG = True, +# MAIL_SERVER = 'smtp.gmail.com', +# MAIL_PORT = 465, +# MAIL_USE_SSL = True, +# MAIL_USERNAME = 'robert.b.shelton.42@gmail.com', +# MAIL_PASSWORD = c.password, +# ) -mail = Mail(app) +# mail = Mail(app) @app.route('/s-bfls/', methods=['POST']) def Sbfl(): @@ -50,13 +50,13 @@ def Sbfl(): my_s_bfl.solve() print(my_s_bfl.optimization_result) response = jsonify(my_s_bfl.optimization_result) - response.headers.add('Access-Control-Allow-Origin', '*') + # response.headers.add('Access-Control-Allow-Origin', '*') - msg = Message('S-BFLS', - sender="robert.b.shelton.42@gmail.com", - recipients=["robes98@vt.edu"]) - msg.body = "Thanks for using SBFLS! Attached are our results." - mail.send(msg) + # msg = Message('S-BFLS', + # sender="robert.b.shelton.42@gmail.com", + # recipients=["robes98@vt.edu"]) + # msg.body = "Thanks for using SBFLS! Attached are our results." + # mail.send(msg) return response @app.errorhandler(404) From 33339fd52c5629512bc933d50067d9657fe7d29f Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 20 Feb 2019 12:32:59 -0500 Subject: [PATCH 3/3] Changed names working test for backwards compatability --- algorithm/s_bfl.py | 125 ++++++++++++++++++++++++--------------------- myapp.py | 40 +++++++-------- 2 files changed, 87 insertions(+), 78 deletions(-) diff --git a/algorithm/s_bfl.py b/algorithm/s_bfl.py index a0a3240..b69eb19 100644 --- a/algorithm/s_bfl.py +++ b/algorithm/s_bfl.py @@ -29,37 +29,48 @@ def input(self, input_data, sysnum, t_lim = 10, jit=False, **kwargs): self.jit = jit self.sysnum = sysnum self.params = create_data(input_data, self.sysnum, **kwargs) - (*_, self.a, self.c_op, self.c_op_jit, self.c_pen, self.cfs, self.cs, self.cs_jit, - self.csk, self.d, self.hf, self.hs, self.U, self.UE, self.UE_jit) = self.params.values() + (*_, self.harvested, self.operating_cost, self.operating_cost_jit, self.c_pen, self.farm_ssl_trans_cost, self.ssl_refinery_trans_cost, self.ssl_refinery_jit_trans_cost, + self.fixed_cost_ssls, self.demand, self.farm_holding_cost, self.ssl_holding_cost, self.upperbound_inventory, self.upperbound_equip_proc_rate, self.upperbound_equip_proc_rate_jit) = self.params.values() def solve(self): - # variable names let's make it clear - T = list(range(1, len(self.d))) - F = list(range(len(self.cfs))) - S = list(range(len(self.csk))) - K = list(range(len(self.U))) - a = np.array(self.a) - M = a.sum(axis=0) - c_zfs = (np.array(self.cfs) + self.c_op).tolist() - c_z_jit = (np.array(self.cs_jit)[None] + np.array(self.cfs) + self.c_op_jit).tolist() + # T, F, S, K : Set of time periods, farms, potential SSL sites, and available types of SSLs, respectively + # t, f, s, k : element of T, F, S, K + T = list(range(1, len(self.demand))) + F = list(range(len(self.farm_ssl_trans_cost))) + S = list(range(len(self.fixed_cost_ssls))) + K = list(range(len(self.upperbound_inventory))) + + harvested = np.array(self.harvested) + M = harvested.sum(axis=0) + farm_ssl_cost_per_period = (np.array(self.farm_ssl_trans_cost) + self.operating_cost).tolist() + jit_trans_costs = (np.array(self.ssl_refinery_jit_trans_cost)[None] + np.array(self.farm_ssl_trans_cost) + self.operating_cost_jit).tolist() logger.info("Parameters created. Begin building model.") m = Model('ms1m_base') + # ++++++ Linear Programming Notation ++++++ # ====== Create vars and objectives ====== - w = m.addVars(S, K, obj=self.csk, vtype='B', name='w') + + # w[s][k] = 1 => is an ssl of type k is built at site s; otherwise 0 + w = m.addVars(S, K, obj=self.fixed_cost_ssls, vtype='B', name='w') + + # y[f][s] = 1 => if farm f supplies ssl s; 0 otherwise y = m.addVars(F, S, vtype='B', name='y') - zfs = m.addVars(T, F, S, obj=c_zfs * len(T), name='zfs') - zs = m.addVars(T, S, obj=self.cs * len(T), name='zs') - Is = m.addVars([0] + T, S, obj=self.hs, name='Is') - If = m.addVars([0] + T, F, obj=self.hf, name='If') + + shipped_farm_ssl = m.addVars(T, F, S, obj=farm_ssl_cost_per_period * len(T), name='shipped_farm_ssl') + shipped_ssl_refinery = m.addVars(T, S, obj=self.ssl_refinery_trans_cost * len(T), name='shipped_ssl_refinery') + + # Note: inventory levels taken at the end of period t + inventory_level_ssl = m.addVars([0] + T, S, obj=self.ssl_holding_cost, name='inventory_level_ssl') + inventory_level_farm = m.addVars([0] + T, F, obj=self.farm_holding_cost, name='inventory_level_farm') + if self.jit: - z_jit = m.addVars(T, F, S, obj=c_z_jit * len(T), name='z_jit') + z_jit = m.addVars(T, F, S, obj=jit_trans_costs * len(T), name='z_jit') penalty = m.addVars(T, obj=self.c_pen, name='penalty') - m.setAttr('UB', Is.select(0, '*'), [0] * len(S)) - m.setAttr('UB', If.select(0, '*'), [0] * len(F)) + m.setAttr('UB', inventory_level_ssl.select(0, '*'), [0] * len(S)) + m.setAttr('UB', inventory_level_farm.select(0, '*'), [0] * len(F)) m.ModelSense = GRB.MINIMIZE @@ -67,42 +78,42 @@ def solve(self): m.addConstrs((w.sum(s, '*') <= 1 for s in S), name='c1') m.addConstrs((y[f, s] <= w.sum(s, '*') for f in F for s in S), name='c2') m.addConstrs((y.sum(f, '*') == 1 for f in F), name='c3') - m.addConstrs((Is[t, s] == Is[t - 1, s] - zs[t, s] + zfs.sum(t, '*', s) + m.addConstrs((inventory_level_ssl[t, s] == inventory_level_ssl[t - 1, s] - shipped_ssl_refinery[t, s] + shipped_farm_ssl.sum(t, '*', s) for t in T for s in S), name='c4') - m.addConstrs((Is[t, s] <= quicksum([self.U[k] * w[s, k] for k in K]) for t in T + m.addConstrs((inventory_level_ssl[t, s] <= quicksum([self.upperbound_inventory[k] * w[s, k] for k in K]) for t in T for s in S), name='c7') - m.addConstrs((zfs.sum(t, '*', s) <= quicksum([self.UE[k] * w[s, k] for k in K]) + m.addConstrs((shipped_farm_ssl.sum(t, '*', s) <= quicksum([self.upperbound_equip_proc_rate[k] * w[s, k] for k in K]) for t in T for s in S), name='c9a') if not self.jit: - m.addConstrs((If[t, f] == If[t - 1, f] + a[t, f] - zfs.sum(t, f, '*') + m.addConstrs((inventory_level_farm[t, f] == inventory_level_farm[t - 1, f] + harvested[t, f] - shipped_farm_ssl.sum(t, f, '*') for t in T for f in F), name='c5') - m.addConstrs((zs.sum(t, '*') + penalty[t] == self.d[t] for t in T), + m.addConstrs((shipped_ssl_refinery.sum(t, '*') + penalty[t] == self.demand[t] for t in T), name='c6') m.addConstrs( - (zfs.sum('*', f, s) <= M[f] * y[f, s] for f in F for s in S), + (shipped_farm_ssl.sum('*', f, s) <= M[f] * y[f, s] for f in F for s in S), name='c8') m.addConstrs( - (zfs.sum(t, '*', s) <= quicksum([self.UE_jit[k] * w[s, k] for k in K]) + (shipped_farm_ssl.sum(t, '*', s) <= quicksum([self.upperbound_equip_proc_rate_jit[k] * w[s, k] for k in K]) for t in T for s in S), name='c9b') else: - m.addConstrs((If[t, f] == If[t - 1, f] + a[t, f] - zfs.sum(t, f, '*') - + m.addConstrs((inventory_level_farm[t, f] == inventory_level_farm[t - 1, f] + harvested[t, f] - shipped_farm_ssl.sum(t, f, '*') - z_jit.sum(t, f, '*') for t in T for f in F), name='c5') m.addConstrs( - (z_jit.sum(t, '*', '*') + zs.sum(t, '*') + penalty[t] == self.d[t] + (z_jit.sum(t, '*', '*') + shipped_ssl_refinery.sum(t, '*') + penalty[t] == self.demand[t] for t in T), name='c6') m.addConstrs( - (z_jit.sum('*', f, s) + zfs.sum('*', f, s) <= M[f] * y[f, s] + (z_jit.sum('*', f, s) + shipped_farm_ssl.sum('*', f, s) <= M[f] * y[f, s] for f in F for s in S), name='c8') - m.addConstrs((z_jit.sum(t, '*', s) + zfs.sum(t, '*', s) <= quicksum( - [self.UE_jit[k] * w[s, k] for k in K]) for t in T for s in S), + m.addConstrs((z_jit.sum(t, '*', s) + shipped_farm_ssl.sum(t, '*', s) <= quicksum( + [self.upperbound_equip_proc_rate_jit[k] * w[s, k] for k in K]) for t in T for s in S), name='c9b') logger.info("Model created. Begin solving.") @@ -148,31 +159,28 @@ def solve(self): cost_total = m.objVal gap = (cost_total - cost_total_lb) / cost_total # what does cost locations mean? - cost_loc = w.prod({(s, k): self.csk[s][k] for s in S for k in K}).getValue() + cost_loc = w.prod({(s, k): self.fixed_cost_ssls[s][k] for s in S for k in K}).getValue() - cost_op = zfs.sum().getValue() * self.c_op - cfs_dict = {(t, f, s): self.cfs[f][s] for t, f, s in setprod(T, F, S)} + cost_op = shipped_farm_ssl.sum().getValue() * self.operating_cost + cfs_dict = {(t, f, s): self.farm_ssl_trans_cost[f][s] for t, f, s in setprod(T, F, S)} # cost of transporting from f to s in time t - cost_tran_fs = zfs.prod(cfs_dict).getValue() - # what does the b stand for? - cost_tran_sb = zs.prod({(t, s): self.cs[s] + cost_tran_fs = shipped_farm_ssl.prod(cfs_dict).getValue() + cost_tran_sr = shipped_ssl_refinery.prod({(t, s): self.ssl_refinery_trans_cost[s] for t in T for s in S}).getValue() if self.jit: - cost_op += z_jit.sum().getValue() * self.c_op_jit + cost_op += z_jit.sum().getValue() * self.operating_cost_jit cost_tran_fs += z_jit.prod(cfs_dict).getValue() - cost_tran_sb += z_jit.prod({(t, f, s): self.cs_jit[s] + cost_tran_sr += z_jit.prod({(t, f, s): self.ssl_refinery_jit_trans_cost[s] for t in T for f in F for s in S}).getValue() - cost_inv_S = Is.sum().getValue() * self.hs - cost_inv_F = If.sum().getValue() * self.hf + cost_inv_S = inventory_level_ssl.sum().getValue() * self.ssl_holding_cost + cost_inv_F = inventory_level_farm.sum().getValue() * self.farm_holding_cost K_cnt = dict(Counter(k for s in S for k in K if w[s, k].x > 0.5)) jit_amount = z_jit.sum().getValue() if self.jit else np.nan - # why do we need to send the user every variable value? - # is there a cleaner way to do this? # maybe a function for getting all the variables that are active and convert to lat, lng? # getActiveRoutes() # Binary encoding of open ssls @@ -182,32 +190,33 @@ def solve(self): 'status': status[m.status], 'CPU_time': m.runtime, 'gap': gap, - 'K': len(K), - 'T': len(T), - 'F': len(F), - 'S': len(S), - 'num_SSL': w.sum().getValue(), + 'available_types_ssl': len(K), + 'num_weeks_horizon': len(T), + 'num_farms': len(F), + # I'm not super sure about the ssl one + 'num_ssls_considered': len(S), + 'num_ssls_used': w.sum().getValue(), 'SSL_type_cnt': K_cnt, } summary['cost'] = { - 'lb': cost_total_lb, - 'ub': cost_total, + 'total_lb': cost_total_lb, + 'total_ub': cost_total, 'penalty': penalty.sum().getValue(), 'operation': cost_op, 'loc_own': cost_loc, - 'tran_fs': cost_tran_fs, - 'tran_sb': cost_tran_sb, - 'inv_f': cost_inv_F, - 'inv_s': cost_inv_S, + 'tran_farms_ssl': cost_tran_fs, + 'tran_ssl_refinery': cost_tran_sr, + 'farm_inventory': cost_inv_F, + 'ssl_inventory': cost_inv_S, } - a_sum = float(a.sum()) + harvested_sum = float(harvested.sum()) summary['per_dry_Mg'] = { - k: v / a_sum + k: v / harvested_sum for k, v in summary['cost'].items() } summary['trans_amount'] = { - 'base_fs': zfs.sum().getValue(), - 'base_sb': zs.sum().getValue(), + 'base_fs': shipped_farm_ssl.sum().getValue(), + 'base_sb': shipped_ssl_refinery.sum().getValue(), 'jit': jit_amount } diff --git a/myapp.py b/myapp.py index d2aefd0..c36b495 100644 --- a/myapp.py +++ b/myapp.py @@ -11,9 +11,9 @@ from flask import Flask, render_template, request, send_from_directory, jsonify, send_file from algorithm.tsp import tsp from algorithm.s_bfl import s_bfl -from email_credentials import credentials -from flask_mail import Mail -from flask_mail import Message +# from email_credentials import credentials +# from flask_mail import Mail +# from flask_mail import Message from flask_cors import CORS class CustomFlask(Flask): @@ -27,20 +27,20 @@ class CustomFlask(Flask): app = CustomFlask(__name__,template_folder='') # This replaces your existing "app = Flask(__name__)" CORS(app) -c = credentials() -c.setPassword() +# c = credentials() +# c.setPassword() -app.config.update( - DEBUG = True, - MAIL_SERVER = 'smtp.gmail.com', - MAIL_PORT = 465, - MAIL_USE_SSL = True, - MAIL_USERNAME = 'robert.b.shelton.42@gmail.com', - MAIL_PASSWORD = c.password, -) +# app.config.update( +# DEBUG = True, +# MAIL_SERVER = 'smtp.gmail.com', +# MAIL_PORT = 465, +# MAIL_USE_SSL = True, +# MAIL_USERNAME = 'robert.b.shelton.42@gmail.com', +# MAIL_PASSWORD = c.password, +# ) -mail = Mail(app) +# mail = Mail(app) @app.route('/s-bfls/', methods=['POST']) def Sbfl(): @@ -50,13 +50,13 @@ def Sbfl(): my_s_bfl.solve() print(my_s_bfl.optimization_result) response = jsonify(my_s_bfl.optimization_result) - response.headers.add('Access-Control-Allow-Origin', '*') + # response.headers.add('Access-Control-Allow-Origin', '*') - msg = Message('S-BFLS', - sender="robert.b.shelton.42@gmail.com", - recipients=["robes98@vt.edu"]) - msg.body = "Thanks for using SBFLS! Attached are our results." - mail.send(msg) + # msg = Message('S-BFLS', + # sender="robert.b.shelton.42@gmail.com", + # recipients=["robes98@vt.edu"]) + # msg.body = "Thanks for using SBFLS! Attached are our results." + # mail.send(msg) return response @app.errorhandler(404)