class testPerfForesightConsumerType(unittest.TestCase): def setUp(self): self.agent = PerfForesightConsumerType() self.agent_infinite = PerfForesightConsumerType(cycles=0) PF_dictionary = { "CRRA": 2.5, "DiscFac": 0.96, "Rfree": 1.03, "LivPrb": [0.98], "PermGroFac": [1.01], "T_cycle": 1, "cycles": 0, "AgentCount": 10000, } self.agent_alt = PerfForesightConsumerType(**PF_dictionary) def test_default_solution(self): self.agent.solve() c = self.agent.solution[0].cFunc self.assertEqual(c.x_list[0], -0.9805825242718447) self.assertEqual(c.x_list[1], 0.01941747572815533) self.assertEqual(c.y_list[0], 0) self.assertEqual(c.y_list[1], 0.511321002804608) self.assertEqual(c.decay_extrap, False) def test_another_solution(self): self.agent_alt.DiscFac = 0.90 self.agent_alt.solve() self.assertAlmostEqual(self.agent_alt.solution[0].cFunc(10).tolist(), 3.9750093524820787) def test_check_conditions(self): self.agent_infinite.check_conditions() self.assertTrue(self.agent_infinite.conditions["AIC"]) self.assertTrue(self.agent_infinite.conditions["GICRaw"]) self.assertTrue(self.agent_infinite.conditions["RIC"]) self.assertTrue(self.agent_infinite.conditions["FHWC"]) def test_simulation(self): self.agent_infinite.solve() # Create parameter values necessary for simulation SimulationParams = { "AgentCount": 10000, # Number of agents of this type "T_sim": 120, # Number of periods to simulate "aNrmInitMean": -6.0, # Mean of log initial assets "aNrmInitStd": 1.0, # Standard deviation of log initial assets "pLvlInitMean": 0.0, # Mean of log initial permanent income "pLvlInitStd": 0.0, # Standard deviation of log initial permanent income "PermGroFacAgg": 1.0, # Aggregate permanent income growth factor "T_age": None, # Age after which simulated agents are automatically killed } self.agent_infinite.assign_parameters( **SimulationParams ) # This implicitly uses the assign_parameters method of AgentType # Create PFexample object self.agent_infinite.track_vars = ["mNrm"] self.agent_infinite.initialize_sim() self.agent_infinite.simulate() self.assertAlmostEqual( np.mean(self.agent_infinite.history["mNrm"], axis=1)[40], -23.008063500363942, ) self.assertAlmostEqual( np.mean(self.agent_infinite.history["mNrm"], axis=1)[100], -27.164608851546927, ) ## Try now with the manipulation at time step 80 self.agent_infinite.initialize_sim() self.agent_infinite.simulate(80) # This actually does nothing because aNrmNow is # epiphenomenal. Probably should change mNrmNow instead self.agent_infinite.state_now['aNrm'] += (-5.0) self.agent_infinite.simulate(40) self.assertAlmostEqual( np.mean(self.agent_infinite.history["mNrm"], axis=1)[40], -23.008063500363942, ) self.assertAlmostEqual( np.mean(self.agent_infinite.history["mNrm"], axis=1)[100], -29.140261331951606, ) def test_stable_points(self): # Solve the constrained agent. Stable points exists only with a # borrowing constraint. constrained_agent = PerfForesightConsumerType(cycles=0, BoroCnstArt=0.0) constrained_agent.solve() # Check against pre-computed values. self.assertEqual(constrained_agent.solution[0].mNrmStE, 1.0) # Check that they are both the same, since the problem is deterministic self.assertEqual(constrained_agent.solution[0].mNrmStE, constrained_agent.solution[0].mNrmTrg)
PFexample.assign_parameters(**SimulationParams) # %% [markdown] {"incorrectly_encoded_metadata": "pycharm= [markdown] {\"name\": \"#%% md\\n\"}"} # To generate simulated data, we need to specify which variables we want to track the "history" of for this instance. To do so, we set the `track_vars` attribute of our `PerfForesightConsumerType` instance to be a list of strings with the simulation variables we want to track. # # In this model, valid arguments to `track_vars` include $\texttt{mNrm}$, $\texttt{cNrm}$, $\texttt{aNrm}$, and $\texttt{pLvl}$. Because this model has no idiosyncratic shocks, our simulated data will be quite boring. # # ### Generating simulated data # # Before simulating, the `initialize_sim` method must be invoked. This resets our instance back to its initial state, drawing a set of initial $\texttt{aNrm}$ and $\texttt{pLvl}$ values from the specified distributions and storing them in the attributes $\texttt{aNrmNow_init}$ and $\texttt{pLvlNow_init}$. It also resets this instance's internal random number generator, so that the same initial states will be set every time `initialize_sim` is called. In models with non-trivial shocks, this also ensures that the same sequence of shocks will be generated on every simulation run. # # Finally, the `simulate` method can be called. # %% {"pycharm": {"name": "#%%\n"}} PFexample.track_vars = ['mNrm'] PFexample.initialize_sim() PFexample.simulate() # %% {"incorrectly_encoded_metadata": "pycharm= [markdown] {\"name\": \"#%% md\\n\"}"} # Each simulation variable $\texttt{X}$ named in $\texttt{track_vars}$ will have the *history* of that variable for each agent stored in the attribute $\texttt{X_hist}$ as an array of shape $(\texttt{T_sim},\texttt{AgentCount})$. To see that the simulation worked as intended, we can plot the mean of $m_t$ in each simulated period: # %% {"pycharm": {"name": "#%%\n"}} plt.plot(np.mean(PFexample.history['mNrm'], axis=1)) plt.xlabel("Time") plt.ylabel("Mean normalized market resources") plt.show() # %% [markdown] {"incorrectly_encoded_metadata": "pycharm= [markdown] {\"name\": \"#%% md\\n\"}"} # A perfect foresight consumer can borrow against the PDV of his future income-- his human wealth-- and thus as time goes on, our simulated agents approach the (very negative) steady state level of $m_t$ while being steadily replaced with consumers with roughly $m_t=1$. # # The slight wiggles in the plotted curve are due to consumers randomly dying and being replaced; their replacement will have an initial state drawn from the distributions specified by the user. To see the current distribution of ages, we can look at the attribute $\texttt{t_age}$.