# Adding new decisions to LifeCycleModel35semiz

**URL:** https://discourse.vfitoolkit.com/t/adding-new-decisions-to-lifecyclemodel35semiz/584
**Category:** Uncategorized
**Created:** [February 3, 2026, 1:40am UTC](https://discourse.vfitoolkit.com/t/adding-new-decisions-to-lifecyclemodel35semiz/584 "2026-02-03T01:40:17Z")
**Posts on this page:** 20
**Page:** 1

<div class="post-metadata">

### Author: ![MichaelTiemann](https://discourse.vfitoolkit.com/user_avatar/discourse.vfitoolkit.com/michaeltiemann/32/220_2.png) [@MichaelTiemann](https://discourse.vfitoolkit.com/u/MichaelTiemann)
#### Post date: [February 3, 2026, 1:40am UTC](https://discourse.vfitoolkit.com/t/adding-new-decisions-to-lifecyclemodel35semiz/584/1 "2026-02-03T01:40:17Z")

</div>

I’m interested in adding a decision to install rooftop solar on top of a house in LifeCycleModel35semiz.

I’ve added `installpv` as a binary choice and `solarpv` as a scalable generation asset (scalable from 0 to 30 kWh).

```auto
n_d=[11,101,5,2]; % Decisions: riskyshare, savings, buyhouse (note, SemiExoStateFn hardcodes that buyhouse is 5 points), installpv
n_a=[3,21,7]; % Endogenous housing, asset, and solarpv holdings (0-30kW generation)

```

I’m now stuck on the proper definition of `refine_d`

```auto
vfoptions.refine_d=[0,1,1,1]; % tell the code how many d1, d2, d3 and d4 there are

```

If I add to `d1` I get a message that `riskyasset+semiz with d1 not yet implemented`.

If I add to d4, I get an error about incompatibly-shaped arrays. I do pass `installpv` to the `SemiExoStateFn` (mainly to keep the price of the house from falling when installing PV). And I use `solarpv` in the return function (where it adds to income, like an asset).

Do I need to wait for the new feature or should I reshape what I’m doing to better fit with the existing system?

---

<div class="post-metadata">

### Author: ![robertdkirkby](https://discourse.vfitoolkit.com/user_avatar/discourse.vfitoolkit.com/robertdkirkby/32/287_2.png) [@robertdkirkby](https://discourse.vfitoolkit.com/u/robertdkirkby)
#### Post date: [February 3, 2026, 3:18am UTC](https://discourse.vfitoolkit.com/t/adding-new-decisions-to-lifecyclemodel35semiz/584/2 "2026-02-03T03:18:13Z")

</div>

What kind of endogenous state is solarpv supposed to be? In any case this won’t work with current toolkit implementations.

My impression: you don’t need riskyasset for anything (do you?). I would set n\_a=[21,3,7] as two standard endogenous states for ‘assets’ and ‘house’ and one experienceasset for ‘solarpv’. n\_d=2, as the ‘installpv’ (the action space will include next period ‘assets’ and next period ‘house’). This should run okay, but would not currently work for using divide-and-conquer or grid interpolation layer on the ‘assets’ (can be implemented).

---

<div class="post-metadata">

### Author: ![MichaelTiemann](https://discourse.vfitoolkit.com/user_avatar/discourse.vfitoolkit.com/michaeltiemann/32/220_2.png) [@MichaelTiemann](https://discourse.vfitoolkit.com/u/MichaelTiemann)
#### Post date: [February 3, 2026, 3:30am UTC](https://discourse.vfitoolkit.com/t/adding-new-decisions-to-lifecyclemodel35semiz/584/3 "2026-02-03T03:30:29Z")

</div>

Thanks for the D-C tip and the `experienceasset` reminder. I’ll adapt accordingly. And indeed the `riskyasset` probably is a distraction–I’m much more interested in the housing and solar questions (including the stochastic behavior of housing prices and energy prices). Risky assets are a dimension I don’t need to interrogate right now.

---

<div class="post-metadata">

### Author: ![MichaelTiemann](https://discourse.vfitoolkit.com/user_avatar/discourse.vfitoolkit.com/michaeltiemann/32/220_2.png) [@MichaelTiemann](https://discourse.vfitoolkit.com/u/MichaelTiemann)
#### Post date: [February 3, 2026, 7:03pm UTC](https://discourse.vfitoolkit.com/t/adding-new-decisions-to-lifecyclemodel35semiz/584/4 "2026-02-03T19:03:39Z")

</div>

If we want to have both renters and homeowners, I think `n_d` should be [5, 2] (`buyhouse` and `installpv`), no?

---

<div class="post-metadata">

### Author: ![robertdkirkby](https://discourse.vfitoolkit.com/user_avatar/discourse.vfitoolkit.com/robertdkirkby/32/287_2.png) [@robertdkirkby](https://discourse.vfitoolkit.com/u/robertdkirkby)
#### Post date: [February 3, 2026, 7:08pm UTC](https://discourse.vfitoolkit.com/t/adding-new-decisions-to-lifecyclemodel35semiz/584/5 "2026-02-03T19:08:01Z")

</div>

If ‘house’ is a standard endogenous state, then it is something you can choose the ‘next period house’ for, and does not need to appear in ‘d’ (if it is in ‘a’, and a standard endogenous state, then it appears as ‘aprime’).

---

<div class="post-metadata">

### Author: ![MichaelTiemann](https://discourse.vfitoolkit.com/user_avatar/discourse.vfitoolkit.com/michaeltiemann/32/220_2.png) [@MichaelTiemann](https://discourse.vfitoolkit.com/u/MichaelTiemann)
#### Post date: [February 3, 2026, 7:26pm UTC](https://discourse.vfitoolkit.com/t/adding-new-decisions-to-lifecyclemodel35semiz/584/6 "2026-02-03T19:26:05Z")

</div>

I was working from the `semiz` example. In that case should it be as I said?

---

<div class="post-metadata">

### Author: ![robertdkirkby](https://discourse.vfitoolkit.com/user_avatar/discourse.vfitoolkit.com/robertdkirkby/32/287_2.png) [@robertdkirkby](https://discourse.vfitoolkit.com/u/robertdkirkby)
#### Post date: [February 3, 2026, 7:52pm UTC](https://discourse.vfitoolkit.com/t/adding-new-decisions-to-lifecyclemodel35semiz/584/7 "2026-02-03T19:52:58Z")

</div>

Yes, if it is a semi-exogenous shock then the decision variable that controls it needs to be in n\_d.

But why do you want house as a semi-exogenous shock, not as an endogenous state? Not that you can’t, but that it is only worthwhile if you have a reason for wanting to do so.

---

<div class="post-metadata">

### Author: ![MichaelTiemann](https://discourse.vfitoolkit.com/user_avatar/discourse.vfitoolkit.com/michaeltiemann/32/220_2.png) [@MichaelTiemann](https://discourse.vfitoolkit.com/u/MichaelTiemann)
#### Post date: [February 3, 2026, 8:03pm UTC](https://discourse.vfitoolkit.com/t/adding-new-decisions-to-lifecyclemodel35semiz/584/8 "2026-02-03T20:03:08Z")

</div>

I like the pattern you created of fluctuating housing prices, so am building off that. I could simplify down to LifeCycleModel35 (without semiz). Thanks for confirming!

---

<div class="post-metadata">

### Author: ![MichaelTiemann](https://discourse.vfitoolkit.com/user_avatar/discourse.vfitoolkit.com/michaeltiemann/32/220_2.png) [@MichaelTiemann](https://discourse.vfitoolkit.com/u/MichaelTiemann)
#### Post date: [February 4, 2026, 2:19am UTC](https://discourse.vfitoolkit.com/t/adding-new-decisions-to-lifecyclemodel35semiz/584/9 "2026-02-04T02:19:02Z")

</div>

I note that `ValueFnIter_FHorz_RiskyAsset_semiz` cleverly skips past the (d,u) inputs when it is sussing out aprimeFnParamNames (line 15).

This means that at line 145, when it calls `ValueFnIter_FHorz_RiskyAsset_nod1_semiz_raw` the only `aprime` parameter name is `r`, which is in Parameters.

However, `ValueFnIter_FHorz_ExpAssetSemiExo` only strips out `d3` and `a2` parameter names, leaving the `a1` parameters to be found by `CreateVectorFromParams`. But `a` and `h` (the `a1` parameters) are not in Params, so the program triggers a warning that the parameters are not found.

Why would we not skip past the `a1` parameter names, too, and not just the `d3` and `a2` parameter names?

---

<div class="post-metadata">

### Author: ![MichaelTiemann](https://discourse.vfitoolkit.com/user_avatar/discourse.vfitoolkit.com/michaeltiemann/32/220_2.png) [@MichaelTiemann](https://discourse.vfitoolkit.com/u/MichaelTiemann)
#### Post date: [February 4, 2026, 2:25am UTC](https://discourse.vfitoolkit.com/t/adding-new-decisions-to-lifecyclemodel35semiz/584/10 "2026-02-04T02:25:07Z")

</div>

I think I can answer my own question: experience asset aprime functions are their own things and do not cover other assets generally. So it drives what could be considered an a2prime function. Yes?

If so, then we have a kind of a name clash, with `vfoptions.experienceasset` depending upon `vfoptions.aprime` being set, but then we cannot have a proper aprime function in the event we want to do more complex aprime-y stuff with `a1`.

---

<div class="post-metadata">

### Author: ![robertdkirkby](https://discourse.vfitoolkit.com/user_avatar/discourse.vfitoolkit.com/robertdkirkby/32/287_2.png) [@robertdkirkby](https://discourse.vfitoolkit.com/u/robertdkirkby)
#### Post date: [February 4, 2026, 2:48am UTC](https://discourse.vfitoolkit.com/t/adding-new-decisions-to-lifecyclemodel35semiz/584/12 "2026-02-04T02:48:26Z")

</div>

Currently it is not possible to have more than one endogenous state that uses an ‘aprimeFn’ setup. I think this is what you are observing.

In principle it would be easy enough to have ‘aprime1Fn’ and ‘aprime2Fn’, or whatever they would be called, but this has not yet been done anywhere so what they would be called is up in the air.

---

<div class="post-metadata">

### Author: ![MichaelTiemann](https://discourse.vfitoolkit.com/user_avatar/discourse.vfitoolkit.com/michaeltiemann/32/220_2.png) [@MichaelTiemann](https://discourse.vfitoolkit.com/u/MichaelTiemann)
#### Post date: [February 4, 2026, 5:59am UTC](https://discourse.vfitoolkit.com/t/adding-new-decisions-to-lifecyclemodel35semiz/584/13 "2026-02-04T05:59:29Z")

</div>

I’m puzzling over code in `EvaluateFnOnAgentDist\FHorz\LifeCycleProfiles_FHorz_Case1.m` and specifically what happens after consolidating `semiz`, `z`, and `e` (via the call to `CreateGridvals_FnsToEvaluate_FHorz`). When all this become part of a `z_gridvals_J` then the decision function that’s sitting in `refine_d(4)` should be removed from consideration as well. I think this is the easy way to do it:

```auto
% Figure out l_daprime from PolicyValues
l_daprime=size(PolicyValues,1);
if simoptions.experienceasset || simoptions.experienceassetu
    if isfield(simoptions, 'refine_d')
        if length(simoptions.refine_d)==4
            % adjust if there are experienceassets that were also semiz
            l_daprime=l_daprime-simoptions.refine_d(4);
        end
    else
        error("cannot use experienceasset or experienceassetu without simoptions.refine_d");
    end
end

```

I’ll create a pull request if this is not blatantly wrong.

---

<div class="post-metadata">

### Author: ![robertdkirkby](https://discourse.vfitoolkit.com/user_avatar/discourse.vfitoolkit.com/robertdkirkby/32/287_2.png) [@robertdkirkby](https://discourse.vfitoolkit.com/u/robertdkirkby)
#### Post date: [February 4, 2026, 6:46am UTC](https://discourse.vfitoolkit.com/t/adding-new-decisions-to-lifecyclemodel35semiz/584/14 "2026-02-04T06:46:19Z")

</div>

> I’m puzzling over code in `EvaluateFnOnAgentDist\FHorz\LifeCycleProfiles_FHorz_Case1.m` and specifically what happens after consolidating `semiz`, `z`, and `e` (via the call to `CreateGridvals_FnsToEvaluate_FHorz`). When all this become part of a `z_gridvals_J` then the decision function that’s sitting in `refine_d(4)` should be removed from consideration as well. I think this is the easy way to do it:

Why would you want to do this though? We still want all the d variables, and for evaluating functions on agent dist the content of refine\_d is irrelevant.

---

<div class="post-metadata">

### Author: ![MichaelTiemann](https://discourse.vfitoolkit.com/user_avatar/discourse.vfitoolkit.com/michaeltiemann/32/220_2.png) [@MichaelTiemann](https://discourse.vfitoolkit.com/u/MichaelTiemann)
#### Post date: [February 4, 2026, 7:08am UTC](https://discourse.vfitoolkit.com/t/adding-new-decisions-to-lifecyclemodel35semiz/584/15 "2026-02-04T07:08:21Z")

</div>

The problem I’m trying to solve is that without adjusting l\_daprime, the now-integrated semiz variable is gone, and when we call arrayfun to calculate the return matrix, the unadjusted l\_daprime value requests more da vars than we have to offer. The call to arrayfun happens very soon after this point in the code.

Maybe my mistake is that I need two aprimes, one for the experience asset and one for the semiz variable? Here’s the error message:

```auto
Error using EvalFnOnAgentDist_Grid (line 436)
gpuArray/arrayfun encountered an issue while compiling '@(installpv,buyhouse,hprime,a,h,solarpv,pbefore,pafter,yearsowned,olddownpayment,z)a'.

Error in LifeCycleProfiles_FHorz_Case1 (line 476)
                Values(:,:,jj-j1+1)=EvalFnOnAgentDist_Grid(FnsToEvaluate{ff}, FnToEvaluateParamsCell,PolicyValuesPermuteJ(:,:,:,jj),l_daprime,n_a,n_z,a_gridvals,z_gridvals_J(:,:,jj));
                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Error in ElectrifyHousing (line 369)
AgeConditionalStats=LifeCycleProfiles_FHorz_Case1(StationaryDist,Policy,FnsToEvaluate,Params,[],n_d,n_a,n_z,N_j,d_grid,a_grid,z_grid,simoptions);
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Caused by:
    @(installpv,buyhouse,hprime,a,h,solarpv,pbefore,pafter,yearsowned,olddownpayment,z)a takes at most 11 inputs. 12 were supplied.

```

If I had both the `aprime` for `installpv` and `hprime` for `buyhouse` then my function and the parameters would agree (I think).

---

<div class="post-metadata">

### Author: ![robertdkirkby](https://discourse.vfitoolkit.com/user_avatar/discourse.vfitoolkit.com/robertdkirkby/32/287_2.png) [@robertdkirkby](https://discourse.vfitoolkit.com/u/robertdkirkby)
#### Post date: [February 4, 2026, 7:25am UTC](https://discourse.vfitoolkit.com/t/adding-new-decisions-to-lifecyclemodel35semiz/584/16 "2026-02-04T07:25:58Z")

</div>

What is the action space of your model (what are n\_d, n\_a, n\_semiz, n\_z, n\_e, and if you are using any non-standard endogenous states what are those)?

Have you watched the [‘workshop’ videos](https://www.vfitoolkit.com/2025-workshop-lse/)? They give an explanation of the action space. That will help you understand what the inputs should be for ReturnFn and FnsToEvaluate.

---

<div class="post-metadata">

### Author: ![MichaelTiemann](https://discourse.vfitoolkit.com/user_avatar/discourse.vfitoolkit.com/michaeltiemann/32/220_2.png) [@MichaelTiemann](https://discourse.vfitoolkit.com/u/MichaelTiemann)
#### Post date: [February 4, 2026, 7:50am UTC](https://discourse.vfitoolkit.com/t/adding-new-decisions-to-lifecyclemodel35semiz/584/17 "2026-02-04T07:50:11Z")

</div>

I haven’t watched them yet. I will.

I have:

```auto
n_d=[5,2]; % Decisions: buyhouse (note, SemiExoStateFn hardcodes that buyhouse is 5 points), installpv
n_a=[21,3,5]; % Endogenous asset, housing, and solarpv (0-40kW generation) 
n_semiz=[5,5,ceil(30/p5),3]; % Semi-exog: house prices before/after purchase, years since purchase (one minus this is the 30y duration of mortgages in model periods), and downpayment
n_z=7; % Exogenous labor productivity units shock

There's no n_e

% Set up d for VFI Toolkit (is the two decision variables)
d_grid=[buyhouse_grid; installpv_grid];

% experienceasset is last
a_grid=[asset_grid; house_grid; solarpv_grid];

```

The idea is that after the install decision, the solarpv asset value becomes non-zero, and it happily creates revenue offsets for electricity costs. Once installed, the solarpv cannot be removed. But it can be upgraded by spending more, up to a limit.

---

<div class="post-metadata">

### Author: ![robertdkirkby](https://discourse.vfitoolkit.com/user_avatar/discourse.vfitoolkit.com/robertdkirkby/32/287_2.png) [@robertdkirkby](https://discourse.vfitoolkit.com/u/robertdkirkby)
#### Post date: [February 4, 2026, 8:04am UTC](https://discourse.vfitoolkit.com/t/adding-new-decisions-to-lifecyclemodel35semiz/584/18 "2026-02-04T08:04:06Z")

</div>

Action space will be: (d1,d2,a1prime,a2prime,a1,a2,a3,semiz1,semiz2,semiz3,semiz4,z,…)  
VFI Toolkit will interpret these to be the first inputs in ReturnFn and FnsToEvaluate, and assume anything after this as a parameter which it will look for in the Params structure.  
(action space is figured out by looking at n\_d,n\_a, etc. and vfoptions/simoptions)

[a3prime is missing because it is an experienceasset so cannot be chosen directly, instead is determined based on the aprimeFn]

> The idea is that after the install decision, the solarpv asset value becomes non-zero, and it happily creates revenue offsets for electricity costs. Once installed, the solarpv cannot be removed. But it can be upgraded by spending more, up to a limit.

This will all be easy enough to control by setting up aprimeFn and ReturnFn appropriately.

---

<div class="post-metadata">

### Author: ![MichaelTiemann](https://discourse.vfitoolkit.com/user_avatar/discourse.vfitoolkit.com/michaeltiemann/32/220_2.png) [@MichaelTiemann](https://discourse.vfitoolkit.com/u/MichaelTiemann)
#### Post date: [February 4, 2026, 9:32pm UTC](https://discourse.vfitoolkit.com/t/adding-new-decisions-to-lifecyclemodel35semiz/584/19 "2026-02-04T21:32:01Z")

</div>

Thanks for the clues (and the videos)! This is the magic spell (from `OLG/ImrohorogluImrohorogluJoines2003_PhiaprimeFn.m`) I thought I was looking for:

```auto
n_a=[n_a1,n_a2,n_a3]; % Because of how evaluating fns on gpu works I had to split this vector in three, can now put it back together.
Phi_aprime=sub2ind_homemade(n_a,[kprime_c,ebarprime_c,bprime_c]);

```

And now I think I understand why multiple `aprimeFn` functions are not needed: because `aprimeFn` can see the complete action space (if one sets it up correctly).

However, I also see that IIJ2003 doesn’t use Phi\_aprime anywhere I can see, so there’s that. I will see if I can get an `aprimeFn` that agrees enough with my `ReturnFn` to give me sensible results.

And thinking more about it, `refine_d` might just interrupt this line of thinking. Hmm.

---

<div class="post-metadata">

### Author: ![MichaelTiemann](https://discourse.vfitoolkit.com/user_avatar/discourse.vfitoolkit.com/michaeltiemann/32/220_2.png) [@MichaelTiemann](https://discourse.vfitoolkit.com/u/MichaelTiemann)
#### Post date: [February 5, 2026, 5:46pm UTC](https://discourse.vfitoolkit.com/t/adding-new-decisions-to-lifecyclemodel35semiz/584/20 "2026-02-05T17:46:13Z")

</div>

I was looking at this thread: [Mandatory Saving](https://discourse.vfitoolkit.com/t/mandatory-saving/416) .

And I’ve been thinking about how I can or cannot control my `installpv` decision. From what I can tell, the `experienceasset` is very limited in what it can see as far as the action space is concerned. It can see its decision variable (`installpv`) and its own asset value (`solarpv`), and of course it can see static values in `Params`, but it cannot see the housing decisions (`buyhouse`), so it tries to install PV independently of whether the agent yet owns a house.

I can make the agent reject any state that accumulates `solarpv` before a house is purchased, but that makes the `solarpv` asset kind of meaningless.

Alas, I don’t have the credentials needed to access the Zhou paper, so I have only a superficial understanding of what the action space really looks like in that example. But if I do understand correctly, I should ditch the idea of making `installpv` its own binary decision variable, and consolidate everything into `buyhouse` where a new value of 5 in a 6-member list could be “installpv in a house that you own”. In which case the experienceasset could test the status of home ownership before deciding to install.

---

<div class="post-metadata">

### Author: ![robertdkirkby](https://discourse.vfitoolkit.com/user_avatar/discourse.vfitoolkit.com/robertdkirkby/32/287_2.png) [@robertdkirkby](https://discourse.vfitoolkit.com/u/robertdkirkby)
#### Post date: [February 5, 2026, 7:52pm UTC](https://discourse.vfitoolkit.com/t/adding-new-decisions-to-lifecyclemodel35semiz/584/21 "2026-02-05T19:52:46Z")

</div>

You can just use the ReturnFn to give -Inf whenever someone tries to install solarpv but owns zero house. But let them install solarpv if either they own a house or they choose buyhouse.

[Next page](https://discourse.vfitoolkit.com/t/adding-new-decisions-to-lifecyclemodel35semiz/584.md?page=2)
