State values of Tauchen method in the Quantecon package

Hi all, I am a new user of Julia and the forum. I will apologize in advance if I am asking a question that has been answered.
I am trying to implement the Tauchen method of discretizing AR(1) processes by the function provided in Tauchen method. When I want to output my state spaces (say 3) by simply printing mc.state_values. The second one is the same as the third one. When there are four states, printing mc.state_values only gives 3. However, when checking each of them using mc.state_values[i], everything seems normal. See pic (3 states):

Code: `Using QuantEcon

mc = tauchen(3, 0.9, 1)
Is it a bug of Julia or the code? Or is it some other features I don’t know that play here?

Hi there @2xu2 ,

If you try typeof(mc.state_values) you will see it’s an abstract vector, probably of type StepRangeLen. The format is start:step_size:end.

If you type collect(mc.state_values) you will get an ordinary vector.

Hope that helps. John.

1 Like

Hi John,
Thanks, it is very helpful.
May I also ask if there’s a way to multi-dispatch a discrete markov chain?
Say I want to get the states and transition matrix of a discrete markov chain. Can I do something like (state, transition) = mc to get them? Or do I have to stick with using two lines?

I usually write something like

julia> mc = tauchen(3, .9, .1);

julia> states, probs = mc.state_values, mc.p

Yeah, as john said the state_values is not an array, although it “behaves” like one for most purposes.

In general, you are better off leaving things in their more abstract form as long as possible since otherwise you lose structure that can lead to better algorithms. Most julia algorithms will work just as well with a range as with a concrete array so you probably won’t even notice. Why is it different? A small point here is that there is essentially no storage in the state_values other than the starting point, the step-size, and the number of elements. If you convert it to a vector it will both need a vector to have all of those values (which is probably irrelvant for small ones like this simple example, but this is a serious issue for larger ranges), but the ore important problem is that it loses the structure that this is a uniformly spaced vector.

Where would that be useful? Well, occasionally when iterating through it the compiler can use it to radically speed things up but the bigger consideration is that it allows specialized algorithms. For example, interpolating with Convenience Constructors · Interpolations.jl would do something different if you pass in a range, 1.0:0.01:2.0, vs. a vector, collect(1.0:0.01:2.0)which it can’t know would be regularly spaced. In fact, there isn’t even a cubicspline feature in that package for irregularly spaced grids so it wouldn’t work at all if you pass it in after converting to a vector.

If you can handle the state and transition as being the same names as the fields, then since Julia 1.7, the canonical way of doing this sort of thing is

(; state_values, p) = mc

if you want to extract those. Or pre julia 1.7 you will see things using the Parameters/Unpack macro all over the place in people’s code

@unpack state_values, p = mc

This isn’t strictly necessary, of course, but the style is pervasive in Julia. The main benefit is that the lack of repetition leads to what you would call “defensive programming” to make bugs less likely

For example, spot what is wrong with unpacking this datastructure with a few more fields:

field_c, field_d, field_a, field_b = mc.field_c, mc.field_a, mc.field_d, mc.field_b


(;field_c, field_d, field_a, field_b) = mc

It becomes very easy to accidentally mismatch the order of the fields in the first case - especially if you are adding/removing a bunch of them and forget to swap the order on both sides. But as I said, these are small stylistic things which you don’t need to apply religiously (and has no impact on performance either way).

Thanks, Jesse. Really appreciate the detailed explanation from you and John.