Changeset 323

Show
Ignore:
Timestamp:
11/12/08 17:00:08 (2 months ago)
Author:
emuller
Message:

Added adapting markov process (1d and 2d) to stgen

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/src/stgen.py

    r307 r323  
    2121""" 
    2222 
    23  
    24 # TODO : needs refactoring 
    25 # TODO: needs python gsl wrapper / convert to numpy 
    26 # TODO make it generate spiketrains? 
    2723 
    2824from NeuroTools import check_dependency 
     
    392388    else: 
    393389        inh_gamma_generator = _inh_gamma_generator_unimplemented 
     390 
     391 
     392 
     393    def _inh_adaptingmarkov_generator_python(self, a, bq, tau, t, t_stop, array=False): 
     394 
     395        """ 
     396        Returns a SpikeList whose spikes are an inhomogeneous 
     397        realization (dynamic rate) of the so-called adapting markov 
     398        process (see references). The implementation uses the thinning 
     399        method, as presented in the references. 
     400 
     401        This is the 1d implementation, with no relative refractoriness. 
     402        For the 2d implementation with relative refractoriness,  
     403        see the inh_2dadaptingmarkov_generator. 
     404 
     405        Inputs: 
     406            a,bq    - arrays of the parameters of the hazard function where a[i] and bq[i]  
     407                     will be active on interval [t[i],t[i+1]] 
     408            tau    - the time constant of adaptation (in milliseconds). 
     409            t      - an array specifying the time bins (in milliseconds) at which to  
     410                     specify the rate 
     411            t_stop - length of time to simulate process (in ms) 
     412            array  - if True, a numpy array of sorted spikes is returned, 
     413                     rather than a SpikeList object. 
     414 
     415        Note:  
     416            - t_start=t[0] 
     417 
     418            - a is in units of Hz.  Typical values are available  
     419              in Fig. 1 of Muller et al 2007, a~5-80Hz (low to high stimulus) 
     420 
     421            - bq here is taken to be the quantity b*q_s in Muller et al 2007, is thus 
     422              dimensionless, and has typical values bq~3.0-1.0 (low to high stimulus) 
     423 
     424            - tau_s has typical values on the order of 100 ms 
     425 
     426 
     427        References: 
     428 
     429        Eilif Muller, Lars Buesing, Johannes Schemmel, and Karlheinz Meier  
     430        Spike-Frequency Adapting Neural Ensembles: Beyond Mean Adaptation and Renewal Theories 
     431        Neural Comput. 2007 19: 2958-3010. 
     432         
     433        Devroye, L. (1986). Non-uniform random variate generation. New York: Springer-Verlag. 
     434 
     435        Examples: 
     436         
     437        See also: 
     438            inh_poisson_generator, inh_gamma_generator, inh_2dadaptingmarkov_generator 
     439 
     440        """ 
     441 
     442        from numpy import shape 
     443 
     444        if shape(t)!=shape(a) or shape(a)!=shape(bq): 
     445            raise ValueError('shape mismatch: t,a,b must be of the same shape') 
     446 
     447        # get max rate and generate poisson process to be thinned 
     448        rmax = numpy.max(a) 
     449        ps = self.poisson_generator(rmax, t_start=t[0], t_stop=t_stop, array=True) 
     450 
     451        isi = numpy.zeros_like(ps) 
     452        isi[1:] = ps[1:]-ps[:-1] 
     453        isi[0] = ps[0] #-0.0 # assume spike at 0.0 
     454 
     455        # return empty if no spikes 
     456        if len(ps) == 0: 
     457            return SpikeTrain(numpy.array([]), t_start=t[0],t_stop=t_stop) 
     458 
     459 
     460        # gen uniform rand on 0,1 for each spike 
     461        rn = numpy.array(self.rng.uniform(0, 1, len(ps))) 
     462 
     463        # instantaneous a,bq for each spike 
     464 
     465        idx=numpy.searchsorted(t,ps)-1 
     466        spike_a = a[idx] 
     467        spike_bq = bq[idx] 
     468 
     469        keep = numpy.zeros(shape(ps),bool) 
     470 
     471        # thin spikes 
     472 
     473        i = 0 
     474        t_last = 0.0 
     475        t_i = 0 
     476        # initial adaptation state is unadapted, i.e. large t_s 
     477        t_s = 1000*tau 
     478 
     479        while(i<len(ps)): 
     480            # find index in "t" time, without searching whole array each time 
     481            t_i = numpy.searchsorted(t[t_i:],ps[i],'right')-1+t_i 
     482 
     483            # evolve adaptation state 
     484            t_s+=isi[i] 
     485 
     486            if rn[i]<a[t_i]*numpy.exp(-bq[t_i]*numpy.exp(-t_s/tau))/rmax: 
     487                # keep spike 
     488                keep[i] = True 
     489                # remap t_s state 
     490                t_s = -tau*numpy.log(numpy.exp(-t_s/tau)+1) 
     491            i+=1 
     492 
     493 
     494        spike_train = ps[keep] 
     495 
     496        if array: 
     497            return spike_train 
     498 
     499        return SpikeTrain(spike_train, t_start=t[0],t_stop=t_stop) 
     500 
     501 
     502    # use slow python implementation for the time being 
     503    # TODO: provide optimized C/weave implementation if possible 
     504 
     505         
     506    inh_adaptingmarkov_generator = _inh_adaptingmarkov_generator_python 
     507 
     508 
     509    def _inh_2Dadaptingmarkov_generator_python(self, a, bq, tau_s, tau_r, qrqs, t, t_stop, array=False): 
     510 
     511        """ 
     512        Returns a SpikeList whose spikes are an inhomogeneous 
     513        realization (dynamic rate) of the so-called 2D adapting markov 
     514        process (see references).  2D implies the process has two 
     515        states, an adaptation state, and a refractory state, both of 
     516        which affect its probability to spike.  The implementation 
     517        uses the thinning method, as presented in the references. 
     518 
     519        For the 1d implementation, with no relative refractoriness, 
     520        see the inh_adaptingmarkov_generator. 
     521 
     522        Inputs: 
     523            a,bq    - arrays of the parameters of the hazard function where a[i] and bq[i]  
     524                     will be active on interval [t[i],t[i+1]] 
     525            tau_s    - the time constant of adaptation (in milliseconds). 
     526            tau_r    - the time constant of refractoriness (in milliseconds). 
     527            qrqs     - the ratio of refractoriness conductance to adaptation conductance. 
     528                       typically on the order of 200. 
     529            t      - an array specifying the time bins (in milliseconds) at which to  
     530                     specify the rate 
     531            t_stop - length of time to simulate process (in ms) 
     532            array  - if True, a numpy array of sorted spikes is returned, 
     533                     rather than a SpikeList object. 
     534 
     535        Note:  
     536            - t_start=t[0] 
     537 
     538            - a is in units of Hz.  Typical values are available  
     539              in Fig. 1 of Muller et al 2007, a~5-80Hz (low to high stimulus) 
     540 
     541            - bq here is taken to be the quantity b*q_s in Muller et al 2007, is thus 
     542              dimensionless, and has typical values bq~3.0-1.0 (low to high stimulus) 
     543 
     544            - qrqs is the quantity q_r/q_s in Muller et al 2007,  
     545              where a value of qrqs = 3124.0nS/14.48nS = 221.96 was used. 
     546 
     547            - tau_s has typical values on the order of 100 ms 
     548            - tau_r has typical values on the order of 2 ms 
     549 
     550 
     551        References: 
     552 
     553        Eilif Muller, Lars Buesing, Johannes Schemmel, and Karlheinz Meier  
     554        Spike-Frequency Adapting Neural Ensembles: Beyond Mean Adaptation and Renewal Theories 
     555        Neural Comput. 2007 19: 2958-3010. 
     556         
     557        Devroye, L. (1986). Non-uniform random variate generation. New York: Springer-Verlag. 
     558 
     559        Examples: 
     560         
     561        See also: 
     562            inh_poisson_generator, inh_gamma_generator, inh_adaptingmarkov_generator 
     563 
     564        """ 
     565 
     566        from numpy import shape 
     567 
     568        if shape(t)!=shape(a) or shape(a)!=shape(bq): 
     569            raise ValueError('shape mismatch: t,a,b must be of the same shape') 
     570 
     571        # get max rate and generate poisson process to be thinned 
     572        rmax = numpy.max(a) 
     573        ps = self.poisson_generator(rmax, t_start=t[0], t_stop=t_stop, array=True) 
     574 
     575        isi = numpy.zeros_like(ps) 
     576        isi[1:] = ps[1:]-ps[:-1] 
     577        isi[0] = ps[0] #-0.0 # assume spike at 0.0 
     578 
     579        # return empty if no spikes 
     580        if len(ps) == 0: 
     581            return SpikeTrain(numpy.array([]), t_start=t[0],t_stop=t_stop) 
     582 
     583 
     584        # gen uniform rand on 0,1 for each spike 
     585        rn = numpy.array(self.rng.uniform(0, 1, len(ps))) 
     586 
     587        # instantaneous a,bq for each spike 
     588 
     589        idx=numpy.searchsorted(t,ps)-1 
     590        spike_a = a[idx] 
     591        spike_bq = bq[idx] 
     592 
     593        keep = numpy.zeros(shape(ps),bool) 
     594 
     595        # thin spikes 
     596 
     597        i = 0 
     598        t_last = 0.0 
     599        t_i = 0 
     600        # initial adaptation state is unadapted, i.e. large t_s 
     601        t_s = 1000*tau_s 
     602        t_r = 1000*tau_s 
     603 
     604        while(i<len(ps)): 
     605            # find index in "t" time, without searching whole array each time 
     606            t_i = numpy.searchsorted(t[t_i:],ps[i],'right')-1+t_i 
     607 
     608            # evolve adaptation state 
     609            t_s+=isi[i] 
     610            t_r+=isi[i] 
     611 
     612            if rn[i]<a[t_i]*numpy.exp(-bq[t_i]*(numpy.exp(-t_s/tau_s)+qrqs*numpy.exp(-t_r/tau_r)))/rmax: 
     613                # keep spike 
     614                keep[i] = True 
     615                # remap t_s state 
     616                t_s = -tau_s*numpy.log(numpy.exp(-t_s/tau_s)+1) 
     617                t_r = -tau_r*numpy.log(numpy.exp(-t_r/tau_r)+1) 
     618            i+=1 
     619 
     620 
     621        spike_train = ps[keep] 
     622 
     623        if array: 
     624            return spike_train 
     625 
     626        return SpikeTrain(spike_train, t_start=t[0],t_stop=t_stop) 
     627 
     628 
     629    # use slow python implementation for the time being 
     630    # TODO: provide optimized C/weave implementation if possible 
     631 
     632         
     633    inh_2Dadaptingmarkov_generator = _inh_2Dadaptingmarkov_generator_python 
     634 
     635 
     636 
     637 
     638 
    394639 
    395640 
  • trunk/test/test_stgen.py

    r307 r323  
    227227 
    228228 
     229    def testInhAdaptingMarkov(self): 
     230 
     231 
     232        stg = stgen.StGen() 
     233 
     234        from numpy import array 
     235 
     236        t = array([0.0,5000.0]) 
     237        # using parameters from paper 
     238        a = array([23.18,47.24]) 
     239        bq = array([0.10912,0.09794])*14.48 
     240 
     241        # expected mean firing rates for 2D case 
     242        alpha = array([7.60, 10.66]) 
     243 
     244        tau = 110.0 
     245        t_stop = 10000.0 
     246 
     247        st = stg.inh_adaptingmarkov_generator(a,bq,tau,t,t_stop) 
     248        assert isinstance(st,signals.SpikeTrain) 
     249 
     250        st = stg.inh_adaptingmarkov_generator(a,bq,tau,t,t_stop,array=True) 
     251        assert isinstance(st, numpy.ndarray) 
     252 
     253        assert st[-1] < t_stop 
     254        assert st[0] > t[0] 
     255 
     256 
     257    def testInh2DAdaptingMarkov(self): 
     258 
     259 
     260        stg = stgen.StGen() 
     261 
     262        from numpy import array 
     263 
     264        t = array([0.0,10000.0]) 
     265        # using parameters from paper 
     266        a = array([23.18,47.24]) 
     267        bq = array([0.10912,0.09794])*14.48 
     268 
     269        # expected mean firing rates for 2D case 
     270        alpha = array([7.60, 10.66]) 
     271 
     272        tau_s = 110.0 
     273        tau_r = 1.97 
     274        qrqs = 221.96 
     275        t_stop = 20000.0 
     276 
     277        st = stg.inh_2Dadaptingmarkov_generator(a,bq,tau_s,tau_r,qrqs,t,t_stop) 
     278        assert isinstance(st,signals.SpikeTrain) 
     279 
     280        st = stg.inh_2Dadaptingmarkov_generator(a,bq,tau_s,tau_r,qrqs,t,t_stop,array=True) 
     281        assert isinstance(st, numpy.ndarray) 
     282 
     283        assert st[-1] < t_stop 
     284        assert st[0] > t[0] 
     285 
     286        spikes1 = len(st[st<10000]) 
     287        spikes2 = len(st[st>10000]) 
     288         
     289        # should be approximately alpha[0]*10.0 spikes 
     290        assert numpy.clip(spikes1,60,100)==spikes1 
     291 
     292        # should be approximately alpha[1]*10.0 spikes 
     293        assert numpy.clip(spikes2,80,140)==spikes2 
     294 
     295 
    229296 
    230297