Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MARKOV: Put the Markov functions into a class wrapper and created a way ... #43

Merged
merged 3 commits into from
Aug 7, 2014

Conversation

cc7768
Copy link
Member

@cc7768 cc7768 commented Aug 7, 2014

...to work around issues with multiple eigenvalues near unity to prevent nonstationary distirbutions from being considered stationary.

If you get a chance to look, let me know what you think. There are some minor things that I plan on changing (right now I'm squeezing everything so that it works with the tests that people had already written, but eventually I hope to clean that up or change the tests). This is more to get a working version into master and get some feedback of what people think of using a class as a wrapper.

…ay to work around issues with multiple eigenvalues near unity to prevent nonstationary distirbutions from being considered stationary.
@sglyon
Copy link
Member

sglyon commented Aug 7, 2014

I haven't taken time to read through what the code does, but I like the class. Also, it looks like you wrapped the simluation function to be a class method -- I like this and would suggest that we wrap mc_compute_stationary in a similar way.

@sglyon
Copy link
Member

sglyon commented Aug 7, 2014

I see that you have pretty much done that already.

I would suggest the following changes:

  • Make the method names match the function names. This would be very similar to numpy naming conventions (e.g. np.shape(P) == P.shape or np.reshape(P, (1,4)) == P.reshape((1, 4)))
  • Make the method docstrings inherit the function's docstrings. This way we only have to maintain one set of docstrings. There is an example below:
def mc_sample_path(P, init=0, sample_size=1000):
    # === set up array to store output === #
    X = np.empty(sample_size, dtype=int)
    if isinstance(init, int):
        X[0] = init
    else:
        X[0] = DiscreteRV(init).draw()

    # === turn each row into a distribution === #
    # In particular, let P_dist[i] be the distribution corresponding to the
    # i-th row P[i,:]
    n = len(P)
    P_dist = [DiscreteRV(P[i,:]) for i in range(n)]

    # === generate the sample path === #
    for t in range(sample_size - 1):
        X[t+1] = P_dist[X[t]].draw()

    return X

_sample_path_docstr = \
"""
Generates one sample path from a finite Markov chain with (n x n)
Markov matrix P on state space S = {{0,...,n-1}}.

Parameters
----------
{p_arg}init : array_like(float ndim=1) or scalar(int)
    If init is an array_like then it is treated as the initial
    distribution across states.  If init is a scalar then it
    treated as the deterministic initial state.

sample_size : scalar(int), optional(default=1000)
    The length of the sample path.

Returns
-------
X : array_like(int, ndim=1)
    The simulation of states

"""

# set docstring for function
mc_sample_path.__doc__ = _sample_path_docstr.format(p_arg=
"""P : array_like(float, ndim=2)
    A discrete Markov transition matrix

""")


class DMarkov(object):

    # Other methods

    def mc_sample_path(self, init=0, sample_size=1000):

        return mc_sample_path(self.P, init, sample_size)


# set docstring for method
DMarkov.mc_sample_path.__func__.__doc__ = _sample_path_docstr.format(p_arg="")

Then in a python session it all works as expected:

In [27]: dm = DMarkov(np.random.rand(4, 4))

In [29]: dm.mc_sample_path?
Type:        instancemethod
String form: <bound method DMarkov.mc_sample_path of <__main__.DMarkov object at 0x1080bb250>>
File:        /Users/sglyon/Desktop/foo.py
Definition:  dm.mc_sample_path(self, init=0, sample_size=1000)
Docstring:
Generates one sample path from a finite Markov chain with (n x n)
Markov matrix P on state space S = {0,...,n-1}.

Parameters
----------
init : array_like(float ndim=1) or scalar(int)
    If init is an array_like then it is treated as the initial
    distribution across states.  If init is a scalar then it
    treated as the deterministic initial state.

sample_size : scalar(int), optional(default=1000)
    The length of the sample path.

Returns
-------
X : array_like(int, ndim=1)
    The simulation of states

In [30]: mc_sample_path?
Type:        function
String form: <function mc_sample_path at 0x1080ba9b0>
File:        /Users/sglyon/Desktop/foo.py
Definition:  mc_sample_path(P, init=0, sample_size=1000)
Docstring:
Generates one sample path from a finite Markov chain with (n x n)
Markov matrix P on state space S = {0,...,n-1}.

Parameters
----------
P : array_like(float, ndim=2)
    A discrete Markov transition matrix

init : array_like(float ndim=1) or scalar(int)
    If init is an array_like then it is treated as the initial
    distribution across states.  If init is a scalar then it
    treated as the deterministic initial state.

sample_size : scalar(int), optional(default=1000)
    The length of the sample path.

Returns
-------
X : array_like(int, ndim=1)
    The simulation of states

This may be more convoluted than necessary, but it would be a way to minimize replication of docstrings. I'll officially call this an optional suggestion that you can do whatever you want with.

@cc7768
Copy link
Member Author

cc7768 commented Aug 7, 2014

Good suggestion. There is now no docstring repetition.

jstac added a commit that referenced this pull request Aug 7, 2014
Nice work guys, this is neat.
@jstac jstac merged commit 842f179 into master Aug 7, 2014
@jstac jstac deleted the markov_class branch August 7, 2014 23:29
jstac added a commit that referenced this pull request Aug 25, 2014
Nice work guys, this is neat.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants