def get_initcoeffs(lcoeff, poly):
    #iterate until convergence to find fixed point

    nfunc = poly['nfunc']
    npoly = poly['npoly']
    ns = poly['ns']
    nmsv = poly['nmsv']

    acoeff0 = np.zeros([ns, nfunc * npoly])
    for i in np.arange(ns):
        polyapp = np.zeros([npoly, nfunc])
        if poly['ne'] > 0:
            shk = poly['exoggrid'][i, :]
        for ip in np.arange(npoly):
            msvm1 = po.msv2xx(poly['pgrid'][ip, :], nmsv, poly['scxx2msv'])
            if poly['ne'] == 0:
                msvm1plus = msvm1
            else:
                msvm1plus = np.append(msvm1, shk)
            polyapp[ip, :] = np.dot(lcoeff, msvm1plus)
        alphass = np.dot(poly['bbtinv'], polyapp)
        for ip in np.arange(npoly):
            for ifunc in np.arange(nfunc):
                acoeff0[i, ifunc * npoly + ip] = alphass[ip, ifunc]
    return (acoeff0)
def decr(endogvarm1, innov, paramplus, acoeff, poly):
    #decision rule with variables in levels and deviation from steady state.
    endogvar = {}
    kk = endogvarm1['kp_d']
    invm1 = endogvarm1['inv_d']
    shocks = np.zeros(poly['ne'])
    if poly['shockswitch'] == 0:
        shocks[0] = paramplus['rhobeta'] * endogvarm1['beta_d'] + paramplus[
            'stdbeta'] * innov[0]
        if poly['ne'] == 2:
            shocks[1] = paramplus['rhomu'] * endogvarm1['mu_d'] + paramplus[
                'stdmu'] * innov[1]
    else:
        shocks[0] = paramplus['rhomu'] * endogvarm1['mu_d'] + paramplus[
            'stdmu'] * innov[0]
        if poly['ne'] == 2:
            shocks[1] = paramplus['rhobeta'] * endogvarm1[
                'beta_d'] + paramplus['stdbeta'] * innov[1]

    if (poly['ne'] == 0):
        msvm1 = np.array([kk, invm1, shocks[0]])
        xx1 = po.msv2xx(msvm1, poly['nmsv'], poly['scmsv2xx'])
        poly_xx = chebpolytensor(xx1, poly['nmsv'], poly['npoly'],
                                 poly['ncheb'])
        for ifunc in np.arange(nfunc):
            polycur[ifunc] = np.dot(
                acoeff[0, ifunc * poly['npoly']:(ifunc + 1) * poly['npoly']],
                poly_xx)
    else:
        msvm1 = np.array([kk, invm1])
        ind_shocks = po.get_index(shocks, poly['ne'], poly['ngrid'],
                                  poly['steps'], poly['bounds'])
        xx1 = po.msv2xx(msvm1, poly['nmsv'], poly['scmsv2xx'])
        polycur = po.get_linspline(xx1,shocks,ind_shocks,acoeff,poly['exoggrid'],poly['steps'],poly['nfunc'],\
            poly['ngrid'],poly['npoly'],poly['nmsv'],poly['ncheb'],poly['ne'])
    (dvar, lvar) = modelvariables(polycur, msvm1, shocks, paramplus,
                                  poly['eqswitch'], poly['shockswitch'],
                                  poly['ne'])
    for x in lvar:
        endogvar[x] = lvar[x]
        endogvar[x + '_d'] = dvar[x]
    return (endogvar)
def get_quadstates(poly, paramplus):
    #returns exogenous states at each quadrature point and each exogenous grid point

    ninnov = poly['ninnov']
    nqs = poly['nqs']
    ns = poly['ns']
    npoly = poly['npoly']
    ne = ninnov
    quadgrid, quadweight = po.get_quadgrid(poly['nquad'], ninnov, nqs)

    if poly['ne'] == 0:
        nchebexog = np.prod(poly['ncheb'][2:])
        pgridexog = poly['pgrid'][:nchebexog, 2:poly['nmsv']]
        ns = nchebexog
        exoggrid = np.zeros([nchebexog, poly['nmsv'] - 2])
        exogscxx2msv = poly['scxx2msv'][2:poly['nmsv'] * 2:poly['nmsv']]
        for i in np.arange(ns):
            exoggrid[i, :] = po.msv2xx(pgridexog[i, :], poly['nmsv'] - 2,
                                       exogscxx2msv)
    else:
        exoggrid = poly['exoggrid']

    sfut = np.zeros([ns, nqs, ninnov])
    ind_sfut = np.zeros([ns, nqs, ne], dtype=int)
    for j in np.arange(nqs):
        for i in np.arange(ns):
            if poly['shockswitch'] == 0:
                sfut[i, j, 0] = paramplus['rhobeta'] * exoggrid[
                    i, 0] + paramplus['stdbeta'] * quadgrid[j, 0]
                if ninnov == 2:
                    sfut[i, j, 1] = paramplus['rhomu'] * exoggrid[
                        i, 1] + paramplus['stdmu'] * quadgrid[j, 1]
            else:
                sfut[i, j, 0] = paramplus['rhomu'] * exoggrid[
                    i, 0] + paramplus['stdmu'] * quadgrid[j, 0]
                if ninnov == 2:
                    sfut[i, j, 1] = paramplus['rhobeta'] * exoggrid[
                        i, 1] + paramplus['stdbeta'] * quadgrid[j, 1]
            if poly['ne'] > 0:
                ind_sfut[i, j, :] = po.get_index(sfut[i, j, :], ninnov,
                                                 poly['ngrid'], poly['steps'],
                                                 poly['bounds'])
    return (sfut, ind_sfut, quadweight)
def decr(endogvarm1, innov, regime, acoeff, poly, params):
    endogvar = np.zeros(poly['nvars'])
    ne = poly['nexog_fe']
    npoly = poly['npoly']
    nmsv = poly['nmsv']
    nmsve = poly['nexog_nmsv']
    nsreg = poly['nsreg']
    nx = nmsv - nmsve - (nsreg - 1)
    ss = np.zeros(ne + nmsve)
    msvm1 = np.zeros(nmsv)
    shocks = np.zeros(ne + 1)

    #update non-monetary shocks and compute place on grid
    endogvar[
        -6] = params['rhoeta'] * endogvarm1[-4] + params['stdeta'] * innov[0]
    ss[0] = endogvar[-6]
    ind_ss = po.get_index(ss, ne, poly['ngrid'], poly['steps'], poly['bounds'])
    ss[1] = poly['gamma0'][regime] + params['stdm'] * innov[1]
    endogvar[-3] = ss[1]
    endogvar[-4] = params['stdm'] * innov[1]
    endogvar[-5] = poly['gamma0'][regime]
    msvm1[:nx + nsreg - 1] = endogvarm1[:nx + nsreg - 1]
    msvm1[nx + nsreg - 1] = ss[1]
    xxm1 = po.msv2xx(msvm1, nmsv, poly['scmsv2xx'])
    polycur = po.get_linspline(xxm1, ss[:ne], ind_ss, acoeff, poly['exoggrid'],
                               poly['steps'], poly['nfunc'], poly['ngrid'],
                               npoly, nmsv, ne)
    (yy, dp, nr, lptp, post) = modelvariables(polycur, msvm1[:nmsv - nmsve],
                                              ss, params, nmsv, nmsve, nsreg,
                                              poly['gamma0'], poly['P'])
    endogvar[-2] = polycur[0]
    endogvar[-1] = polycur[1]
    endogvar[0] = nr
    endogvar[1] = yy
    endogvar[2] = dp
    if nsreg == 2:
        endogvar[nx] = lptp
    else:
        endogvar[nx:nx + nsreg - 1] = lptp
    endogvar[nx + nsreg - 1:nx + 2 * nsreg - 1] = post
    return (endogvar)
def calc_euler(ind_state, gridindex, acoeff, poly, paramplus):
    npoly = poly['npoly']
    nmsv = poly['nmsv']
    ne = poly['ne']
    polycur = np.zeros([poly['nfunc']])
    polyvarm1 = poly['bbt'][gridindex, :]
    for ifunc in np.arange(poly['nfunc']):
        polycur[ifunc] = np.dot(
            acoeff[ind_state, ifunc * npoly:(ifunc + 1) * npoly], polyvarm1)

    msvm1 = po.msv2xx(poly['pgrid'][gridindex, :], nmsv, poly['scxx2msv'])
    kk = msvm1[0]
    invm1 = msvm1[1]
    if ne == 0:
        shocks = np.zeros(poly['ninnov'])
        shocks[0] = msvm1[2]
    else:
        shocks = poly['exoggrid'][ind_state, :]
    (dvar, lvar) = modelvariables(polycur, msvm1, shocks, paramplus,
                                  poly['eqswitch'], poly['shockswitch'],
                                  poly['ne'])

    ind = npoly * ind_state + gridindex
    ss_futmat = poly['sfutquad'][ind_state, :, :]
    if ne > 0:
        ind_futmat = poly['ind_sfutquad'][ind_state, :, :]
        msv = np.array([dvar['kp'], dvar['inv']])
    else:
        msv = np.zeros(nmsv)
        msv[0] = dvar['kp']
        msv[1] = dvar['inv']

    exp_qeq = 0.
    exp_ieq = 0.
    qweight = (1.0 - paramplus['delta']) / paramplus['gamma']
    for j in np.arange(poly['nqs']):
        if ne == 0:
            msv[2] = ss_futmat[j, :]
        xx1 = po.msv2xx(msv, nmsv, poly['scmsv2xx'])
        if ne == 0:
            poly_xx = po.chebpolytensor(xx1, nmsv, npoly, poly['ncheb'])
            polyfut = np.zeros(poly['nfunc'])
            for ifunc in np.arange(poly['nfunc']):
                polyfut[ifunc] = np.dot(
                    acoeff[0, ifunc * npoly:(ifunc + 1) * npoly], poly_xx)
        else:
            polyfut = po.get_linspline(xx1,ss_futmat[j,:],ind_futmat[j,:],acoeff,poly['exoggrid'],poly['steps'],poly['nfunc'],\
                poly['ngrid'],npoly,nmsv,poly['ncheb'],ne)
        (dvarp, lvarp) = modelvariables(polyfut, msv, ss_futmat[j, :],
                                        paramplus, poly['eqswitch'],
                                        poly['shockswitch'], poly['ne'])
        if (poly['eqswitch'] == 0):
            exp_qeq = exp_qeq + poly['quadweight'][j] * qweight * dvarp['qq']
            exp_ieq = exp_ieq + poly['quadweight'][j] * paramplus['beta'] * (
                dvarp['inv'] - dvar['inv'])
        else:
            exp_qeq = exp_qeq + poly['quadweight'][j] * qweight * lvarp['qq']
            Sprimep = paramplus['b'] * paramplus['a'] * (
                np.exp(paramplus['a'] * (lvarp['inv'] / lvar['inv'] - 1)) - 1)
            exp_ieq = exp_ieq + poly['quadweight'][j] * lvar['beta'] * lvarp[
                'qq'] * lvarp['mu'] * Sprimep * (lvarp['inv'] / lvar['inv'])**2
    polynew = np.zeros(poly['nfunc'])
    if poly['eqswitch'] == 0:
        polynew[0] = invm1 + (1.0 / (paramplus['a']**2 * paramplus['b'])) * (
            dvar['qq'] + dvar['mu']) + exp_ieq
        polynew[1] = -(1 - paramplus['beta'] * qweight) * (
            1.0 - paramplus['alpha']
        ) * dvar['kp'] + paramplus['beta'] * exp_qeq + dvar['beta']
    else:
        linvm1 = np.exp(invm1 + np.log(paramplus['inv']))
        dinv_l = lvar['inv'] / linvm1
        adjcost = paramplus['b'] * (np.exp(paramplus['a'] *
                                           (dinv_l - 1)) - paramplus['a'] *
                                    (dinv_l - 1) - 1)
        stemp = (1 - adjcost - (1.0 - exp_ieq) /
                 (lvar['qq'] * lvar['mu'])) * (1 / dinv_l)
        sarg = 1.0 + (
            1.0 / paramplus['a']) * np.log(1.0 + stemp /
                                           (paramplus['b'] * paramplus['a']))
        polynew[0] = invm1 + np.log(sarg)
        rkp = (paramplus['alpha'] / paramplus['gamma']) * (
            lvar['kp'] / paramplus['gamma'])**(paramplus['alpha'] - 1)
        polynew[1] = np.log(lvar['beta'] * (rkp + exp_qeq))
    res = np.sum(np.abs(polynew - polycur)) / poly['nfunc']
    # if (gridindex == 1):
    #     print('---------------------')
    #     print('kk = ', kk)
    #     print('invm1 = ', invm1)
    #     print('dvar =', dvar)
    #     print(np.abs(polynew-polycur))
    #     print('polycur = ', polycur)
    #     print('exp_qeq = ', exp_qeq)
    #     print('exp_ieq = ', exp_ieq)
    #     print('-----------------')
    #     print('ind_state = ', ind_state)
    #     print('gridindex = ', gridindex)
    #     print('msvm1 = ', msvm1)
    #     print('shocks = ', shocks)
    #     print('---------------------')
    #     print('polynew = ', polynew)
    #     print('res = ', res)
    #     sys.exit('in calc')
    return (polynew, res)
def calc_euler(ind_state, gridindex, acoeff, polyapp, params):
    #returns predicted decision rules and prediction errors
    from sys import exit
    npoly = polyapp['npoly']
    nmsv = polyapp['nmsv']
    nmsve = polyapp['nexog_nmsv']
    ne = polyapp['nexog_fe']
    nsreg = polyapp['nsreg']
    nx = nmsv - nmsve - (nsreg - 1)

    polycur = np.zeros([polyapp['nfunc']])
    polyvarm1 = polyapp['bbt'][gridindex, :]
    for ifunc in np.arange(polyapp['nfunc']):
        polycur[ifunc] = np.dot(
            acoeff[ind_state, ifunc * npoly:(ifunc + 1) * npoly], polyvarm1)

    msvm1 = po.msv2xx(polyapp['pgrid'][gridindex, :], nmsv,
                      polyapp['scxx2msv'])
    ss = np.append(polyapp['exoggrid'][ind_state, :], msvm1[nmsv - nmsve:])
    (yy, dp, nr, lptp,
     posterior) = modelvariables(polycur, msvm1[:nmsv - nmsve], ss, params,
                                 nmsv, nmsve, nsreg, polyapp['gamma0'],
                                 polyapp['P'])

    ind_futmat = polyapp['ind_sfutquad'][ind_state, :, :]
    ss_futmat = polyapp['sfutquad'][ind_state, :, :]

    exp_yyp = 0.
    exp_dpp = 0.
    msv = np.zeros(nmsv)
    if (nx >= 1):
        msv[0] = nr
    if (nx >= 2):
        msv[1] = yy
    if (nx == 3):
        msv[2] = dp

    ptp_c_t = np.zeros(nsreg)
    if (nsreg == 2):
        msv[nx] = lptp[0]
        ptp_c_t[0] = np.exp(msv[nx])
        ptp_c_t[1] = 1.0 - ptp_c_t[0]
    else:
        mid = np.int((nsreg + 1) / 2)
        msv[nx:nx + mid - 1] = lptp[:mid - 1]
        msv[nx + mid - 1:nx + nsreg] = lptp[mid - 1:]
        ptp_c_t[0:mid - 1] = np.exp(msv[nx:nx + mid - 1])
        ptp_c_t[mid:] = np.exp(msv[nx + mid:nx + nsreg])
        temp_arr = np.append(ptp_c_t[:mid - 1], ptp_c_t[mid:])
        ptp_c_t[mid - 1] = 1.0 - np.sum(temp_arr)

    for ireg in np.arange(nsreg):
        for j in np.arange(polyapp['nqs']):
            shockall = ss_futmat[j, :]
            shockall[ne] = polyapp['gamma0'][ireg] + ss_futmat[j, ne]
            msv[nmsv - nmsve] = shockall[ne]
            xx1 = po.msv2xx(msv, nmsv, polyapp['scmsv2xx'])
            polyfut = po.get_linspline(xx1, ss_futmat[j, :ne],
                                       ind_futmat[j, :], acoeff,
                                       polyapp['exoggrid'], polyapp['steps'],
                                       polyapp['nfunc'], polyapp['ngrid'],
                                       npoly, nmsv, ne)
            (yyp, dpp, nrp, lptpp,
             postp) = modelvariables(polyfut, msv[:nmsv - nmsve], shockall,
                                     params, nmsv, nmsve, nsreg,
                                     polyapp['gamma0'], polyapp['P'])
            exp_yyp = exp_yyp + ptp_c_t[ireg] * polyapp['quadweight'][j] * yyp
            exp_dpp = exp_dpp + ptp_c_t[ireg] * polyapp['quadweight'][j] * dpp

    polynew = np.zeros(polyapp['nfunc'])
    polynew[0] = exp_yyp
    polynew[1] = exp_dpp

    # print('difference in coeffs')
    # print(np.abs(polynew-polycur))
    # print('polycur = ', polycur)
    # print('-----------------')
    # print('ind_state = ', ind_state)
    # print('gridindex = ', gridindex)
    # print('msv = ', msv)
    # print('ptp_c_t = ', ptp_c_t)
    # print('polynew = ', polynew)
    # print('data = ', yy,dp,nr,posterior.round(3))
    # exit()
    res = np.sum(np.abs(polynew - polycur)) / (polyapp['nfunc'])
    return (polynew, res)