def fit_mdl_obj(x, *args): # obj function to fit TTA and AHT for each language, region, type combination to match ABN and SLA # note the obj is the generalized MAPE for each. This is to compensate over-weighting for low prob entries tta, aht = x row, t = args mdl_abn, abn = eA.abn_prob(row['calls'], 1 / aht, row['servers'], 1 / tta), row['pct_abn'] mdl_sla, sla = eA.sla_prob(row['calls'], 1 / tta, row['servers'], 1 / aht, t), row['sla_120'] return ((mdl_abn - abn) / (mdl_abn + abn))**2 + ((mdl_sla - sla) / (mdl_sla + sla))**2
def threshold(a_df, p_esc, t): # gets the optimal routing between TR and NT per language, region pair tr_row = a_df[a_df['type'] == 'Trip'] nt_row = a_df[a_df['type'] == 'NonTrip'] m_tr = tr_row['servers'].values[0] m_nt = nt_row['servers'].values[0] calls_tr = tr_row['calls'].values[0] calls_nt = nt_row['calls'].values[0] calls = calls_tr + calls_nt aht_tr = tr_row['mdl_aht'].values[0] aht_nt = nt_row['mdl_aht'].values[0] tta_tr = tr_row['mdl_tta'].values[0] tta_nt = nt_row['mdl_tta'].values[0] args = (calls, p_esc, t, calls_tr, calls_nt, tta_tr, tta_nt, aht_tr, aht_nt, m_tr, m_nt) p0 = (0.5, ) res = minimize(t_obj, x0=p0, bounds=((0.1, 0.95), ), args=args, method='SLSQP') opt_pr = res.x[0] a_df.sort_values(by='type', inplace=True) # NonTrip, Trip a_df['p_tr'] = [calls_nt / calls, calls_tr / calls] a_df['mdl_p_tr'] = [1 - opt_pr, opt_pr] a_df['mdl_adj_sla'] = [ eA.sla_prob((1 - opt_pr) * calls, 1 / aht_nt, m_nt, 1 / tta_nt, t), eA.sla_prob((opt_pr + p_esc * (1 - opt_pr)) * calls, 1 / aht_tr, m_tr, 1 / tta_tr, t) ] a_df['mdl_adj_abn'] = [ eA.abn_prob((1 - opt_pr) * calls, 1 / aht_nt, m_nt, 1 / tta_nt), eA.abn_prob((opt_pr + (1 - opt_pr) * p_esc) * calls, 1 / aht_tr, m_tr, 1 / tta_tr) ] return a_df
def t_obj(p_tr, *args): # basic objective function for optimal routing: minimize the sum of mse of SLA and ABN for both trip and not trip # we could weight TR more heavily # Note that that obj function ensure to be close to the SLA and ABN but we may violate them # should try constraints on TR and minimize on NT calls, p_esc, t, calls_tr, calls_nt, tta_tr, tta_nt, aht_tr, aht_nt, m_tr, m_nt = args nt_abn = eA.abn_prob((1 - p_tr) * calls, 1 / aht_nt, m_nt, 1 / tta_nt) tr_abn = eA.abn_prob((p_tr + (1 - p_tr) * p_esc) * calls, 1 / aht_tr, m_tr, 1 / tta_tr) nt_sla = eA.sla_prob((1 - p_tr) * calls, 1 / aht_nt, m_nt, 1 / tta_nt, t) tr_sla = eA.sla_prob((p_tr + p_esc * (1 - p_tr)) * calls, 1 / aht_tr, m_tr, 1 / tta_tr, t) try: nt_abn_err = (0.15 - nt_abn)**2 tr_abn_err = (0.15 - tr_abn)**2 nt_sla_err = (0.8 - nt_sla)**2 tr_sla_err = (0.8 - tr_sla)**2 return tr_sla_err + tr_abn_err + nt_sla_err + nt_abn_err except TypeError: print('OBJ:::' + str(calls) + ' ' + str(p_tr) + ' nt: ' + str((1 - p_tr) * calls) + ' tr: ' + str((p_tr + p_esc * (1 - p_tr)) * calls, )) return 100
def fit_mdl(row, aht_tr, aht_nt, t): # finds TTA and AHT for each row in the data # x0 = TTA, AHT aht = get_aht(row, aht_tr, aht_nt) bounds = ((1, 50), (0.5 * aht, 2.0 * aht)) x0 = tuple([(x[0] + x[1]) / 2 for x in bounds]) args = (row, t) res = minimize(fit_mdl_obj, x0=x0, bounds=bounds, args=args, method='SLSQP') if res.status == 0: row['mdl_tta'], row['mdl_aht'] = res.x row['mdl_pct_abn'] = eA.abn_prob(row['calls'], 1 / row['mdl_aht'], row['servers'], 1 / row['mdl_tta']) row['mdl_sla_120'] = eA.sla_prob(row['calls'], 1 / row['mdl_aht'], row['servers'], 1 / row['mdl_tta'], t) else: print('no convergence for ' + str(row)) return row
lbda_arr, TTA_arr, m_arr, pab_arr, t_arr, q_arr, util_arr = list(), list( ), list(), list(), list(), list(), list() for TTA in [5, 10, 15]: theta = 1 / TTA for lbda in np.linspace(10, 100, 10): m_max = 4 * lbda / mu for t in np.linspace(0, 5, 6): m = m_max w = eA.sla_prob(lbda, mu, m_max, theta, t) - q_SLA while w >= 0: m -= 1 w = eA.sla_prob(lbda, mu, m, theta, t) - q_SLA pab = eA.abn_prob(lbda, mu, m, theta) lbda_arr.append(lbda) TTA_arr.append(TTA) m_arr.append(m) pab_arr.append(pab) t_arr.append(t) q_arr.append(eA.sla_prob(lbda, mu, m, theta, t)) util_arr.append(lbda * (1 - pab) / (m * mu)) print('lbda: ' + str(lbda) + ' t: ' + str(t) + ' m: ' + str(int(m)) + ' pab: ' + str(eA.abn_prob(lbda, mu, m, theta)) + ' q: ' + str(eA.sla_prob(lbda, mu, m, theta, t))) df = pd.DataFrame({ 'interactions/min': lbda_arr, 'prob_abn': pab_arr, 'TTA': TTA_arr,