def _F_const_full(t, X, Y, alphas): # alphas are unravelled here (2d) alphas = np.maximum(0, np.minimum(1, np.atleast_2d(np.array(alphas)))) assert alphas.shape[1] == 2 assert (t - 1) == alphas.shape[0] alphas = np.vstack([alphas, [1, 1]]) tax = list() alpha_ys = list() alpha_xs = list() ys = list() xs = list() Xs = list() Ys = list() x = X / t if isinstance(Y, int) or isinstance(Y, float): Y_state = [Y] # is unused room else: Y_state = list(Y) for i, (alpha_x, alpha_y) in enumerate(alphas): Xs.append(X) alpha_xs.append(alpha_x) alpha_ys.append(alpha_y) x = alpha_x * X X = X - x assert len(Y_state) <= 3 y_max = sum(Y_state) + G(x) assert 0 <= alpha_y <= 1 y = alpha_y * min(x, y_max) # was a bug (X) before! # this years remaining room # yes this is how it works, it is dumb, you can not use up the old stuff first and have room left. the only way of accessing prev room is to over-contribute Y_state.append(max(0, G(x) - y)) Y_state = Y_state[-3:] # keep only last three years! Ys.append(Y_state) xs.append(x) ys.append(y) tax.append(F(x - y)) if _bounds_errors: assert X >= 0 assert sum(Y_state) >= 0 else: pass # if X < 0: # print('WARNING: X = {} >= 0'.format(X)) # if Y < 0: # print('WARNING: Y = {} >= 0'.format(Y)) # as a check, final state Xs.append(X) Ys.append(Y_state) tax_pv = tax / np.power(1 + gamma, np.arange(0, len(tax))) return dict(tax=tax, tax_pv=tax_pv, xs=xs, ys=ys, Ys=Ys, Xs=Xs, alpha_xs=alpha_xs, alpha_ys=alpha_ys, tax_annualized=sum(tax) / t, tax_pv_annualized=sum(tax_pv) / t)
def get_random_sample(t=10, X=1e6): # sample yx s.t. sum(ys) == sum([G(x) for x in xs]) and 0 <= y <= Y_t for y in ys alpha = (1, ) * t # sample xs s.t. sum(xs) == X xs = nr.dirichlet(alpha, size=1)[0] * X taxes = list() ys = list() Ys = list() # initial states Y = 0 y = 0 n = len(xs) for i, x in enumerate(xs): Y = G(x) + Y - y Ys.append(Y) # sample y if not last, else take everythin if i == (n - 1): y = Y else: y = nr.rand() * Y # in [0, Y] taxes.append(F(x - y)) ys.append(y) df = pd.DataFrame(list(zip(xs, ys, Ys, taxes)), columns=['x', 'y', 'Y', 'tax']) return df
def take_step(state, action): # reward too t, X, Y = state if t == 0: raise Exception("terminal state!") x, y = action_to_xy(action, X, Y) state_ = (t - 1, X - x, Y + G(x) - y) return state_
def get_tax_pension_income_fixed_x(t, X, Y, xs, actions): assert t == len(actions) tax = list() ys = list() # pension Xs = list() Ys = list() alpha_ys = list() for i, (x, action) in enumerate(zip(xs, actions)): Xs.append(X) Ys.append(Y) alpha_y = action_to_zeroone(action) # this will work in both cases alpha_ys.append(alpha_y) y = alpha_y * min(X, (Y + G(x))) ys.append(y) tax.append(F(x - y)) X = X - x Y = Y + G(x) - y assert X >= 0 assert Y >= 0 return dict(tax=tax, xs=xs, ys=ys, Ys=Ys, Xs=Xs, alpha_ys=alpha_ys)
def _F_const_full(t, X, Y, alpha_ys): assert (t - 1) == len(alpha_ys) alpha_ys = np.hstack([alpha_ys, 1]) tax = list() ys = list() Xs = list() Ys = list() x = X / t for i, alpha_y in enumerate(alpha_ys): Xs.append(X) Ys.append(Y) y = alpha_y * min(X, (Y + G(x))) ys.append(y) tax.append(F(x - y)) X = X - x Y = Y + G(x) - y assert X >= 0 assert Y >= 0 return dict(tax=tax, xs=np.repeat(x, t), ys=ys, Ys=Ys, Xs=Xs, alpha_ys=alpha_ys)
def tax(xs, ys, t, X, Y=0): # non recursive definition assert len(xs) == len(yx) == len(t) reward = list() tax = list() for i, x, y in zip(range(t), xs, ys): print(i, x, y) Y = Y + G(x) - y X = X - x assert x >= 0 assert y >= 0 assert Y >= 0 assert X >= 0 _tax = F(x - y) tax.append(_tax) reward.append(x - _tax) df = pd.DataFrame(list(zip(xs, ys, tax, reward))) df.columns = ['x', 'y', 'tax', 'reward'] return df
def get_tax_pension_income(t, X, Y, actions): """ just the calc given alphas avoid recursion last step can be sub-optimal, if you want optimal set alpha[-1] = 1 """ assert t == len(actions) tax = list() xs = list() # gross ys = list() # pension Xs = list() Ys = list() alpha_xs = list() alpha_ys = list() for i, action in enumerate(actions): Xs.append(X) Ys.append(Y) alpha_x, alpha_y = action_to_zeroone(action) alpha_xs.append(alpha_x) alpha_ys.append(alpha_y) x, y = action_to_xy(action, X, Y) xs.append(x) ys.append(y) tax.append(F(x - y)) print(action, X) X = X - x print('after', X, x) Y = Y + G(x) - y assert X >= 0 assert Y >= 0 if alpha_x == 1: assert X == 0 # note that Y might not be zero because you can not draw down more than X return dict(tax=tax, xs=xs, yx=ys, Ys=Ys, Xs=Xs, alpha_xs=alpha_xs, alpha_ys=alpha_ys)
def action_to_xy(action, X, Y): alpha_x, alpha_y = action x = alpha_x * X y = alpha_y * (Y + G(x)) return x, y
def terminal_reward(state): t, X, Y = state assert t == 1 # use all X, all all available room (not more than X) y = Y + G(X) return F(X - min(X, y))
def action_to_xy(action, X, Y): # not sure if makes sense for array of actions alpha_x, alpha_y = action_to_zeroone(action) x = alpha_x * X y = alpha_y * min(X, (Y + G(x))) return x, y