def tauchen_nonst(T=40,
                  sigma_persistent=0.05,
                  sigma_init=0.2,
                  npts=50,
                  *,
                  nsd=3,
                  fix_0=False):
    import numpy as np

    # start with creating list of points
    sd_z = sd_rw(T, sigma_persistent, sigma_init)
    X = list()
    Pi = list()

    for t in range(0, T):
        s = t if not fix_0 else 0
        #X = X + [np.linspace(-nsd*sd_z[s],nsd*sd_z[s],num=npts)]
        X = X + [nonuniform_centered_grid(npts, nsd * sd_z[s])]

    # then define a list transition matrices
    # note that Pi[t] is transition matrix from X[t] to X[t+1]

    for t in range(1, T):
        '''
        h = 2*nsd*sd_z[t]/(npts-1) # step size
        Pi_here = np.zeros([npts,npts])
        Pi_here_2 = np.zeros([npts,npts])

        Pi_here[:,0] = normcdf_tr( (X[t][0] - X[t-1][:] + h/2) / sigma_persistent)
        Pi_here[:,-1] = 1.0 - normcdf_tr( (X[t][-1] - X[t-1][:] - h/2) / sigma_persistent)

        for i in range(1,npts-1):
            Pi_here[:,i] = normcdf_tr( (X[t][i] - X[t-1][:] + h/2) / sigma_persistent) - normcdf_tr( (X[t][i] - X[t-1][:] - h/2) / sigma_persistent)

        #print(Pi_here)
        #print(np.sum(Pi_here,axis=1))
        #assert(np.all( abs( np.sum(Pi_here,axis=1) -np.ones(npts) ) < 1e-6 ))
        '''

        Pi_here = np.zeros((npts, npts))
        for i in range(npts):
            Pi_here[i, :] = int_prob(X[t],
                                     X[t - 1][i],
                                     sigma_persistent,
                                     trim=False)

        Pi = Pi + [Pi_here]
        assert np.allclose(Pi_here.sum(axis=1), 1.0)

    Pi = Pi + [None]  # last matrix is not defined

    return X, Pi
Beispiel #2
0
 def mar_mats_assets(self,npoints=4,abar=0.1):
     # for each grid point on single's grid it returns npoints positions
     # on (potential) couple's grid's and assets of potential partner 
     # (that can be off grid) and correpsonding probabilities. 
     
     self.prob_a_mat = dict()
     self.i_a_mat = dict()
     
     na = self.agrid_s.size
     
     agrid_s = self.agrid_s
     agrid_c = self.agrid_c
     
     s_a_partner = self.pars['sig_partner_a']
     
     for female in [True,False]:
         prob_a_mat = np.zeros((na,npoints),dtype=self.dtype)
         i_a_mat = np.zeros((na,npoints),dtype=np.int16)
         
         
         
         for ia, a in enumerate(agrid_s):
             lagrid_t = np.zeros_like(agrid_c)
             
             i_neg = (agrid_c <= max(abar,a) - 1e-6)
             
             # if a is zero this works a bit weird but does the job
             
             lagrid_t[~i_neg] = np.log(2e-6 + (agrid_c[~i_neg] - a)/max(abar,a))
             lmin = lagrid_t[~i_neg].min()
             # just fill with very negative values so this is never chosen
             lagrid_t[i_neg] = lmin - s_a_partner*10 - \
                 s_a_partner*np.flip(np.arange(i_neg.sum())) 
             
             # TODO: this needs to be checked
             if female:
                 mean=self.pars['mean_partner_a_female']
             else:
                 mean=self.pars['mean_partner_a_male']
             p_a = int_prob(lagrid_t,mu=mean,sig=s_a_partner,n_points=npoints)
             i_pa = (-p_a).argsort()[:npoints] # this is more robust then nonzero
             p_pa = p_a[i_pa]
             prob_a_mat[ia,:] = p_pa
             i_a_mat[ia,:] = i_pa
         
         
         self.prob_a_mat[female] = prob_a_mat
         self.i_a_mat[female] = i_a_mat
def nonpar_distribution(z, t, data, nbins, *, female, college):

    if female and college:
        sd = lambda t: np.exp(1.153647 - .013831 * t)
        mu = lambda z, t: .496482 + .2205861 * t + .888435 * z + .0874937 * z * t

    if (not female) and college:
        sd = lambda t: np.exp(1.056854 - .0106599 * t)
        mu = lambda z, t: 1.066965 + .2004596 * t + 1.309432 * z + .0649392 * z * t

    if (female) and (not college):
        sd = lambda t: np.exp(.8055752 + .0050402 * t)
        mu = lambda z, t: .5254092 + .0645352 * t + 1.717792 * z + .0047126 * z * t

    if (not female) and (not college):
        sd = lambda t: np.exp(1.173178 - .0113634 * t)
        mu = lambda z, t: .5254092 + .0645352 * t + 1.717792 * z + .0047126 * z * t

    vec = z
    vm = np.concatenate(([-np.inf], vec[:-1]))
    vp = np.concatenate((vec[1:], [np.inf]))
    z_up = 0.5 * (vec + vp)
    z_down = 0.5 * (vec + vm)
    nz = z.size

    z_probs = np.zeros((z.size, ))
    a_probs_by_z = np.zeros((z.size, nbins))
    a_vals_by_z = np.zeros((z.size, nbins))

    if nbins == 5:
        sa = np.array([-1.5, -0.75, 0.0, 0.75, 1.5])
    else:
        sa = sps.norm.ppf([(i + 1) / (nbins + 1) for i in range(nbins)])

    muz = np.average(data['z'], weights=data['w'])
    sdz = np.sqrt(np.average((data['z'] - muz)**2, weights=data['w']))

    pz_all = int_prob(vec, mu=muz, sig=sdz)

    for iz in range(nz):
        p_groups = np.zeros((nbins))
        a_vals = np.zeros((nbins))

        p_z = pz_all[iz]

        vsd = sd(t)
        vmu = mu(z[iz], t)

        la_vals = vmu + sa * vsd
        p_groups = int_prob(la_vals, mu=vmu, sig=vsd, trim=False)

        a_vals = np.exp(la_vals) * (la_vals >= 0)

        z_probs[iz] = p_z
        a_probs_by_z[iz, :] = p_groups
        a_vals_by_z[iz, :] = a_vals
        #assert np.all(np.diff(a_vals)>=0)
        assert np.allclose(np.sum(p_groups), 1.0)

    assert np.allclose(z_probs.sum(), 1.0)
    return z_probs, a_probs_by_z, a_vals_by_z
Beispiel #4
0
 def _mar_mats(self,t,female=True):
     # this returns transition matrix for single agents into possible couples
     # rows are single's states
     # columnts are couple's states
     # you have to transpose it if you want to use it for integration
     setup = self
     
     nexo = setup.pars['nexo_t'][t]
     sigma_psi_init = setup.pars['sigma_psi_init']
     psi_couple = setup.exogrid.psi_t[t+1]
     
     mu = setup.pars['mu_psi_init']
     
     
     if female:
         nz_single = setup.exogrid.zf_t[t].shape[0]
         p_mat = np.empty((nz_single,nexo))
         z_own = setup.exogrid.zf_t[t]
         n_zown = z_own.shape[0]
         z_partner = setup.exogrid.zm_t[t+1]
         zmat_own = setup.exogrid.zf_t_mat[t]
         pz_precomputed = self.partners_distribution_fem
     else:
         nz_single = setup.exogrid.zm_t[t].shape[0]
         p_mat = np.empty((nz_single,nexo))
         z_own = setup.exogrid.zm_t[t]
         n_zown = z_own.shape[0]
         z_partner = setup.exogrid.zf_t[t+1]
         zmat_own = setup.exogrid.zm_t_mat[t] 
         pz_precomputed = self.partners_distribution_mal
         
     def ind_conv(a,b,c): return setup.all_indices(t,(a,b,c))[0]
     
     pz_all = pz_precomputed['prob_z']
     
     
     pick = t if t < len(pz_all) else -1
     
     pz = pz_precomputed['prob_z'][pick]         
     pa = pz_precomputed['prob_a_by_z'][pick] 
     va = pz_precomputed['val_a_by_z'][pick] 
     
     
     na_matches = pa.shape[-1]
     
     p_mat_pa = np.empty((nexo,) + (na_matches,),dtype=setup.dtype)
     p_mat_ia = np.empty((nexo,) + (setup.na,) + (na_matches,),dtype=np.int16)
     
     agrid_s = self.agrid_s
     
     for iz in range(n_zown):
         p_psi = int_prob(psi_couple,mu=mu,sig=sigma_psi_init)
         if female:
             p_zm  = np.array(pz)
             p_zf  = zmat_own[iz,:]
         else:
             p_zf  = np.array(pz)
             p_zm  = zmat_own[iz,:]
         
         
         p_vec = np.zeros(nexo)
         ie, izf, izm, ipsi = setup.all_indices(t)
         
         izpnext = izm if female else izf
         
         p_vec = p_zm[izm]*p_zf[izf]*p_psi[ipsi]
         assert np.allclose(p_vec.sum(),1.0)                            
         p_mat[iz,:] = p_vec
     
     a_resuling = np.clip(agrid_s[None,:,None] + va[:,None,:],0.0,self.agrid_c.max()-1e-5)
     ia_resulting = np.clip(np.searchsorted(setup.agrid_c,a_resuling) - 1,0,setup.na-1)
     p_resulting = pa
     assert np.allclose(pa.sum(axis=-1),1.0)
     # this slightly brings things down
     
     p_mat_ia[:,:,:] = ia_resulting[izpnext,:,:]
     p_mat_pa[:,:] = p_resulting[izpnext,:]
         
     nexo_ext = nexo*na_matches
     p_exo_ext = np.empty((nz_single,nexo_ext),dtype=self.dtype)
     ia_table = np.empty((setup.na,nexo_ext),dtype=np.int16) # resulting ia for each na and nexo_ext
     
     
     
     corresponding_iexo = np.empty(nexo_ext,dtype=np.int16)
     corresponding_imatch = np.empty(nexo_ext,dtype=np.int8)
     
     for im in range(na_matches):
         p_exo_ext[:,(im*nexo):((im+1)*nexo)] = p_mat*(p_mat_pa[:,im][None,:])
         ia_table[:,(im*nexo):((im+1)*nexo)] = p_mat_ia[:,:,im].T
         corresponding_iexo[(im*nexo):((im+1)*nexo)] = ie
         corresponding_imatch[(im*nexo):((im+1)*nexo)] = im
     
     
         
     return {'p_mat_iexo':p_mat,
             'p_mat_extended':p_exo_ext,
             'ia_c_table':ia_table,
             'corresponding_iexo':corresponding_iexo,
             'corresponding_imatch':corresponding_imatch}
Beispiel #5
0
 def mar_mats_iexo(self,t,female=True,trim_lvl=0.001):
     # TODO: check timing
     # this returns transition matrix for single agents into possible couples
     # rows are single's states
     # columnts are couple's states
     # you have to transpose it if you want to use it for integration
     setup = self
     
     nexo = setup.pars['nexo_t'][t]
     sigma_psi_init = setup.pars['sigma_psi_init']
     #sig_z_partner = setup.pars['sig_partner_z']
     psi_couple = setup.exogrid.psi_t[t+1]
     
     
     if female:
         nz_single = setup.exogrid.zf_t[t].shape[0]
         p_mat = np.empty((nexo,nz_single))
         z_own = setup.exogrid.zf_t[t]
         n_zown = z_own.shape[0]
         z_partner = setup.exogrid.zm_t[t]
         zmat_own = setup.exogrid.zf_t_mat[t]
         trend=setup.pars['m_wage_trend_single'][t]
         mean=setup.pars['mean_partner_z_female']-setup.pars['m_wage_trend'][t]+setup.pars['m_wage_trend_single'][t]
         sig_z_partner=(setup.pars['sig_zm_0']**2+(t+1)*setup.pars['sig_zm']**2)**0.5
     else:
         nz_single = setup.exogrid.zm_t[t].shape[0]
         p_mat = np.empty((nexo,nz_single))
         z_own = setup.exogrid.zm_t[t]
         n_zown = z_own.shape[0]
         z_partner = setup.exogrid.zf_t[t]
         zmat_own = setup.exogrid.zm_t_mat[t]    
         trend=setup.pars['f_wage_trend_single'][t]
         mean=setup.pars['mean_partner_z_male']-setup.pars['f_wage_trend'][t]+setup.pars['f_wage_trend_single'][t]
         sig_z_partner=(setup.pars['sig_zf_0']**2+(t+1)*setup.pars['sig_zf']**2)**0.5
         
     def ind_conv(a,b,c): return setup.all_indices(t,(a,b,c))[0]
     
     
     for iz in range(n_zown):
         p_psi = int_prob(psi_couple,mu=0,sig=sigma_psi_init)
         if female:
             p_zm  = int_prob(z_partner, mu=setup.pars['dump_factor_z']*z_partner[iz]+
                               mean+setup.pars['mean_partner_z_female'],sig=(1-setup.pars['dump_factor_z'])**
                               0.5*sig_z_partner*setup.pars['sig_partner_mult'])
             p_zf  = zmat_own[iz,:]
         else:
             p_zf  = int_prob(z_partner, mu=setup.pars['dump_factor_z']*z_partner[iz]+ 
                              mean+setup.pars['mean_partner_z_male'],sig=(1-setup.pars['dump_factor_z'])**
                              0.5*sig_z_partner*setup.pars['sig_partner_mult'])
             p_zm  = zmat_own[iz,:]
         #sm = sf
     
         p_vec = np.zeros(nexo)
         
         for izf, p_zf_i in enumerate(p_zf):
             if p_zf_i < trim_lvl: continue
         
             for izm, p_zm_i in enumerate(p_zm):
                 if p_zf_i*p_zm_i < trim_lvl: continue
             
                 for ipsi, p_psi_i in enumerate(p_psi):                    
                     p = p_zf_i*p_zm_i*p_psi_i
                     
                     if p > trim_lvl:
                         p_vec[ind_conv(izf,izm,ipsi)] = p    
                         
         assert np.any(p_vec>trim_lvl), 'Everything is zero?'              
         p_vec = p_vec / np.sum(p_vec)
         p_mat[:,iz] = p_vec
         
     return p_mat.T
Beispiel #6
0
    def __init__(self,
                 Mlist,
                 age_uni,
                 female=False,
                 pswitchlist=None,
                 N=15000,
                 T=None,
                 verbose=True,
                 nosim=False,
                 draw=False):

        np.random.seed(8)

        # take the stuff from the model and arguments
        # note that this does not induce any copying just creates links

        if type(Mlist) is not list:
            Mlist = [Mlist]

        #Unilateral Divorce
        self.Mlist = Mlist
        self.Vlist = [M.V for M in Mlist]
        self.declist = [M.decisions for M in Mlist]
        self.npol = len(Mlist)
        self.transition = len(self.Mlist) > 1

        if T is None:
            T = self.Mlist[0].setup.pars['T']

        self.setup = self.Mlist[0].setup
        self.state_names = self.setup.state_names
        self.N = N
        self.T = T
        self.verbose = verbose
        self.timer = self.Mlist[0].time
        self.draw = draw

        self.female = female
        self.single_state = 'Female, single' if female else 'Male, single'

        #Divorces
        self.divorces = np.zeros((N, T), bool)

        # all the randomness is here
        shokko = np.random.random_sample((9, N, T))
        self.shocks_single_iexo2 = shokko[
            8, :, :]  # np.random.random_sample((N,T))
        self.shocks_single_iexo = shokko[
            0, :, :]  # np.random.random_sample((N,T))
        self.shocks_single_meet = shokko[
            1, :, :]  # np.random.random_sample((N,T))
        self.shocks_couple_iexo = shokko[
            2, :, :]  # np.random.random_sample((N,T))
        self.shocks_single_a = shokko[
            3, :, :]  # np.random.random_sample((N,T))
        self.shocks_couple_a = shokko[
            4, :, :]  # np.random.random_sample((N,T))

        self.shocks_div_a = shokko[5, :, :]  #np.random.random_sample((N,T))

        z_t = self.setup.exogrid.zf_t if female else self.setup.exogrid.zm_t
        sig = self.setup.pars['sig_zf_0'] if female else self.setup.pars[
            'sig_zm_0']
        z_prob = int_prob(z_t[0], sig=sig)
        shocks_init = shokko[6, :, 0]  #np.random.random_sample((N,))
        i_z = np.sum((shocks_init[:, None] > np.cumsum(z_prob)[None, :]),
                     axis=1)
        iexoinit = i_z  # initial state

        self.shocks_transition = shokko[
            7, :, :]  #np.random.random_sample((N,T))
        # no randomnes past this line please

        # initialize assets

        self.iassets = np.zeros((N, T), np.int16)
        self.iassetss = np.zeros((N, T), np.int16)
        self.tempo = VecOnGrid(self.setup.agrid_s, self.iassets[:, 0])

        # initialize FLS
        #self.ils=np.ones((N,T),np.float64)
        self.ils_i = np.ones((N, T), np.int8) * (len(self.setup.ls_levels) - 1)

        self.ils_i[:, -1] = 5

        # initialize theta
        self.itheta = -np.ones((N, T), np.int16)

        # initialize iexo
        self.iexo = np.zeros((N, T), np.int16)
        self.iexos = np.zeros((N, T), np.int16)
        # TODO: look if we can/need fix the shocks here...

        self.iexo[:, 0] = iexoinit
        self.iexos[:, 0] = iexoinit

        # NB: the last column of these things will not be filled
        # c refers to consumption expenditures (real consumption of couples
        # may be higher b/c of returns to scale)
        self.c = np.zeros((N, T), np.float32)
        self.x = np.zeros((N, T), np.float32)
        self.s = np.zeros((N, T), np.float32)

        self.state_codes = dict()
        self.has_theta = list()
        for i, name in enumerate(self.setup.state_names):
            self.state_codes[name] = i
            self.has_theta.append((name == 'Couple, C' or name == 'Couple, M'))

        # initialize state
        self.state = np.zeros((N, T), dtype=np.int8)
        self.state[:, 0] = self.state_codes[
            self.single_state]  # everyone starts as female

        self.timer('Simulations, creation', verbose=self.verbose)
        self.ils_def = self.setup.nls - 1

        #Create a file with the age of the change foreach person

        self.policy_ind = np.zeros((N, T), dtype=np.int8)

        if pswitchlist == None:
            pswitchlist = [np.eye(self.npol)] * T

        # this simulates "exogenous" transitions of polciy functions
        # policy_ind stands for index of the policies to apply, they are
        # from 0 to (self.npol-1)
        zeros = np.zeros((N, ), dtype=np.int8)
        mat_init = pswitchlist[0]

        self.policy_ind[:, 0] = mc_simulate(
            zeros, mat_init,
            shocks=self.shocks_transition[:, 0])  # everyone starts with 0
        if self.npol > 1:
            for t in range(T - 1):
                mat = pswitchlist[t + 1]
                self.policy_ind[:, t + 1] = mc_simulate(
                    self.policy_ind[:, t],
                    mat,
                    shocks=self.shocks_transition[:, t + 1])
        else:
            self.policy_ind[:] = 0

        if not nosim: self.simulate()
Beispiel #7
0
    def __init__(self,
                 Mlist,
                 pswitchlist=None,
                 female=True,
                 N=15000,
                 T=30,
                 verbose=True,
                 nosim=False,
                 fix_seed=True):

        if fix_seed: np.random.seed(18)

        # take the stuff from the model and arguments
        # note that this does not induce any copying just creates links

        if type(Mlist) is not list:
            Mlist = [Mlist]

        #Unilateral Divorce
        self.Mlist = Mlist
        self.Vlist = [M.V for M in Mlist]
        self.declist = [M.decisions for M in Mlist]
        self.npol = len(Mlist)
        self.transition = len(self.Mlist) > 1

        if T is None:
            T = self.Mlist[0].setup.pars['Tsim']

        self.setup = self.Mlist[0].setup
        self.state_names = self.setup.state_names
        self.N = N
        self.T = T
        self.verbose = verbose
        self.timer = self.Mlist[0].time

        self.female = female
        self.single_state = 'Female, single' if female else 'Male, single'

        # all the randomness is here
        self._shocks_single_iexo = np.random.random_sample((N, T))
        self._shocks_single_meet = np.random.random_sample((N, T))
        self._shocks_couple_iexo = np.random.random_sample((N, T))
        self._shocks_single_a = np.random.random_sample((N, T))
        self._shocks_couple_a = np.random.random_sample((N, T))

        if female:
            inc_prob = int_prob(self.setup.exogrid.zf_t[0],
                                sig=self.setup.pars['sig_zf_0'])
        else:
            inc_prob = int_prob(self.setup.exogrid.zm_t[0],
                                sig=self.setup.pars['sig_zm_0'])

        _shocks_init = np.random.random_sample((N, ))
        i_inc = np.sum((_shocks_init[:, None] > np.cumsum(inc_prob)[None, :]),
                       axis=1)
        iexoinit = i_inc  # initial state

        self._shocks_outsm = np.random.random_sample((N, T))
        self._shocks_transition = np.random.random_sample((N, T))
        self._shocks_single_preg = np.random.random_sample((N, T))
        self._shocks_planned_preg = np.random.random_sample((N, T))

        self._shocks_child_support_fem = np.random.random_sample((N, T))
        self._shocks_child_support_mal = np.random.random_sample((N, T))

        # no randomnes past this line please

        # initialize assets

        self.iassets = np.zeros((N, T), np.int32)

        # initialize FLS
        #self.ils=np.ones((N,T),np.float64)
        self.ils_i = np.zeros((N, T), np.int8)  #*(len(self.setup.ls_levels)-1)

        self.ils_i[:, -1] = 5

        # initialize theta
        self.itheta = -np.ones((N, T), np.int16)

        # initialize iexo
        self.iexo = np.zeros((N, T), np.int16)

        self.c = np.zeros((N, T), np.float32)
        self.x = np.zeros((N, T), np.float32)
        self.s = np.zeros((N, T), np.float32)

        self.unplanned_preg = np.zeros((N, T), dtype=np.bool)
        self.planned_preg = np.zeros((N, T), dtype=np.bool)
        self.disagreed = np.zeros((N, T), dtype=np.bool)
        self.aborted = np.zeros((N, T), dtype=np.bool)
        self.met_a_partner = np.zeros((N, T), dtype=np.bool)
        self.agreed = np.zeros((N, T), dtype=np.bool)
        self.agreed_k = np.zeros((N, T), dtype=np.bool)
        self.agreed_unplanned = np.zeros((N, T), dtype=np.bool)
        self.renegotiated = np.zeros((N, T), dtype=np.bool)
        self.just_divorced = np.zeros((N, T), dtype=np.bool)
        self.just_divorced_nk = np.zeros((N, T), dtype=np.bool)
        self.just_divorced_k = np.zeros((N, T), dtype=np.bool)
        self.new_child = np.zeros((N, T), dtype=np.bool)
        self.k_m = np.zeros((N, T), dtype=np.bool)
        self.k_m_true = np.zeros((N, T), dtype=np.bool)
        self.m_k = np.zeros((N, T), dtype=np.bool)
        self.nmar = np.zeros((N, T), dtype=np.int8)

        self.ub_hit_single = False
        self.ub_hit_couple = False

        self.yaftmar = -np.ones((N, T), dtype=np.int8)

        self.iexo[:, 0] = iexoinit

        # initialize state

        self.state_codes = dict()
        self.has_theta = list()
        self.has_fls = list()
        for i, name in enumerate(self.setup.state_names):
            self.state_codes[name] = i
            self.has_theta.append((name == 'Couple, no children'
                                   or name == 'Couple and child'))
            self.has_fls.append(
                (name == 'Couple, no children' or name == 'Couple and child'
                 or name == 'Female and child'))

        self.state = np.zeros((N, T), dtype=np.int8)
        self.state[:, 0] = self.state_codes[
            self.single_state]  # everyone starts as female

        self.timer('Simulations, creation', verbose=self.verbose)
        self.ils_def = 0  #self.setup.nls - 1

        #Create a file with the age of the change foreach person

        self.policy_ind = np.zeros((N, T), dtype=np.int8)

        if pswitchlist == None:
            pswitchlist = [np.eye(self.npol)] * T

        # this simulates "exogenous" transitions of polciy functions
        # policy_ind stands for index of the policies to apply, they are
        # from 0 to (self.npol-1)
        zeros = np.zeros((N, ), dtype=np.int8)
        mat_init = pswitchlist[0]

        self.policy_ind[:, 0] = mc_simulate(
            zeros, mat_init,
            shocks=self._shocks_transition[:, 0])  # everyone starts with 0
        if self.npol > 1:
            for t in range(T - 1):
                mat = pswitchlist[t + 1]
                self.policy_ind[:, t + 1] = mc_simulate(
                    self.policy_ind[:, t],
                    mat,
                    shocks=self._shocks_transition[:, t + 1])
        else:
            self.policy_ind[:] = 0

        if not nosim: self.simulate()
        self.compute_aux()
        counts, offers, marriages = self.marriage_stats()

        if self.verbose and self.ub_hit_single:
            print('Assets upped bound is reached for singles')
        if self.verbose and self.ub_hit_couple:
            print('Assets upped bound is reached for couples')