# Constrain General Eqm Parameters

**URL:** https://discourse.vfitoolkit.com/t/constrain-general-eqm-parameters/392
**Category:** Uncategorized
**Created:** [June 9, 2025, 10:01am UTC](https://discourse.vfitoolkit.com/t/constrain-general-eqm-parameters/392 "2025-06-09T10:01:37Z")
**Posts on this page:** 1
**Showing post:** 8

<div class="post-metadata">

### Author: ![aledinola](https://discourse.vfitoolkit.com/letter_avatar_proxy/v4/letter/a/3ec8ea/32.png) [@aledinola](https://discourse.vfitoolkit.com/u/aledinola)
#### Post date: [June 1, 2026, 9:48pm UTC](https://discourse.vfitoolkit.com/t/constrain-general-eqm-parameters/392/8 "2026-06-01T21:48:52Z")

</div>

According to my AI, there are a few bugs.

# Proofreading notes: parameter-constraint transformations in VFI Toolkit calibration

Focus: parameter transformations used to handle constraints in the calibration routines.

Relevant files:

- `SubCodes/ParameterConstraints/ParameterConstraints_TransformParamsToUnconstrained.m`
- `SubCodes/ParameterConstraints/ParameterConstraints_TransformParamsToOriginal.m`
- `SubCodes/ParameterConstraints/ParameterConstraints_PType_TransformParamsToUnconstrained.m`
- `Estimation/Calibration/CalibrateLifeCycleModel.m`
- `Estimation/Calibration/CalibrateLifeCycleModel_PType.m`
- `Estimation/Calibration/CalibrateOLGModel_PType.m`
- `Estimation/Calibration/CalibrateBIHAModel_PType.m`
- `Estimation/Calibration/CalibrateInfHorzAgentModel_PType.m`

* * *

## 1. Serious bug: PType constrained parameters are transformed back using the non-PType routine

In PType calibration, the initial vector is transformed using the PType-specific routine:

```matlab
[calibparamsvec0,caliboptions] = ...
    ParameterConstraints_PType_TransformParamsToUnconstrained( ...
        calibparamsvec0, calibparamsvecindex, CalibParamNames, ...
        nCalibParamsFinder, caliboptions, 1);

```

This is correct, because PType calibration expands original parameter names into PType-specific blocks.

However, at the end of the PType calibration wrappers, the code transforms back using the non-PType routine:

```matlab
[calibparamsvec,penalty] = ...
    ParameterConstraints_TransformParamsToOriginal( ...
        calibparamsvec, calibparamsvecindex, CalibParamNames, caliboptions);

```

This is likely wrong.

The non-PType inverse routine loops over:

```matlab
for pp = 1:length(CalibParamNames)

```

But in PType calibration, the relevant number of blocks is:

```matlab
nCalibParams = size(nCalibParamsFinder,1);

```

These are not the same object. `CalibParamNames` contains original parameter names, while `nCalibParamsFinder` indexes the PType-expanded parameter blocks.

Therefore, if a constrained parameter is PType-specific, some entries may remain in log/logit space instead of being transformed back to the original model scale.

### Suggested fix

Add a PType-specific inverse transform:

```matlab
function [calibparamsvec,penalty] = ...
    ParameterConstraints_PType_TransformParamsToOriginal( ...
        calibparamsvec, calibparamsvecindex, CalibParamNames, ...
        nCalibParamsFinder, caliboptions)

nCalibParams = size(nCalibParamsFinder,1);

penalty = zeros(length(calibparamsvec),1);

for pp = 1:nCalibParams

    idx = calibparamsvecindex(pp)+1:calibparamsvecindex(pp+1);

    if caliboptions.constrainpositive(pp)==1

        temp = calibparamsvec(idx);

        penalty(idx) = abs(temp/50).*(temp < -51);

        calibparamsvec(idx) = exp(temp);

    elseif caliboptions.constrain0to1(pp)==1

        temp = calibparamsvec(idx);

        penalty(idx) = abs(temp/50).*((temp > 51) + (temp < -51));

        calibparamsvec(idx) = 1./(1+exp(-temp));

        calibparamsvec(idx) = calibparamsvec(idx).*(temp > -50);
        calibparamsvec(idx) = calibparamsvec(idx).*(1-(temp > 50)) + (temp > 50);

    end

    if caliboptions.constrainAtoB(pp)==1

        A = caliboptions.constrainAtoBlimits(pp,1);
        B = caliboptions.constrainAtoBlimits(pp,2);

        calibparamsvec(idx) = A + (B-A)*calibparamsvec(idx);

    end

end

if sum(penalty)>0
    penalty = 1/prod(1./penalty(penalty>0));
else
    penalty = 0;
end

end

```

Then replace, in PType wrappers:

```matlab
[calibparamsvec,penalty] = ...
    ParameterConstraints_TransformParamsToOriginal( ...
        calibparamsvec, calibparamsvecindex, CalibParamNames, caliboptions);

```

with:

```matlab
[calibparamsvec,penalty] = ...
    ParameterConstraints_PType_TransformParamsToOriginal( ...
        calibparamsvec, calibparamsvecindex, CalibParamNames, ...
        nCalibParamsFinder, caliboptions);

```

Apply this to:

- `CalibrateLifeCycleModel_PType.m`
- `CalibrateOLGModel_PType.m`
- `CalibrateBIHAModel_PType.m`
- `CalibrateInfHorzAgentModel_PType.m`

* * *

## 2. Serious bug in `CalibrateLifeCycleModel.m`: extra `usingallstats` under `fminalgo==8`

In the non-`lsqnonlin` branch, the objective function receives:

```matlab
..., usingallstats, usinglcp, usingcustomstats, ...

```

But in the `fminalgo==8` branch, it receives:

```matlab
..., usingallstats, usingallstats, usinglcp, usingcustomstats, ...

```

There is an extra `usingallstats`.

Since `fminalgo==8` is the default, this is important.

### Suggested fix

Change:

```matlab
..., FnsToEvaluateParamNames, usingallstats, usingallstats, usinglcp, usingcustomstats, targetmomentvec, ...

```

to:

```matlab
..., FnsToEvaluateParamNames, usingallstats, usinglcp, usingcustomstats, targetmomentvec, ...

```

* * *

## 3. Add checks for positive constraints

Current logic:

```matlab
calibparamsvec(idx) = max(log(calibparamsvec(idx)),-49.99);

```

This handles `p=0`, but not `p<0`. For `p<0`, `log(p)` is complex.

### Suggested fix

```matlab
idx = calibparamsvecindex(pp)+1:calibparamsvecindex(pp+1);
p = calibparamsvec(idx);

if any(p < 0)
    error('Initial guess for positive-constrained parameter is negative.');
end

calibparamsvec(idx) = max(log(p), -49.99);

```

Apply this in:

- `ParameterConstraints_TransformParamsToUnconstrained.m`
- `ParameterConstraints_PType_TransformParamsToUnconstrained.m`

* * *

## 4. Add checks for 0-to-1 constraints

Current logic:

```matlab
calibparamsvec(idx) = min(49.99, max(-49.99, ...
    log(calibparamsvec(idx)./(1-calibparamsvec(idx)))));

```

This handles exactly `p=0` and `p=1`, but not `p<0` or `p>1`.

### Suggested fix

```matlab
idx = calibparamsvecindex(pp)+1:calibparamsvecindex(pp+1);
p = calibparamsvec(idx);

if any(p < 0 | p > 1)
    error('Initial guess for 0-to-1 constrained parameter is outside [0,1].');
end

calibparamsvec(idx) = min(49.99, max(-49.99, log(p./(1-p))));

```

Apply this in:

- `ParameterConstraints_TransformParamsToUnconstrained.m`
- `ParameterConstraints_PType_TransformParamsToUnconstrained.m`

* * *

## 5. Add checks for A-to-B constraints

Current logic first maps:

```matlab
p01 = (p-A)/(B-A);

```

then applies the 0-to-1 logit transform.

This is valid only if:

- `B > A`
- initial `p` is in `[A,B]`

### Suggested fix

```matlab
idx = calibparamsvecindex(pp)+1:calibparamsvecindex(pp+1);

A = caliboptions.constrainAtoBlimits(pp,1);
B = caliboptions.constrainAtoBlimits(pp,2);

if B <= A
    error('constrainAtoB upper bound must be greater than lower bound.');
end

p = calibparamsvec(idx);

if any(p < A | p > B)
    error('Initial guess for A-to-B constrained parameter is outside [A,B].');
end

calibparamsvec(idx) = (p-A)/(B-A);

```

Apply this in:

- `ParameterConstraints_TransformParamsToUnconstrained.m`
- `ParameterConstraints_PType_TransformParamsToUnconstrained.m`

* * *

## 6. Penalty is not used in the `lsqnonlin` residual vector

The inverse transform computes a `penalty` when transformed parameters move too far beyond the artificial cutoffs.

For scalar objectives, the penalty is used. But for `lsqnonlin`, the objective returns a vector of residuals with `caliboptions.vectoroutput==2`. The penalty is not appended to that vector.

### Suggested fix

In the `vectoroutput==2` branch of each objective function, after constructing `Obj`, add:

```matlab
if penalty > 0
    Obj = [Obj; sqrt(penalty)];
end

```

This is natural because `lsqnonlin` minimizes the sum of squared residuals.

Apply this to relevant objective functions:

- `CalibrateLifeCycleModel_objectivefn.m`
- `CalibrateOLGModel_*_objectivefn.m`
- `CalibrateBIHAModel_*_objectivefn.m`
- `CalibrateInfHorzAgentModel_objectivefn.m`
- PType objective functions

* * *

## 7. The inverse transformation formula is conceptually fine

The non-PType inverse transform uses:

```matlab
p = exp(x)

```

for positive constraints,

```matlab
p = 1./(1+exp(-x))

```

for 0-to-1 constraints, and

```matlab
p = A + (B-A)*p01

```

for A-to-B constraints.

These formulas are correct.

The main problems are:

1. PType wrappers call the non-PType inverse transform.
2. Initial guesses are not checked before applying `log` or `logit`.
3. `lsqnonlin` does not use the penalty in the residual vector.
4. `CalibrateLifeCycleModel.m` has a duplicated `usingallstats` argument under `fminalgo==8`.

* * *

## Summary of recommended changes

Highest priority:

1. Add `ParameterConstraints_PType_TransformParamsToOriginal.m`.
2. Use it in all PType calibration wrappers.
3. Fix duplicated `usingallstats` in `CalibrateLifeCycleModel.m` under `fminalgo==8`.

Medium priority:

1. Add explicit initial-guess checks for:
  - positive constraints: parameter must be non-negative
  - 0-to-1 constraints: parameter must be in `[0,1]`
  - A-to-B constraints: parameter must be in `[A,B]`
  - A-to-B limits: require `B>A`

Lower priority:

1. Add a penalty residual in the `vectoroutput==2` / `lsqnonlin` branch.

---

_[View the full topic](https://discourse.vfitoolkit.com/t/constrain-general-eqm-parameters/392)._
