GSoC 2019: Testing an API

1 minute read

Published:

This is a really short update. Here are a couple things I have been working on since the last blog post.

1) Continuing to write the API so that it is intuitive

2) Writing unit tests

3) Benchmarking

When I last made a blog post about the API, users were to pass the ode parameters and initial conditions as a single vector. That was just to get things off the ground. Now that API is working, I can go back and make that a little more user friendly. The ODEModel (the meat and potatoes of the API) inherits from the theano.Op class, so in the make_node method I changed


    def make_node(self, x):
        x = theano.tensor.as_tensor_variable(x)

        return theano.Apply(self, [x], [x.type()])

to

    def make_node(self, odeparams, initial_condition):

        if np.ndim(odeparams)>1:
            odeparams = np.ravel(odeparams)
        if np.ndim(initial_condition) > 1:
            odeparams = np.ravel(initial_condition)


        odeparams = tt.as_tensor_variable(odeparams)
        initial_condition = tt.as_tensor_variable(initial_condition)
        x = tt.concatenate([odeparams,initial_condition])

        return theano.Apply(self, [x], [x.type()])

The little bit of logic at the beginning is to get around some shape problems with theano. So now to use the API, instead of doing

  all_params = pm.math.stack([<parameters here>, <initial conditions here>])
  forward = ode_model(all_params)

you can do


  forward = ode_model(odeparams = [<parameters here>], initial_condition = [<initial conditions here>])

which I think is much better. Explicit is better than implicit. This change actually makes some models run much faster which is interesting.