Parameter structures and restrictions

Hi,

I’m using a parameter structure for use in an economic model in Julia. I’d like to know what are the best practices here, including the best way to include restrictions when generating and modifying a parameter structure. Let me give you an MWE of the structure I’m using:

using Parameters

@with_kw mutable struct Param
    β::Float64                  = 0.95           # discount factor
    ϕ::Float64                  = 0.12           # relative taste for housing
    γ::Float64                  = 0.8             # ES parameter between consumption and housing
    βsq::Float64              = β^2            # squared discount factor
end

I then do p=Param(). Let’s say I wish to change β to 0.9. Two issues come up, that I’d like to overcome:

  1. I want βsq to update accordingly, if possible.
  2. I want to introduce restrictions on these variables. Say 0<β<1.

What are the best practices to do this (including abandoning the use of structures)?

Thanks for the help.

You could write a function to do this like

julia> function updateβ!(x::Param, βₙ)
           0 < βₙ < 1 || error("β has to be between 0 and 1")
           x.β = βₙ
           x.βsq = βₙ^2
       end
1 Like

You can do what @nilshg suggested.

Regarding you final question, I’ve found that if I am just dealing with individual parameters, I am often better off using named tuples. I only reach for structs when I am also passing around more complicated structures.

2 Likes

Given how lightweight your struct is, I’d guess the performance you might get with mutability might not be worth the hassle. An immutable approach (using simpler letters bc I’m on a phone) might look like this:

struct Params
    a::Real
    b::Real
    bsq::Real
    # mask the default constructor
    Params(a::Real = 0.5, b::Real = 0.5) = new(a, b, b^2)
end

# an "update" constructor, you can also call this `update` instead of making it a constructor
Params(old::Params; a=nothing, b=nothing) =
    Params(isnothing(a) ? old.a : a, isnothing(b) ? old.b : b)
1 Like

I believe the docs would suggest not to use the types as you’ve put them. Performance Tips · The Julia Language

Here is what I would do that addresses both concerns

function paramsfun(a,b)
    @assert 0 < b < 1 "b is must be between 0 and 1"
    return (; a, b, bsq=b^2)
end

Because you are only working with a few scalar values, creating named tuples is going to be lightweight and easy. You don’t have to worry about working “in place”. This thing will also place nicely with AD and lots of other neat tools for free.

1 Like

I believe the docs would suggest not to use the types as you’ve put them.

Ah, yes, for better performance it should be typed like this:

struct Params {T<:Real}
    a::T
    b::T
    bsq::T
end

I’m interested in this lightweight approach of using a tuple instead of an immutable struct, but I can’t seem to figure out how I’d write and update function to make it easy to get a new parameters tuple with just one or two values changed.

@tbeason can you show an example of updating parameters in the NamedTuple approach?

2 Likes

You can use packages for that if you want an easy way to do it. In truth I never use these but now that you’ve forced me to think about it I will probably do this going forward…

using BangBang

julia> p = paramsfun(0.8,0.95)
(a = 0.8, b = 0.95, bsq = 0.9025)

julia> p = setproperties!!(p;a=0.5)
(a = 0.5, b = 0.95, bsq = 0.9025)
1 Like

if you care about performance for this type at all, don’t use abstract type here

Thanks for the suggestion. That seems most clean

In my original structure, I have something like 150 parameters, which include vectors and matrices. But it doesn’t get more complex than that for now.

I’ll take these suggestions into account when thinking about my framework

This idea makes a lot of sense to me. The original structure has 150 parameters, which includes vectors and matrices as I said previously

I’ll take a look at these. Thanks

You can overload setproperty!, as well as your constructor(s), to enforce invariants like this.