file src/PoissonCalculators.cpp

[No description available] More…

Namespaces

Name
Gambit
TODO: see if we can use this one:
Gambit::ColliderBit
Gambit::ColliderBit::PoissonCalculators

Detailed Description

Author:

  • Chris Chang
  • Andrew Fowlie

Date:

  • 2024 Oct
  • 2024 Oct

Functions for working with an unbiased Poisson likelihood estimator.


Authors (add name and date if you modify):


Source code

//   GAMBIT: Global and Modular BSM Inference Tool
//   *********************************************
///  \file
///
///  Functions for working with an unbiased 
///  Poisson likelihood estimator.
///
///  *********************************************
///
///  Authors (add name and date if you modify):
///
///  \author Chris Chang
///  \date   2024 Oct
///
///  \author Andrew Fowlie
///  \date   2024 Oct
///
///  *********************************************

#include "gambit/Elements/gambit_module_headers.hpp"
#include "gambit/ColliderBit/ColliderBit_rollcall.hpp"
#include "gambit/ColliderBit/PoissonCalculators.hpp"

namespace Gambit
{
  namespace ColliderBit
  {
    namespace PoissonCalculators
    {


      double log_factorial(double k)
      {
        return std::lgamma(k + 1);
      }

      double beta(double x, double y)
      {
        return std::tgamma(x) * std::tgamma(y) / std::tgamma(x + y);
      }

      double binom(double n, double k)
      {
        if (n < k) { return 0.;}
        return 1. / ((n + 1.) * beta(n - k + 1., k + 1.));
      }

      /**
      Unbiased likelihood estimator
      */

      template <typename engine_type>
      int umvue_draw_n_mc(double n_mc, engine_type engine)
      {
        std::poisson_distribution<> poisson(n_mc);
        return poisson(engine);
      }

      int umvue_draw_n_mc(double n_mc)
      {
        std::random_device rd;
        std::mt19937 engine(rd());
        return umvue_draw_n_mc(n_mc, engine);
      }
      
      int umvue_draw_n_mc_threadsafe(double n_mc)
      {
        std::poisson_distribution<> poisson(n_mc);
        return poisson(Random::rng());
      }
      
      double umvue_poisson_like(int k, double b, int o, int n_mc, double n_exp)
      {

        if ((n_mc <= 0) || (n_exp <= 0))
        {
          ColliderBit_error().raise(LOCAL_INFO, "umvue_poisson_like: n_mc <= 0 || n_exp <= 0");
        }

        const double f = n_exp / n_mc;

        const double eps = 1.0e-9;

        // special case b = 0 and maybe f = 1
        if (std::fabs(b - 0.) < eps)
        {
          if (std::fabs(f - 1.) < eps)
          {
            return k == o ? 1. : 0.;
          }
          return binom(k, o) * std::pow(f, k) * std::pow(1. - f, k - o);
        }

        // special case b !=0 but f = 1
        if (std::fabs(f - 1.) < eps)
        {
          if (k > o) {return 0.;}

          const double ln_like = -b + (o - k) * std::log(b) -log_factorial(o - k);
          return std::exp(ln_like);
        }

        // general cases
        double sum = 0.;
        double term = 1.;
        const double r = f / (1. - f) / b;

        for (int i = 0; i <= std::min(k, o); i++)
        {
          sum += term;
          term *= r * (k - i) * (o - i) / (i + 1);
        }

        const double ln_norm = o * std::log(b) - b - log_factorial(o);
        const double norm = std::exp(ln_norm);
        
        return norm * std::pow(1. - f, k) * sum;
      }

      /**
      Regular likelihood estimator
      */
      double mle_poisson_loglike(double s, double b, int o)
      {
        double sb = s + b;
        return o*log(sb) - sb - log_factorial(o);
      }

    }  // end namespace PoissonCalculators
  }  // end namespace ColliderBit
}  // end namespace Gambit

Updated on 2025-02-12 at 15:36:43 +0000