def test_statistics(self):
        # This is a statistical test that has a non-zero chance of failure
        # during normal operation. Thus, we set the random seed to a value that
        # creates a realization passing the test.
        np.random.seed(seed=12345)

        shape_factor = 2.5

        for rate in [self.rate_profile, self.rate_profile.rescale(pq.kHz)]:
            spiketrain = stgen.inhomogeneous_gamma_process(
                rate, shape_factor=shape_factor)
            intervals = isi(spiketrain)

            # Computing expected statistics and percentiles
            expected_spike_count = (np.sum(rate) *
                                    rate.sampling_period).simplified
            percentile_count = poisson.ppf(.999, expected_spike_count)
            expected_min_isi = (1 / np.min(rate))
            expected_max_isi = (1 / np.max(rate))
            percentile_min_isi = expon.ppf(.999, expected_min_isi)
            percentile_max_isi = expon.ppf(.999, expected_max_isi)

            # Testing (each should fail 1 every 1000 times)
            self.assertLess(spiketrain.size, percentile_count)
            self.assertLess(np.min(intervals), percentile_min_isi)
            self.assertLess(np.max(intervals), percentile_max_isi)

            # Testing t_start t_stop
            self.assertEqual(rate.t_stop, spiketrain.t_stop)
            self.assertEqual(rate.t_start, spiketrain.t_start)

        # Testing type
        spiketrain_as_array = stgen.inhomogeneous_gamma_process(
            rate, shape_factor=shape_factor, as_array=True)
        self.assertTrue(isinstance(spiketrain_as_array, np.ndarray))
        self.assertTrue(isinstance(spiketrain, neo.SpikeTrain))

        # check error if rate has wrong format
        self.assertRaises(ValueError,
                          stgen.inhomogeneous_gamma_process,
                          rate=[0.1, 2.],
                          shape_factor=shape_factor)

        # check error if negative values in rate
        self.assertRaises(ValueError,
                          stgen.inhomogeneous_gamma_process,
                          rate=neo.AnalogSignal([-0.1, 10.] * pq.Hz,
                                                sampling_period=0.001 * pq.s),
                          shape_factor=shape_factor)

        # check error if rate is empty
        self.assertRaises(ValueError,
                          stgen.inhomogeneous_gamma_process,
                          rate=neo.AnalogSignal([] * pq.Hz,
                                                sampling_period=0.001 * pq.s),
                          shape_factor=shape_factor)
    def test_recovered_firing_rate_profile(self):
        np.random.seed(54)
        t_start = 0 * pq.s
        t_stop = 4 * np.round(np.pi, decimals=3) * pq.s  # 2 full periods
        sampling_period = 0.001 * pq.s

        # an arbitrary rate profile
        profile = 0.5 * (1 + np.sin(
            np.arange(t_start.item(), t_stop.item(), sampling_period.item())))

        time_generation = 0
        n_trials = 200
        rtol = 0.05  # 5% of deviation allowed
        kernel = kernels.RectangularKernel(sigma=0.25 * pq.s)
        for rate in (10 * pq.Hz, 100 * pq.Hz):
            rate_profile = neo.AnalogSignal(rate * profile,
                                            sampling_period=sampling_period)
            # the recovered firing rate profile should not depend on the
            # shape factor; here we test float and integer values of the shape
            # factor: the method supports float values that is not trivial
            # for inhomogeneous gamma process generation
            for shape_factor in (1, 2.5, 10.):

                spiketrains = \
                    [stgen.inhomogeneous_gamma_process(
                        rate_profile, shape_factor=shape_factor)
                     for _ in range(n_trials)]
                rate_recovered = instantaneous_rate(
                    spiketrains,
                    sampling_period=sampling_period,
                    kernel=kernel,
                    t_start=t_start,
                    t_stop=t_stop,
                    trim=True).sum(axis=1) / n_trials

                rate_recovered = rate_recovered.flatten().magnitude
                trim = (rate_profile.shape[0] - rate_recovered.shape[0]) // 2
                rate_profile_valid = rate_profile.magnitude.squeeze()
                rate_profile_valid = rate_profile_valid[trim:-trim - 1]
                assert_allclose(rate_recovered,
                                rate_profile_valid,
                                rtol=0,
                                atol=rtol * rate.item())