docstr: Test estimation on simulated data from a parametric 
  Hawkes model with exponential kernels
docstr_tok: ["Test","estimation","on","simulated","data","from","a","parametric","Hawkes","model","with","exponential","kernels"]
code: def test_hawkes_em_fit_2(self):
      """
      Test estimation on simulated data from a parametric
      Hawkes model with exponential kernels
      """
      seed = 12345
      n_nodes = 2
      n_realizations = 1
      decays = np.array([[1.0, 1.5], [0.1, 0.5]])
      baseline = np.array([0.12, 0.07])
      adjacency = np.array([[0.1, 0.4], [0.2, 0.03]])
      end_time = 30000
      simu_model = simulate_hawkes_exp_kern(
          decays=decays,
          baseline=baseline,
          adjacency=adjacency,
          end_time=end_time,
          max_jumps=200000,
          verbose=True,
          force_simulation=False,
          seed=seed,
      )
  
      kernel_support = compute_approx_support_of_exp_kernel(
          adjacency, decays, 1e-4
      )
      # print(f'kernel_suppport = {kernel_support}')
      kernel_size = 20
  
      events = simu_model.timestamps
      baseline_start = np.array(
          [0.05 * np.mean(np.diff(ts)) for ts in simu_model.timestamps]
      )
      # print(f'baseline_start = {baseline_start}')
      kernel_start = np.zeros((n_nodes, n_nodes, kernel_size))
      kernel_start[:, :, : kernel_size - 1] = (
          0.01
          * np.cumsum(
              np.random.uniform(
                  size=(n_nodes, n_nodes, kernel_size - 1)
              ),
              axis=2,
          )[:, :, ::-1]
      )
      # print(f'kernel_start = {kernel_start}')
      em = HawkesEM(
          kernel_support=kernel_support,
          kernel_size=kernel_size,
          tol=1e-9,
          print_every=50,
          record_every=10,
          max_iter=1200,
          verbose=True,
      )
      em.fit(
          events,
          baseline_start=baseline_start,
          kernel_start=kernel_start,
      )
  
      expected_kernel = discretization_of_exp_kernel(
          n_nodes,
          adjacency,
          decays,
          kernel_support,
          kernel_size,
      )
      expected_baseline = baseline
  
      # Test 1.1: shape of baseline
      self.assertEqual(
          expected_baseline.shape,
          em.baseline.shape,
          "Expected baseline and estimated baseline do not have the same shape\n"
          "expected_baseline.shape: {expected_baseline.shape}\n"
          "em.baseline.shape: {em.baseline.shape}\n",
      )
  
      # Test 1.2: relative magnitudes of baseline
      np.testing.assert_array_equal(
          np.argsort(em.baseline),
          np.argsort(expected_baseline),
          err_msg="Relative magnitudes are not consistent"
          "between expected baseline and estimated baseline",
      )
  
      # Test 1.3: approximate equality of baseline
      np.testing.assert_array_almost_equal(
          em.baseline,
          expected_baseline,
          decimal=1,
      )
  
      # Test 2.1: shape of kernel
      self.assertEqual(
          expected_kernel.shape,
          em.kernel.shape,
          "Expected kernel and estimated kernel do not have the same shape\n"
          "expected_kernel.shape: {expected_kernel.shape}\n"
          "em.kernel.shape: {em.kernel.shape}\n",
      )
  
      # Test 2.2: estimated kernel must be non-negative
      self.assertTrue(
          np.all(em.kernel >= 0),
          f"Estimated kernel takes negative values",
      )
  
      # Test 2.3: estimated kernel must be non-increasing
      significance_threshold = 7e-3  # Can we do better?
      estimated_kernel_increments = np.diff(
          em.kernel, append=0.0, axis=2
      )
      estimated_kernel_significant_increments = (
          estimated_kernel_increments[
              np.abs(estimated_kernel_increments)
              > significance_threshold
          ]
      )
      assert estimated_kernel_increments.shape == (
          n_nodes,
          n_nodes,
          kernel_size,
      )
  
      self.assertTrue(
          np.all(estimated_kernel_significant_increments <= 0.0),
          "Estimated kernel are not non-increasing functions. "
          "This is not compatible with the simulation "
          "being performed with exponential kernels.\n"
          f"estimated_kernel_increments:\n{estimated_kernel_increments}\n"
          f"estimated_kernel_significant_increments:\n{estimated_kernel_significant_increments}\n"
          f"estimated_kernel_significant_increments bigger than 0:\n{estimated_kernel_significant_increments[estimated_kernel_significant_increments>.0]}\n",
      )
  
      # Test 2.4: relative magnitudes of kernel at zero
      expected_kernel_at_zero = expected_kernel[:, :, 0].flatten()
      estimated_kernel_at_zero = np.array(em.kernel, copy=True)[
          :, :, 0
      ].flatten()
      np.testing.assert_array_equal(
          np.argsort(
              estimated_kernel_at_zero[estimated_kernel_at_zero > 0.0]
          ),
          np.argsort(
              expected_kernel_at_zero[expected_kernel_at_zero > 0.0]
          ),
          err_msg="Relative magnitudes are not consistent "
          "between expected kernel and estimated kernel\n"
          f"expected_kernel_at_zero:\n{expected_kernel_at_zero}\n"
          f"estimated_kernel_at_zero:\n{estimated_kernel_at_zero}\n",
      )
  
      # Test 2.5: approximate equality of kernel at zero
      np.testing.assert_array_almost_equal(
          expected_kernel_at_zero,
          estimated_kernel_at_zero,
          decimal=0,  # Can we do better?
          err_msg="estimated kernel at zero deviates "
          "from expected  kernel at zero.\n"
          f"expected_kernel_at_zero:\n{expected_kernel_at_zero}\n"
          f"estimated_kernel_at_zero:\n{estimated_kernel_at_zero}\n",
      )
  
imports: import unittest
  import numpy
  from tick.hawkes.inference import HawkesEM
  from tick.hawkes.model.tests.model_hawkes_test_utils import hawkes_intensities, hawkes_log_likelihood
  from tick.hawkes import SimuHawkes, HawkesKernelTimeFunc, HawkesKernelExp, SimuHawkesExpKernels
  from tick.base import TimeFunction
label_desc: Use image node_id 4 for calling the Test obj's underlying member method code with example usage: obj.test_hawkes_em_fit_2() without return types