<commit_before>AliAnalysisTaskSEDvsMultiplicity *AddTaskDvsMultiplicity(Int_t system=0,
							 Bool_t readMC=kFALSE,
							 Int_t MCOption=0,
							 Int_t pdgMeson=411,
							 TString finDirname="Loose",
							 TString filename="",
							 TString finAnObjname="AnalysisCuts",
							 TString estimatorFilename="",
							 Double_t refMult=9.26,
							 Bool_t subtractDau=kFALSE,
							 Bool_t NchWeight=kFALSE,
							 Int_t recoEstimator = AliAnalysisTaskSEDvsMultiplicity::kNtrk10,
							 Int_t MCEstimator = AliAnalysisTaskSEDvsMultiplicity::kEta10,
							 Bool_t isPPbData=kFALSE)
{
  //
  // Test macro for the AliAnalysisTaskSE for D+ candidates
  //Invariant mass histogram and
  // association with MC truth (using MC info in AOD)
  //  R. Bala, bala@to.infn.it
  // Get the pointer to the existing analysis manager via the static access method.
  //==============================================================================

  AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
  if (!mgr) {
    ::Error("AddTaskDvsMultiplicity", "No analysis manager to connect to.");
  }

  Bool_t stdcuts=kFALSE;
  TFile* filecuts;
  if( filename.EqualTo("") ) {
    stdcuts=kTRUE;
  } else {
    filecuts=TFile::Open(filename.Data());
    if(!filecuts ||(filecuts&& !filecuts->IsOpen())){
      AliFatal("Input file not found : check your cut object");
    }
  }

  //Analysis Task
  AliRDHFCuts *analysiscuts=0x0;

  TString Name="";
  if(pdgMeson==411){
    if(stdcuts) {
      analysiscuts = new AliRDHFCutsDplustoKpipi();
      if (system == 0) analysiscuts->SetStandardCutsPP2010();
      else analysiscuts->SetStandardCutsPbPb2011();
    }
    else analysiscuts = (AliRDHFCutsDplustoKpipi*)filecuts->Get(finAnObjname);
    Name="Dplus";
   }else if(pdgMeson==421){
    if(stdcuts) {
      analysiscuts = new AliRDHFCutsD0toKpi();
      if (system == 0) analysiscuts->SetStandardCutsPP2010();
      else analysiscuts->SetStandardCutsPbPb2011();
    }
    else analysiscuts = (AliRDHFCutsD0toKpi*)filecuts->Get(finAnObjname);
    Name="D0";
  }else if(pdgMeson==413){
    if(stdcuts) {
      analysiscuts = new AliRDHFCutsDStartoKpipi();
      if (system == 0) analysiscuts->SetStandardCutsPP2010();
      else analysiscuts->SetStandardCutsPbPb2011();
    }
    else analysiscuts = (AliRDHFCutsDStartoKpipi*)filecuts->Get(finAnObjname);
    Name="DStar";
  }

  AliAnalysisTaskSEDvsMultiplicity *dMultTask = new AliAnalysisTaskSEDvsMultiplicity("dMultAnalysis",pdgMeson,analysiscuts,isPPbData);
  dMultTask->SetReadMC(readMC);
  dMultTask->SetDebugLevel(0);
  dMultTask->SetUseBit(kTRUE);
  dMultTask->SetDoImpactParameterHistos(kFALSE);
  dMultTask->SetSubtractTrackletsFromDaughters(subtractDau);
  dMultTask->SetMultiplicityEstimator(recoEstimator);
  dMultTask->SetMCPrimariesEstimator(MCEstimator);
  dMultTask->SetMCOption(MCOption);
  if(isPPbData) dMultTask->SetIsPPbData();

  if(NchWeight){
    TH1F *hNchPrimaries = (TH1F*)filecuts->Get("hGenPrimaryParticlesInelGt0");
    if(hNchPrimaries) {
      dMultTask->UseMCNchWeight(true);
      dMultTask->SetHistoNchWeight(hNchPrimaries);
    } else {
      AliFatal("Histogram for multiplicity weights not found");
      return 0x0;
    }
  }

  if(pdgMeson==421) {
    dMultTask->SetMassLimits(1.5648,2.1648);
    dMultTask->SetNMassBins(200);
  }else if(pdgMeson==411)dMultTask->SetMassLimits(pdgMeson,0.2);

  if(estimatorFilename.EqualTo("") ) {
    printf("Estimator file not provided, multiplcity corrected histograms will not be filled\n");
  } else{

    TFile* fileEstimator=TFile::Open(estimatorFilename.Data());
    if(!fileEstimator)  {
      AliFatal("File with multiplicity estimator not found\n");
      return;
    }

    dMultTask->SetReferenceMultiplcity(refMult);

    if (isPPbData) {    //Only use two profiles if pPb
      const Char_t* periodNames[2] = {"LHC13b", "LHC13c"};
      TProfile* multEstimatorAvg[2];
      for(Int_t ip=0; ip<2; ip++) {
	multEstimatorAvg[ip] = (TProfile*)(fileEstimator->Get(Form("SPDmult10_%s",periodNames[ip]))->Clone(Form("SPDmult10_%s_clone",periodNames[ip])));
	if (!multEstimatorAvg[ip]) {
	  AliFatal(Form("Multiplicity estimator for %s not found! Please check your estimator file",periodNames[ip]));
	  return;
	}
      }
      dMultTask->SetMultiplVsZProfileLHC13b(multEstimatorAvg[0]);
      dMultTask->SetMultiplVsZProfileLHC13c(multEstimatorAvg[1]);
    }
    else {
      const Char_t* periodNames[4] = {"LHC10b", "LHC10c", "LHC10d", "LHC10e"};
      TProfile* multEstimatorAvg[4];
      for(Int_t ip=0; ip<4; ip++) {
	multEstimatorAvg[ip] = (TProfile*)(fileEstimator->Get(Form("SPDmult10_%s",periodNames[ip]))->Clone(Form("SPDmult10_%s_clone",periodNames[ip])));
	if (!multEstimatorAvg[ip]) {
	  AliFatal(Form("Multiplicity estimator for %s not found! Please check your estimator file",periodNames[ip]));
	  return;
	}
      }
      dMultTask->SetMultiplVsZProfileLHC10b(multEstimatorAvg[0]);
      dMultTask->SetMultiplVsZProfileLHC10c(multEstimatorAvg[1]);
      dMultTask->SetMultiplVsZProfileLHC10d(multEstimatorAvg[2]);
      dMultTask->SetMultiplVsZProfileLHC10e(multEstimatorAvg[3]);
    }
  }
  mgr->AddTask(dMultTask);

  // Create containers for input/output

  TString inname = "cinput";
  TString outname = "coutput";
  TString cutsname = "coutputCuts";
  TString normname = "coutputNorm";
  TString profname = "coutputProf";

  inname += Name.Data();
  outname += Name.Data();
  cutsname += Name.Data();
  normname += Name.Data();
  profname += Name.Data();
  inname += finDirname.Data();
  outname += finDirname.Data();
  cutsname += finDirname.Data();
  normname += finDirname.Data();
  profname += finDirname.Data();

  AliAnalysisDataContainer *cinput = mgr->CreateContainer(inname,TChain::Class(),AliAnalysisManager::kInputContainer);

  TString outputfile = AliAnalysisManager::GetCommonFileName();
  outputfile += ":PWG3_D2H_DMult_";
  outputfile += Name.Data();
  outputfile += finDirname.Data();

  AliAnalysisDataContainer *coutputCuts = mgr->CreateContainer(cutsname,TList::Class(),AliAnalysisManager::kOutputContainer,outputfile.Data());
  AliAnalysisDataContainer *coutput = mgr->CreateContainer(outname,TList::Class(),AliAnalysisManager::kOutputContainer,outputfile.Data());
  AliAnalysisDataContainer *coutputNorm = mgr->CreateContainer(normname,TList::Class(),AliAnalysisManager::kOutputContainer,outputfile.Data());
  AliAnalysisDataContainer *coutputProf = mgr->CreateContainer(profname,TList::Class(),AliAnalysisManager::kOutputContainer,outputfile.Data());

  mgr->ConnectInput(dMultTask,0,mgr->GetCommonInputContainer());

  mgr->ConnectOutput(dMultTask,1,coutput);

  mgr->ConnectOutput(dMultTask,2,coutputCuts);

  mgr->ConnectOutput(dMultTask,3,coutputNorm);

  mgr->ConnectOutput(dMultTask,4,coutputProf);

  return dMultTask;
}
<commit_msg>Change weight tracklet histo for pPb<commit_after>AliAnalysisTaskSEDvsMultiplicity *AddTaskDvsMultiplicity(Int_t system=0,
							 Bool_t readMC=kFALSE,
							 Int_t MCOption=0,
							 Int_t pdgMeson=411,
							 TString finDirname="Loose",
							 TString filename="",
							 TString finAnObjname="AnalysisCuts",
							 TString estimatorFilename="",
							 Double_t refMult=9.26,
							 Bool_t subtractDau=kFALSE,
							 Bool_t NchWeight=kFALSE,
							 Int_t recoEstimator = AliAnalysisTaskSEDvsMultiplicity::kNtrk10,
							 Int_t MCEstimator = AliAnalysisTaskSEDvsMultiplicity::kEta10,
							 Bool_t isPPbData=kFALSE)
{
  //
  // Test macro for the AliAnalysisTaskSE for D+ candidates
  //Invariant mass histogram and
  // association with MC truth (using MC info in AOD)
  //  R. Bala, bala@to.infn.it
  // Get the pointer to the existing analysis manager via the static access method.
  //==============================================================================

  AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
  if (!mgr) {
    ::Error("AddTaskDvsMultiplicity", "No analysis manager to connect to.");
  }

  Bool_t stdcuts=kFALSE;
  TFile* filecuts;
  if( filename.EqualTo("") ) {
    stdcuts=kTRUE;
  } else {
    filecuts=TFile::Open(filename.Data());
    if(!filecuts ||(filecuts&& !filecuts->IsOpen())){
      AliFatal("Input file not found : check your cut object");
    }
  }

  //Analysis Task
  AliRDHFCuts *analysiscuts=0x0;

  TString Name="";
  if(pdgMeson==411){
    if(stdcuts) {
      analysiscuts = new AliRDHFCutsDplustoKpipi();
      if (system == 0) analysiscuts->SetStandardCutsPP2010();
      else analysiscuts->SetStandardCutsPbPb2011();
    }
    else analysiscuts = (AliRDHFCutsDplustoKpipi*)filecuts->Get(finAnObjname);
    Name="Dplus";
   }else if(pdgMeson==421){
    if(stdcuts) {
      analysiscuts = new AliRDHFCutsD0toKpi();
      if (system == 0) analysiscuts->SetStandardCutsPP2010();
      else analysiscuts->SetStandardCutsPbPb2011();
    }
    else analysiscuts = (AliRDHFCutsD0toKpi*)filecuts->Get(finAnObjname);
    Name="D0";
  }else if(pdgMeson==413){
    if(stdcuts) {
      analysiscuts = new AliRDHFCutsDStartoKpipi();
      if (system == 0) analysiscuts->SetStandardCutsPP2010();
      else analysiscuts->SetStandardCutsPbPb2011();
    }
    else analysiscuts = (AliRDHFCutsDStartoKpipi*)filecuts->Get(finAnObjname);
    Name="DStar";
  }

  AliAnalysisTaskSEDvsMultiplicity *dMultTask = new AliAnalysisTaskSEDvsMultiplicity("dMultAnalysis",pdgMeson,analysiscuts,isPPbData);
  dMultTask->SetReadMC(readMC);
  dMultTask->SetDebugLevel(0);
  dMultTask->SetUseBit(kTRUE);
  dMultTask->SetDoImpactParameterHistos(kFALSE);
  dMultTask->SetSubtractTrackletsFromDaughters(subtractDau);
  dMultTask->SetMultiplicityEstimator(recoEstimator);
  dMultTask->SetMCPrimariesEstimator(MCEstimator);
  dMultTask->SetMCOption(MCOption);
  if(isPPbData) dMultTask->SetIsPPbData();

  if(NchWeight){
    TH1F *hNchPrimaries = NULL;
    if(isPPbData) hNchPrimaries = (TH1F*)filecuts->Get("hNtrUnCorrEvWithDWeight");
    else hNchPrimaries = (TH1F*)filecuts->Get("hGenPrimaryParticlesInelGt0");
    if(hNchPrimaries) {
      dMultTask->UseMCNchWeight(true);
      dMultTask->SetHistoNchWeight(hNchPrimaries);
    } else {
      AliFatal("Histogram for multiplicity weights not found");
      return 0x0;
    }
  }

  if(pdgMeson==421) {
    dMultTask->SetMassLimits(1.5648,2.1648);
    dMultTask->SetNMassBins(200);
  }else if(pdgMeson==411)dMultTask->SetMassLimits(pdgMeson,0.2);

  if(estimatorFilename.EqualTo("") ) {
    printf("Estimator file not provided, multiplcity corrected histograms will not be filled\n");
  } else{

    TFile* fileEstimator=TFile::Open(estimatorFilename.Data());
    if(!fileEstimator)  {
      AliFatal("File with multiplicity estimator not found\n");
      return;
    }

    dMultTask->SetReferenceMultiplcity(refMult);

    if (isPPbData) {    //Only use two profiles if pPb
      const Char_t* periodNames[2] = {"LHC13b", "LHC13c"};
      TProfile* multEstimatorAvg[2];
      for(Int_t ip=0; ip<2; ip++) {
	multEstimatorAvg[ip] = (TProfile*)(fileEstimator->Get(Form("SPDmult10_%s",periodNames[ip]))->Clone(Form("SPDmult10_%s_clone",periodNames[ip])));
	if (!multEstimatorAvg[ip]) {
	  AliFatal(Form("Multiplicity estimator for %s not found! Please check your estimator file",periodNames[ip]));
	  return;
	}
      }
      dMultTask->SetMultiplVsZProfileLHC13b(multEstimatorAvg[0]);
      dMultTask->SetMultiplVsZProfileLHC13c(multEstimatorAvg[1]);
    }
    else {
      const Char_t* periodNames[4] = {"LHC10b", "LHC10c", "LHC10d", "LHC10e"};
      TProfile* multEstimatorAvg[4];
      for(Int_t ip=0; ip<4; ip++) {
	multEstimatorAvg[ip] = (TProfile*)(fileEstimator->Get(Form("SPDmult10_%s",periodNames[ip]))->Clone(Form("SPDmult10_%s_clone",periodNames[ip])));
	if (!multEstimatorAvg[ip]) {
	  AliFatal(Form("Multiplicity estimator for %s not found! Please check your estimator file",periodNames[ip]));
	  return;
	}
      }
      dMultTask->SetMultiplVsZProfileLHC10b(multEstimatorAvg[0]);
      dMultTask->SetMultiplVsZProfileLHC10c(multEstimatorAvg[1]);
      dMultTask->SetMultiplVsZProfileLHC10d(multEstimatorAvg[2]);
      dMultTask->SetMultiplVsZProfileLHC10e(multEstimatorAvg[3]);
    }
  }
  mgr->AddTask(dMultTask);

  // Create containers for input/output

  TString inname = "cinput";
  TString outname = "coutput";
  TString cutsname = "coutputCuts";
  TString normname = "coutputNorm";
  TString profname = "coutputProf";

  inname += Name.Data();
  outname += Name.Data();
  cutsname += Name.Data();
  normname += Name.Data();
  profname += Name.Data();
  inname += finDirname.Data();
  outname += finDirname.Data();
  cutsname += finDirname.Data();
  normname += finDirname.Data();
  profname += finDirname.Data();

  AliAnalysisDataContainer *cinput = mgr->CreateContainer(inname,TChain::Class(),AliAnalysisManager::kInputContainer);

  TString outputfile = AliAnalysisManager::GetCommonFileName();
  outputfile += ":PWG3_D2H_DMult_";
  outputfile += Name.Data();
  outputfile += finDirname.Data();

  AliAnalysisDataContainer *coutputCuts = mgr->CreateContainer(cutsname,TList::Class(),AliAnalysisManager::kOutputContainer,outputfile.Data());
  AliAnalysisDataContainer *coutput = mgr->CreateContainer(outname,TList::Class(),AliAnalysisManager::kOutputContainer,outputfile.Data());
  AliAnalysisDataContainer *coutputNorm = mgr->CreateContainer(normname,TList::Class(),AliAnalysisManager::kOutputContainer,outputfile.Data());
  AliAnalysisDataContainer *coutputProf = mgr->CreateContainer(profname,TList::Class(),AliAnalysisManager::kOutputContainer,outputfile.Data());

  mgr->ConnectInput(dMultTask,0,mgr->GetCommonInputContainer());

  mgr->ConnectOutput(dMultTask,1,coutput);

  mgr->ConnectOutput(dMultTask,2,coutputCuts);

  mgr->ConnectOutput(dMultTask,3,coutputNorm);

  mgr->ConnectOutput(dMultTask,4,coutputProf);

  return dMultTask;
}
<|endoftext|>


<commit_before>#define DEBUG 1
/**
 * File    : D2.cpp
 * Author  : Kazune Takahashi
 * Created : 11/13/2019, 7:24:07 PM
 * Powered by Visual Studio Code
 */
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <vector>
#include <string>
#include <complex>
#include <tuple>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <bitset>
#include <functional>
#include <random>
#include <chrono>
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <boost/rational.hpp>
using boost::rational;
using namespace std;
template <typename T>
void ch_max(T &left, T right)
{
  if (left < right)
  {
    left = right;
  }
}
template <typename T>
void ch_min(T &left, T right)
{
  if (left > right)
  {
    left = right;
  }
}
using ll = long long;
constexpr ll MOD{1000000007LL};
constexpr ll MAX_SIZE{3000010LL};
template <ll MOD = MOD>
class Mint
{
public:
  ll x;
  Mint() : x{0LL} {}
  Mint(ll x) : x{x % MOD} {}
  Mint operator-() const { return x ? MOD - x : 0; }
  Mint &operator+=(const Mint &a)
  {
    if ((x += a.x) >= MOD)
    {
      x -= MOD;
    }
    return *this;
  }
  Mint &operator-=(const Mint &a) { return *this += -a; }
  Mint &operator*=(const Mint &a)
  {
    (x *= a.x) %= MOD;
    return *this;
  }
  Mint &operator/=(const Mint &a)
  {
    Mint b{a};
    return *this *= b.power(MOD - 2);
  }
  Mint operator+(const Mint &a) const { return Mint(*this) += a; }
  Mint operator-(const Mint &a) const { return Mint(*this) -= a; }
  Mint operator*(const Mint &a) const { return Mint(*this) *= a; }
  Mint operator/(const Mint &a) const { return Mint(*this) /= a; }
  bool operator<(const Mint &a) const { return x < a.x; }
  bool operator==(const Mint &a) const { return x == a.x; }
  const Mint power(ll N)
  {
    if (N == 0)
    {
      return 1;
    }
    else if (N % 2 == 1)
    {
      return *this * power(N - 1);
    }
    else
    {
      Mint half = power(N / 2);
      return half * half;
    }
  }
};
template <ll MOD>
Mint<MOD> operator+(ll lhs, const Mint<MOD> &rhs)
{
  return rhs + lhs;
}
template <ll MOD>
Mint<MOD> operator-(ll lhs, const Mint<MOD> &rhs)
{
  return -rhs + lhs;
}
template <ll MOD>
Mint<MOD> operator*(ll lhs, const Mint<MOD> &rhs)
{
  return rhs * lhs;
}
template <ll MOD>
Mint<MOD> operator/(ll lhs, const Mint<MOD> &rhs)
{
  return Mint<MOD>{lhs} / rhs;
}
template <ll MOD>
istream &operator>>(istream &stream, Mint<MOD> &a)
{
  return stream >> a.x;
}
template <ll MOD>
ostream &operator<<(ostream &stream, const Mint<MOD> &a)
{
  return stream << a.x;
}
template <ll MOD = MOD, ll MAX_SIZE = MAX_SIZE>
class Combination
{
public:
  vector<Mint<MOD>> inv, fact, factinv;
  Combination() : inv(MAX_SIZE), fact(MAX_SIZE), factinv(MAX_SIZE)
  {
    inv[1] = 1;
    for (auto i = 2LL; i < MAX_SIZE; i++)
    {
      inv[i] = (-inv[MOD % i]) * (MOD / i);
    }
    fact[0] = factinv[0] = 1;
    for (auto i = 1LL; i < MAX_SIZE; i++)
    {
      fact[i] = Mint<MOD>(i) * fact[i - 1];
      factinv[i] = inv[i] * factinv[i - 1];
    }
  }
  Mint<MOD> operator()(int n, int k)
  {
    if (n >= 0 && k >= 0 && n - k >= 0)
    {
      return fact[n] * factinv[k] * factinv[n - k];
    }
    return 0;
  }
  Mint<MOD> catalan(int x, int y)
  {
    return (*this)(x + y, y) - (*this)(x + y, y - 1);
  }
};
// for C++14
using mint = Mint<MOD>;
using combination = Combination<MOD, MAX_SIZE>;
ll gcd(ll x, ll y) { return y ? gcd(y, x % y) : x; }
// constexpr double epsilon{1e-10};
// constexpr ll infty{1000000000000000LL};
// constexpr int dx[4] = {1, 0, -1, 0};
// constexpr int dy[4] = {0, 1, 0, -1};
void Yes()
{
  cout << "Yes" << endl;
  exit(0);
}
void No()
{
  cout << "0 1" << endl;
  exit(0);
}

using Info = tuple<ll, ll>;

int main()
{
  int N;
  cin >> N;
  vector<Info> V(N);
  ll A_sum{0LL};
  for (auto i = 0; i < N; i++)
  {
    ll A, B;
    cin >> A >> B;
    V[i] = Info(max(A, B), B);
    A_sum += A;
  }
  sort(V.rbegin(), V.rend());
  vector<ll> C_sum(N + 1);
  C_sum[0] = 0;
  for (auto i = 0; i < N; i++)
  {
#if DEBUG == 1
    cerr << "C_sum[" << i + 1 << " = " << C_sum[i + 1] << endl;
#endif
    C_sum[i + 1] = C_sum[i] + get<0>(V[i]);
  }
  if (C_sum[N] == A_sum)
  {
    No();
  }
  rational<ll> ans{0, 1};
#if DEBUG == 1
  cerr << "A_sum = " << A_sum << endl;
#endif
  for (auto k = 0; k < N; k++)
  {
    ll B_k{get<1>(V[k])};
    ll ok{N}, ng{-1};
    ll tmp_sum{0};
    bool included{false};
    while (abs(ok - ng) > 1)
    {
      ll t{(ok + ng) / 2};
      ll tmp{C_sum[t]};
      if (k < t)
      {
        tmp -= B_k;
      }
      if (tmp + B_k >= A_sum)
      {
        ok = t;
        included = k < t;
        tmp_sum = tmp;
      }
      else
      {
        ng = t;
      }
    }
    rational<ll> r{A_sum - tmp_sum, B_k};
#if DEBUG == 1
    cerr << "k = " << k << ", B_k = " << B_k << ", tmp_sum = " << tmp_sum << ", r = " << r << endl;
#endif
    ll M{included ? ok - 1 : ok};
#if DEBUG == 1
    cerr << "ok = " << ok << ", included = " << included << ", M = " << M << ", r = " << r << endl;
#endif
    rational<ll> tmp_ans = (N - M - r) / N;
#if DEBUG == 1
    cerr << "tmp_ans = " << tmp_ans << endl;
#endif
    if (r < 0)
    {
      continue;
    }
    ch_max(ans, tmp_ans);
  }
  cout << ans.numerator() << " " << ans.denominator() << endl;
}
<commit_msg>tried D2.cpp to 'D'<commit_after>#define DEBUG 1
/**
 * File    : D2.cpp
 * Author  : Kazune Takahashi
 * Created : 11/13/2019, 7:24:07 PM
 * Powered by Visual Studio Code
 */
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <vector>
#include <string>
#include <complex>
#include <tuple>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <bitset>
#include <functional>
#include <random>
#include <chrono>
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <boost/rational.hpp>
using boost::rational;
using namespace std;
template <typename T>
void ch_max(T &left, T right)
{
  if (left < right)
  {
    left = right;
  }
}
template <typename T>
void ch_min(T &left, T right)
{
  if (left > right)
  {
    left = right;
  }
}
using ll = long long;
constexpr ll MOD{1000000007LL};
constexpr ll MAX_SIZE{3000010LL};
template <ll MOD = MOD>
class Mint
{
public:
  ll x;
  Mint() : x{0LL} {}
  Mint(ll x) : x{x % MOD} {}
  Mint operator-() const { return x ? MOD - x : 0; }
  Mint &operator+=(const Mint &a)
  {
    if ((x += a.x) >= MOD)
    {
      x -= MOD;
    }
    return *this;
  }
  Mint &operator-=(const Mint &a) { return *this += -a; }
  Mint &operator*=(const Mint &a)
  {
    (x *= a.x) %= MOD;
    return *this;
  }
  Mint &operator/=(const Mint &a)
  {
    Mint b{a};
    return *this *= b.power(MOD - 2);
  }
  Mint operator+(const Mint &a) const { return Mint(*this) += a; }
  Mint operator-(const Mint &a) const { return Mint(*this) -= a; }
  Mint operator*(const Mint &a) const { return Mint(*this) *= a; }
  Mint operator/(const Mint &a) const { return Mint(*this) /= a; }
  bool operator<(const Mint &a) const { return x < a.x; }
  bool operator==(const Mint &a) const { return x == a.x; }
  const Mint power(ll N)
  {
    if (N == 0)
    {
      return 1;
    }
    else if (N % 2 == 1)
    {
      return *this * power(N - 1);
    }
    else
    {
      Mint half = power(N / 2);
      return half * half;
    }
  }
};
template <ll MOD>
Mint<MOD> operator+(ll lhs, const Mint<MOD> &rhs)
{
  return rhs + lhs;
}
template <ll MOD>
Mint<MOD> operator-(ll lhs, const Mint<MOD> &rhs)
{
  return -rhs + lhs;
}
template <ll MOD>
Mint<MOD> operator*(ll lhs, const Mint<MOD> &rhs)
{
  return rhs * lhs;
}
template <ll MOD>
Mint<MOD> operator/(ll lhs, const Mint<MOD> &rhs)
{
  return Mint<MOD>{lhs} / rhs;
}
template <ll MOD>
istream &operator>>(istream &stream, Mint<MOD> &a)
{
  return stream >> a.x;
}
template <ll MOD>
ostream &operator<<(ostream &stream, const Mint<MOD> &a)
{
  return stream << a.x;
}
template <ll MOD = MOD, ll MAX_SIZE = MAX_SIZE>
class Combination
{
public:
  vector<Mint<MOD>> inv, fact, factinv;
  Combination() : inv(MAX_SIZE), fact(MAX_SIZE), factinv(MAX_SIZE)
  {
    inv[1] = 1;
    for (auto i = 2LL; i < MAX_SIZE; i++)
    {
      inv[i] = (-inv[MOD % i]) * (MOD / i);
    }
    fact[0] = factinv[0] = 1;
    for (auto i = 1LL; i < MAX_SIZE; i++)
    {
      fact[i] = Mint<MOD>(i) * fact[i - 1];
      factinv[i] = inv[i] * factinv[i - 1];
    }
  }
  Mint<MOD> operator()(int n, int k)
  {
    if (n >= 0 && k >= 0 && n - k >= 0)
    {
      return fact[n] * factinv[k] * factinv[n - k];
    }
    return 0;
  }
  Mint<MOD> catalan(int x, int y)
  {
    return (*this)(x + y, y) - (*this)(x + y, y - 1);
  }
};
// for C++14
using mint = Mint<MOD>;
using combination = Combination<MOD, MAX_SIZE>;
ll gcd(ll x, ll y) { return y ? gcd(y, x % y) : x; }
// constexpr double epsilon{1e-10};
// constexpr ll infty{1000000000000000LL};
// constexpr int dx[4] = {1, 0, -1, 0};
// constexpr int dy[4] = {0, 1, 0, -1};
void Yes()
{
  cout << "Yes" << endl;
  exit(0);
}
void No()
{
  cout << "0 1" << endl;
  exit(0);
}

using Info = tuple<ll, ll>;

int main()
{
  int N;
  cin >> N;
  vector<Info> V(N);
  ll A_sum{0LL};
  for (auto i = 0; i < N; i++)
  {
    ll A, B;
    cin >> A >> B;
    V[i] = Info(max(A, B), B);
    A_sum += A;
  }
  sort(V.rbegin(), V.rend());
  vector<ll> C_sum(N + 1);
  C_sum[0] = 0;
  for (auto i = 0; i < N; i++)
  {
    C_sum[i + 1] = C_sum[i] + get<0>(V[i]);
#if DEBUG == 1
    cerr << "C_sum[" << i + 1 << "] = " << C_sum[i + 1] << endl;
#endif
  }
  if (C_sum[N] == A_sum)
  {
    No();
  }
  rational<ll> ans{0, 1};
#if DEBUG == 1
  cerr << "A_sum = " << A_sum << endl;
#endif
  for (auto k = 0; k < N; k++)
  {
    ll B_k{get<1>(V[k])};
    ll ok{N}, ng{-1};
    ll tmp_sum{0};
    bool included{false};
    while (abs(ok - ng) > 1)
    {
      ll t{(ok + ng) / 2};
      ll tmp{C_sum[t]};
      if (k < t)
      {
        tmp -= B_k;
      }
      if (tmp + B_k >= A_sum)
      {
        ok = t;
        included = k < t;
        tmp_sum = tmp;
      }
      else
      {
        ng = t;
      }
    }
    rational<ll> r{A_sum - tmp_sum, B_k};
#if DEBUG == 1
    cerr << "k = " << k << ", B_k = " << B_k << ", tmp_sum = " << tmp_sum << ", r = " << r << endl;
#endif
    ll M{included ? ok - 1 : ok};
#if DEBUG == 1
    cerr << "ok = " << ok << ", included = " << included << ", M = " << M << ", r = " << r << endl;
#endif
    rational<ll> tmp_ans = (N - M - r) / N;
#if DEBUG == 1
    cerr << "tmp_ans = " << tmp_ans << endl;
#endif
    if (r < 0)
    {
      continue;
    }
    ch_max(ans, tmp_ans);
  }
  cout << ans.numerator() << " " << ans.denominator() << endl;
}
<|endoftext|>


<commit_before>#include "stdafx.h"
#include <exdisp.h>
#include <comdef.h>
#include "ControlEx.h"

class C360SafeFrameWnd : public CWindowWnd, public INotifyUI
{
public:
	C360SafeFrameWnd() { };
	LPCTSTR GetWindowClassName() const { return _T("UIMainFrame"); };
	UINT GetClassStyle() const { return CS_DBLCLKS; };
	void OnFinalMessage(HWND /*hWnd*/) { delete this; };

	void Init() {
		m_pCloseBtn = static_cast<CButtonUI*>(m_pm.FindControl(_T("closebtn")));
		m_pMaxBtn = static_cast<CButtonUI*>(m_pm.FindControl(_T("maxbtn")));
		m_pRestoreBtn = static_cast<CButtonUI*>(m_pm.FindControl(_T("restorebtn")));
		m_pMinBtn = static_cast<CButtonUI*>(m_pm.FindControl(_T("minbtn")));
	}

	void OnPrepare() {
	}

	void Notify(TNotifyUI& msg)
	{
		if( msg.sType == _T("windowinit") ) OnPrepare();
		else if( msg.sType == _T("click") ) {
			if( msg.pSender == m_pCloseBtn ) {
				PostQuitMessage(0);
				return;
			}
			else if( msg.pSender == m_pMinBtn ) {
				SendMessage(WM_SYSCOMMAND, SC_MINIMIZE, 0); return; }
			else if( msg.pSender == m_pMaxBtn ) {
				SendMessage(WM_SYSCOMMAND, SC_MAXIMIZE, 0); return; }
			else if( msg.pSender == m_pRestoreBtn ) {
				SendMessage(WM_SYSCOMMAND, SC_RESTORE, 0); return; }
		}
		else if(msg.sType==_T("selectchanged"))
		{
			CStdString name = msg.pSender->GetName();
			CTabLayoutUI* pControl = static_cast<CTabLayoutUI*>(m_pm.FindControl(_T("switch")));
			if(name==_T("examine"))
				 pControl->SelectItem(0);
			else if(name==_T("trojan"))
				 pControl->SelectItem(1);
			else if(name==_T("plugins"))
				pControl->SelectItem(2);
			else if(name==_T("vulnerability"))
				pControl->SelectItem(3);
			else if(name==_T("rubbish"))
				pControl->SelectItem(4);
			else if(name==_T("cleanup"))
				pControl->SelectItem(5);
			else if(name==_T("fix"))
				pControl->SelectItem(6);
			else if(name==_T("tool"))
				pControl->SelectItem(7);
		}
	}

	LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		LONG styleValue = ::GetWindowLong(*this, GWL_STYLE);
		styleValue &= ~WS_CAPTION;
		::SetWindowLong(*this, GWL_STYLE, styleValue | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);

		m_pm.Init(m_hWnd);
		CDialogBuilder builder;
		CDialogBuilderCallbackEx cb;
		CControlUI* pRoot = builder.Create(_T("skin.xml"), (UINT)0,  &cb, &m_pm);
		ASSERT(pRoot && "Failed to parse XML");
		m_pm.AttachDialog(pRoot);
		m_pm.AddNotifier(this);

		Init();
		return 0;
	}

	LRESULT OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		bHandled = FALSE;
		return 0;
	}

	LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		::PostQuitMessage(0L);

		bHandled = FALSE;
		return 0;
	}

	LRESULT OnNcActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
        if( ::IsIconic(*this) ) bHandled = FALSE;
        return (wParam == 0) ? TRUE : FALSE;
	}

	LRESULT OnNcCalcSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		return 0;
	}

	LRESULT OnNcPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		return 0;
	}

	LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		POINT pt; pt.x = GET_X_LPARAM(lParam); pt.y = GET_Y_LPARAM(lParam);
		::ScreenToClient(*this, &pt);

		RECT rcClient;
		::GetClientRect(*this, &rcClient);

// 		if( !::IsZoomed(*this) ) {
// 			RECT rcSizeBox = m_pm.GetSizeBox();
// 			if( pt.y < rcClient.top + rcSizeBox.top ) {
// 				if( pt.x < rcClient.left + rcSizeBox.left ) return HTTOPLEFT;
// 				if( pt.x > rcClient.right - rcSizeBox.right ) return HTTOPRIGHT;
// 				return HTTOP;
// 			}
// 			else if( pt.y > rcClient.bottom - rcSizeBox.bottom ) {
// 				if( pt.x < rcClient.left + rcSizeBox.left ) return HTBOTTOMLEFT;
// 				if( pt.x > rcClient.right - rcSizeBox.right ) return HTBOTTOMRIGHT;
// 				return HTBOTTOM;
// 			}
// 			if( pt.x < rcClient.left + rcSizeBox.left ) return HTLEFT;
// 			if( pt.x > rcClient.right - rcSizeBox.right ) return HTRIGHT;
// 		}

		RECT rcCaption = m_pm.GetCaptionRect();
		if( pt.x >= rcClient.left + rcCaption.left && pt.x < rcClient.right - rcCaption.right \
			&& pt.y >= rcCaption.top && pt.y < rcCaption.bottom ) {
				CControlUI* pControl = static_cast<CControlUI*>(m_pm.FindControl(pt));
				if( pControl && _tcscmp(pControl->GetClass(), _T("ButtonUI")) != 0 &&
					_tcscmp(pControl->GetClass(), _T("OptionUI")) != 0 &&
					_tcscmp(pControl->GetClass(), _T("TextUI")) != 0 )
					return HTCAPTION;
		}

		return HTCLIENT;
	}

	LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
        SIZE szRoundCorner = m_pm.GetRoundCorner();
        if( !::IsIconic(*this) && (szRoundCorner.cx != 0 || szRoundCorner.cy != 0) ) {
            CRect rcWnd;
            ::GetWindowRect(*this, &rcWnd);
            rcWnd.Offset(-rcWnd.left, -rcWnd.top);
            rcWnd.right++; rcWnd.bottom++;
            HRGN hRgn = ::CreateRoundRectRgn(rcWnd.left, rcWnd.top, rcWnd.right, rcWnd.bottom, szRoundCorner.cx, szRoundCorner.cy);
            ::SetWindowRgn(*this, hRgn, TRUE);
            ::DeleteObject(hRgn);
        }

        bHandled = FALSE;
        return 0;
	}

	LRESULT OnGetMinMaxInfo(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		MONITORINFO oMonitor = {};
		oMonitor.cbSize = sizeof(oMonitor);
		::GetMonitorInfo(::MonitorFromWindow(*this, MONITOR_DEFAULTTOPRIMARY), &oMonitor);
		CRect rcWork = oMonitor.rcWork;
		rcWork.Offset(-rcWork.left, -rcWork.top);

		LPMINMAXINFO lpMMI = (LPMINMAXINFO) lParam;
		lpMMI->ptMaxPosition.x	= rcWork.left;
		lpMMI->ptMaxPosition.y	= rcWork.top;
		lpMMI->ptMaxSize.x		= rcWork.right;
		lpMMI->ptMaxSize.y		= rcWork.bottom;

		bHandled = FALSE;
		return 0;
	}

	LRESULT OnSysCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		// ʱյWM_NCDESTROYյwParamΪSC_CLOSEWM_SYSCOMMAND
		if( wParam == SC_CLOSE ) {
			::PostQuitMessage(0L);
			bHandled = TRUE;
			return 0;
		}
		BOOL bZoomed = ::IsZoomed(*this);
		LRESULT lRes = CWindowWnd::HandleMessage(uMsg, wParam, lParam);
		if( ::IsZoomed(*this) != bZoomed ) {
			if( !bZoomed ) {
				CControlUI* pControl = static_cast<CControlUI*>(m_pm.FindControl(_T("maxbtn")));
				if( pControl ) pControl->SetVisible(false);
				pControl = static_cast<CControlUI*>(m_pm.FindControl(_T("restorebtn")));
				if( pControl ) pControl->SetVisible(true);
			}
			else {
				CControlUI* pControl = static_cast<CControlUI*>(m_pm.FindControl(_T("maxbtn")));
				if( pControl ) pControl->SetVisible(true);
				pControl = static_cast<CControlUI*>(m_pm.FindControl(_T("restorebtn")));
				if( pControl ) pControl->SetVisible(false);
			}
		}
		return lRes;
	}

	LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
	{
		LRESULT lRes = 0;
		BOOL bHandled = TRUE;
		switch( uMsg ) {
		case WM_CREATE:        lRes = OnCreate(uMsg, wParam, lParam, bHandled); break;
		case WM_CLOSE:         lRes = OnClose(uMsg, wParam, lParam, bHandled); break;
		case WM_DESTROY:       lRes = OnDestroy(uMsg, wParam, lParam, bHandled); break;
		case WM_NCACTIVATE:    lRes = OnNcActivate(uMsg, wParam, lParam, bHandled); break;
		case WM_NCCALCSIZE:    lRes = OnNcCalcSize(uMsg, wParam, lParam, bHandled); break;
		case WM_NCPAINT:       lRes = OnNcPaint(uMsg, wParam, lParam, bHandled); break;
		case WM_NCHITTEST:     lRes = OnNcHitTest(uMsg, wParam, lParam, bHandled); break;
		case WM_SIZE:          lRes = OnSize(uMsg, wParam, lParam, bHandled); break;
		case WM_GETMINMAXINFO: lRes = OnGetMinMaxInfo(uMsg, wParam, lParam, bHandled); break;
		case WM_SYSCOMMAND:    lRes = OnSysCommand(uMsg, wParam, lParam, bHandled); break;
		default:
		bHandled = FALSE;
		}
		if( bHandled ) return lRes;
		if( m_pm.MessageHandler(uMsg, wParam, lParam, lRes) ) return lRes;
		return CWindowWnd::HandleMessage(uMsg, wParam, lParam);
	}

public:
	CPaintManagerUI m_pm;

private:
	CButtonUI* m_pCloseBtn;
	CButtonUI* m_pMaxBtn;
	CButtonUI* m_pRestoreBtn;
	CButtonUI* m_pMinBtn;
	//...
};

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, int nCmdShow)
{
	CPaintManagerUI::SetInstance(hInstance);
	CPaintManagerUI::SetResourcePath(CPaintManagerUI::GetInstancePath() + _T("skin"));
	CPaintManagerUI::SetResourceZip(_T("360SafeRes.zip"));

	HRESULT Hr = ::CoInitialize(NULL);
	if( FAILED(Hr) ) return 0;

	C360SafeFrameWnd* pFrame = new C360SafeFrameWnd();
	if( pFrame == NULL ) return 0;
	pFrame->Create(NULL, _T("360ȫʿ"), UI_WNDSTYLE_FRAME, 0L, 0, 0, 800, 572);
	pFrame->CenterWindow();
	::ShowWindow(*pFrame, SW_SHOW);

	CPaintManagerUI::MessageLoop();

	::CoUninitialize();
	return 0;
}<commit_msg>fix.<commit_after>#include "stdafx.h"
#include <exdisp.h>
#include <comdef.h>
#include "ControlEx.h"

class C360SafeFrameWnd : public CWindowWnd, public INotifyUI
{
public:
	C360SafeFrameWnd() { };
	LPCTSTR GetWindowClassName() const { return _T("UIMainFrame"); };
	UINT GetClassStyle() const { return CS_DBLCLKS; };
	void OnFinalMessage(HWND /*hWnd*/) { delete this; };

	void Init() {
		m_pCloseBtn = static_cast<CButtonUI*>(m_pm.FindControl(_T("closebtn")));
		m_pMaxBtn = static_cast<CButtonUI*>(m_pm.FindControl(_T("maxbtn")));
		m_pRestoreBtn = static_cast<CButtonUI*>(m_pm.FindControl(_T("restorebtn")));
		m_pMinBtn = static_cast<CButtonUI*>(m_pm.FindControl(_T("minbtn")));
	}

	void OnPrepare() {
	}

	void Notify(TNotifyUI& msg)
	{
		if( msg.sType == _T("windowinit") ) OnPrepare();
		else if( msg.sType == _T("click") ) {
			if( msg.pSender == m_pCloseBtn ) {
				PostMessage(WM_SYSCOMMAND, SC_CLOSE, 0); return; }
			else if( msg.pSender == m_pMinBtn ) {
				SendMessage(WM_SYSCOMMAND, SC_MINIMIZE, 0); return; }
			else if( msg.pSender == m_pMaxBtn ) {
				SendMessage(WM_SYSCOMMAND, SC_MAXIMIZE, 0); return; }
			else if( msg.pSender == m_pRestoreBtn ) {
				SendMessage(WM_SYSCOMMAND, SC_RESTORE, 0); return; }
		}
		else if(msg.sType==_T("selectchanged"))
		{
			CStdString name = msg.pSender->GetName();
			CTabLayoutUI* pControl = static_cast<CTabLayoutUI*>(m_pm.FindControl(_T("switch")));
			if(name==_T("examine"))
				 pControl->SelectItem(0);
			else if(name==_T("trojan"))
				 pControl->SelectItem(1);
			else if(name==_T("plugins"))
				pControl->SelectItem(2);
			else if(name==_T("vulnerability"))
				pControl->SelectItem(3);
			else if(name==_T("rubbish"))
				pControl->SelectItem(4);
			else if(name==_T("cleanup"))
				pControl->SelectItem(5);
			else if(name==_T("fix"))
				pControl->SelectItem(6);
			else if(name==_T("tool"))
				pControl->SelectItem(7);
		}
	}

	LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		LONG styleValue = ::GetWindowLong(*this, GWL_STYLE);
		styleValue &= ~WS_CAPTION;
		::SetWindowLong(*this, GWL_STYLE, styleValue | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);

		m_pm.Init(m_hWnd);
		CDialogBuilder builder;
		CDialogBuilderCallbackEx cb;
		CControlUI* pRoot = builder.Create(_T("skin.xml"), (UINT)0,  &cb, &m_pm);
		ASSERT(pRoot && "Failed to parse XML");
		m_pm.AttachDialog(pRoot);
		m_pm.AddNotifier(this);

		Init();
		return 0;
	}

	LRESULT OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		bHandled = FALSE;
		return 0;
	}

	LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
 		::PostQuitMessage(0L);

		bHandled = FALSE;
		return 0;
	}

	LRESULT OnNcActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
        if( ::IsIconic(*this) ) bHandled = FALSE;
        return (wParam == 0) ? TRUE : FALSE;
	}

	LRESULT OnNcCalcSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		return 0;
	}

	LRESULT OnNcPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		return 0;
	}

	LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		POINT pt; pt.x = GET_X_LPARAM(lParam); pt.y = GET_Y_LPARAM(lParam);
		::ScreenToClient(*this, &pt);

		RECT rcClient;
		::GetClientRect(*this, &rcClient);

// 		if( !::IsZoomed(*this) ) {
// 			RECT rcSizeBox = m_pm.GetSizeBox();
// 			if( pt.y < rcClient.top + rcSizeBox.top ) {
// 				if( pt.x < rcClient.left + rcSizeBox.left ) return HTTOPLEFT;
// 				if( pt.x > rcClient.right - rcSizeBox.right ) return HTTOPRIGHT;
// 				return HTTOP;
// 			}
// 			else if( pt.y > rcClient.bottom - rcSizeBox.bottom ) {
// 				if( pt.x < rcClient.left + rcSizeBox.left ) return HTBOTTOMLEFT;
// 				if( pt.x > rcClient.right - rcSizeBox.right ) return HTBOTTOMRIGHT;
// 				return HTBOTTOM;
// 			}
// 			if( pt.x < rcClient.left + rcSizeBox.left ) return HTLEFT;
// 			if( pt.x > rcClient.right - rcSizeBox.right ) return HTRIGHT;
// 		}

		RECT rcCaption = m_pm.GetCaptionRect();
		if( pt.x >= rcClient.left + rcCaption.left && pt.x < rcClient.right - rcCaption.right \
			&& pt.y >= rcCaption.top && pt.y < rcCaption.bottom ) {
				CControlUI* pControl = static_cast<CControlUI*>(m_pm.FindControl(pt));
				if( pControl && _tcscmp(pControl->GetClass(), _T("ButtonUI")) != 0 &&
					_tcscmp(pControl->GetClass(), _T("OptionUI")) != 0 &&
					_tcscmp(pControl->GetClass(), _T("TextUI")) != 0 )
					return HTCAPTION;
		}

		return HTCLIENT;
	}

	LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
        SIZE szRoundCorner = m_pm.GetRoundCorner();
        if( !::IsIconic(*this) && (szRoundCorner.cx != 0 || szRoundCorner.cy != 0) ) {
            CRect rcWnd;
            ::GetWindowRect(*this, &rcWnd);
            rcWnd.Offset(-rcWnd.left, -rcWnd.top);
            rcWnd.right++; rcWnd.bottom++;
            HRGN hRgn = ::CreateRoundRectRgn(rcWnd.left, rcWnd.top, rcWnd.right, rcWnd.bottom, szRoundCorner.cx, szRoundCorner.cy);
            ::SetWindowRgn(*this, hRgn, TRUE);
            ::DeleteObject(hRgn);
        }

        bHandled = FALSE;
        return 0;
	}

	LRESULT OnGetMinMaxInfo(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		MONITORINFO oMonitor = {};
		oMonitor.cbSize = sizeof(oMonitor);
		::GetMonitorInfo(::MonitorFromWindow(*this, MONITOR_DEFAULTTOPRIMARY), &oMonitor);
		CRect rcWork = oMonitor.rcWork;
		rcWork.Offset(-rcWork.left, -rcWork.top);

		LPMINMAXINFO lpMMI = (LPMINMAXINFO) lParam;
		lpMMI->ptMaxPosition.x	= rcWork.left;
		lpMMI->ptMaxPosition.y	= rcWork.top;
		lpMMI->ptMaxSize.x		= rcWork.right;
		lpMMI->ptMaxSize.y		= rcWork.bottom;

		bHandled = FALSE;
		return 0;
	}

	LRESULT OnSysCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		BOOL bZoomed = ::IsZoomed(*this);
		LRESULT lRes = CWindowWnd::HandleMessage(uMsg, wParam, lParam);
		if( ::IsZoomed(*this) != bZoomed ) {
			if( !bZoomed ) {
				CControlUI* pControl = static_cast<CControlUI*>(m_pm.FindControl(_T("maxbtn")));
				if( pControl ) pControl->SetVisible(false);
				pControl = static_cast<CControlUI*>(m_pm.FindControl(_T("restorebtn")));
				if( pControl ) pControl->SetVisible(true);
			}
			else {
				CControlUI* pControl = static_cast<CControlUI*>(m_pm.FindControl(_T("maxbtn")));
				if( pControl ) pControl->SetVisible(true);
				pControl = static_cast<CControlUI*>(m_pm.FindControl(_T("restorebtn")));
				if( pControl ) pControl->SetVisible(false);
			}
		}
		return lRes;
	}

	LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
	{
		LRESULT lRes = 0;
		BOOL bHandled = TRUE;
		switch( uMsg ) {
		case WM_CREATE:        lRes = OnCreate(uMsg, wParam, lParam, bHandled); break;
		case WM_CLOSE:         lRes = OnClose(uMsg, wParam, lParam, bHandled); break;
		case WM_DESTROY:       lRes = OnDestroy(uMsg, wParam, lParam, bHandled); break;
		case WM_NCACTIVATE:    lRes = OnNcActivate(uMsg, wParam, lParam, bHandled); break;
		case WM_NCCALCSIZE:    lRes = OnNcCalcSize(uMsg, wParam, lParam, bHandled); break;
		case WM_NCPAINT:       lRes = OnNcPaint(uMsg, wParam, lParam, bHandled); break;
		case WM_NCHITTEST:     lRes = OnNcHitTest(uMsg, wParam, lParam, bHandled); break;
		case WM_SIZE:          lRes = OnSize(uMsg, wParam, lParam, bHandled); break;
		case WM_GETMINMAXINFO: lRes = OnGetMinMaxInfo(uMsg, wParam, lParam, bHandled); break;
		case WM_SYSCOMMAND:    lRes = OnSysCommand(uMsg, wParam, lParam, bHandled); break;
		default:
		bHandled = FALSE;
		}
		if( bHandled ) return lRes;
		if( m_pm.MessageHandler(uMsg, wParam, lParam, lRes) ) return lRes;
		return CWindowWnd::HandleMessage(uMsg, wParam, lParam);
	}

public:
	CPaintManagerUI m_pm;

private:
	CButtonUI* m_pCloseBtn;
	CButtonUI* m_pMaxBtn;
	CButtonUI* m_pRestoreBtn;
	CButtonUI* m_pMinBtn;
	//...
};

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, int nCmdShow)
{
	CPaintManagerUI::SetInstance(hInstance);
	CPaintManagerUI::SetResourcePath(CPaintManagerUI::GetInstancePath() + _T("skin"));
	CPaintManagerUI::SetResourceZip(_T("360SafeRes.zip"));

	HRESULT Hr = ::CoInitialize(NULL);
	if( FAILED(Hr) ) return 0;

	C360SafeFrameWnd* pFrame = new C360SafeFrameWnd();
	if( pFrame == NULL ) return 0;
	pFrame->Create(NULL, _T("360ȫʿ"), UI_WNDSTYLE_FRAME, 0L, 0, 0, 800, 572);
	pFrame->CenterWindow();
	::ShowWindow(*pFrame, SW_SHOW);

	CPaintManagerUI::MessageLoop();

	::CoUninitialize();
	return 0;
}<|endoftext|>


<commit_before>#ifndef STAN_MATH_PRIM_FUN_GRAD_PFQ_HPP
#define STAN_MATH_PRIM_FUN_GRAD_PFQ_HPP

#include <stan/math/prim/meta.hpp>
#include <stan/math/prim/err.hpp>
#include <stan/math/prim/fun/constants.hpp>
#include <stan/math/prim/fun/exp.hpp>
#include <stan/math/prim/fun/log.hpp>
#include <stan/math/prim/fun/log_rising_factorial.hpp>
#include <stan/math/prim/fun/hypergeometric_pFq.hpp>
#include <stan/math/prim/fun/max.hpp>
#include <stan/math/prim/fun/log_sum_exp.hpp>
#include <cmath>

namespace stan {
namespace math {
namespace internal {

/**
 * Returns the gradient of generalised hypergeometric function wrt to the
 * input arguments:
 * \f$ _pF_q(a_1,...,a_p;b_1,...,b_q;z) \f$
 *
 * The derivatives wrt a and b are defined using a Kampé de Fériet function,
 *   (https://en.wikipedia.org/wiki/Kamp%C3%A9_de_F%C3%A9riet_function).
 *   This is implemented below as an infinite sum (on the log scale) until
 *   convergence.
 *
 * \f$ \frac{\partial}{\partial a_1} =
 *     \frac{z\prod_{j=2}^pa_j}{\prod_{j=1}^qb_j}
 *     F_{q+1\:0\;1}^{p\:1\:2}\left(\begin{array}&a_1+1,...,a_p+1;1;1,a_1\\
 *        2, b_1+1,...,b_1+1;;a_1+1\end{array};z,z\right) \f$
 *
 * \f$ \frac{\partial}{\partial b_1}=
 *     -\frac{z\prod_{j=1}^pa_j}{b_1\prod_{j=1}^qb_j}
 *     F_{q+1\:0\;1}^{p\:1\:2}\left(\begin{array}&a_1+1,...,a_p+1;1;1,b_1\\
 *        2, b_1+1,...,b_1+1;;b_1+1\end{array};z,z\right) \f$
 *
 * \f$ \frac{\partial}{\partial z}= \frac{\prod_{j=1}^pa_j}{\prod_{j=1}^qb_j}
 *      {}_pF_q(a_1 + 1,...,a_p + 1; b_1 +1,...,b_q+1;z) \f$
 *
 * @tparam calc_a Boolean for whether to calculate derivatives wrt to 'a'
 * @tparam calc_b Boolean for whether to calculate derivatives wrt to 'b'
 * @tparam calc_z Boolean for whether to calculate derivatives wrt to 'z'
 * @tparam TupleT Type of tuple containing objects to evaluate gradients into
 * @tparam Ta Eigen type with either one row or column at compile time
 * @tparam Tb Eigen type with either one row or column at compile time
 * @tparam Tz Scalar type
 * @param[in] grad_tuple Tuple of references to evaluate gradients into
 * @param[in] a Vector of 'a' arguments to function
 * @param[in] b Vector of 'b' arguments to function
 * @param[in] z Scalar z argument
 * @param[in] precision Convergence criteria for infinite sum
 * @param[in] max_steps Maximum number of iterations for infinite sum
 * @return Generalised hypergeometric function
 */
template <bool calc_a, bool calc_b, bool calc_z, typename TupleT, typename Ta,
          typename Tb, typename Tz,
          require_all_eigen_vector_t<Ta, Tb>* = nullptr,
          require_stan_scalar_t<Tz>* = nullptr>
void grad_pFq_impl(TupleT&& grad_tuple, const Ta& a, const Tb& b, const Tz& z,
                   double precision, int max_steps) {
  using std::max;
  using scalar_t = return_type_t<Ta, Tb, Tz>;
  using Ta_plain = plain_type_t<Ta>;
  using Tb_plain = plain_type_t<Tb>;
  using T_vec = Eigen::Matrix<scalar_t, -1, 1>;

  Ta_plain ap1 = (a.array() + 1).matrix();
  Tb_plain bp1 = (b.array() + 1).matrix();
  Ta_plain log_a = log(a);
  Tb_plain log_b = log(b);
  scalar_type_t<Tz> log_z = log(z);
  scalar_type_t<Ta> sum_log_a = sum(log_a);
  scalar_type_t<Tb> sum_log_b = sum(log_b);

  // Declare vectors to accumulate sums into
  // where NEGATIVE_INFTY is zero on the log scale
  T_vec da_infsum = T_vec::Constant(a.size(), NEGATIVE_INFTY);
  T_vec db_infsum = T_vec::Constant(b.size(), NEGATIVE_INFTY);
  // Vectors to accumulate outer sum into
  T_vec da_iter_m = T_vec::Constant(a.size(), NEGATIVE_INFTY);
  T_vec da_mn = T_vec::Constant(a.size(), NEGATIVE_INFTY);
  T_vec db_iter_m = T_vec::Constant(b.size(), NEGATIVE_INFTY);
  T_vec db_mn = T_vec::Constant(b.size(), NEGATIVE_INFTY);

  // Only need the infinite sum for partials wrt p & b
  if (calc_a || calc_b) {
    double log_precision = log(precision);

    int m = 0;
    scalar_t outer_diff = 0;

    da_infsum.setConstant(NEGATIVE_INFTY);
    db_infsum.setConstant(NEGATIVE_INFTY);

    while ((outer_diff > log_precision) && (m < max_steps)) {
      // Vectors to accumulate outer sum into
      da_iter_m.setConstant(NEGATIVE_INFTY);
      da_mn.setConstant(NEGATIVE_INFTY);
      db_iter_m.setConstant(NEGATIVE_INFTY);
      db_mn.setConstant(NEGATIVE_INFTY);

      double log_phammer_1m = log_rising_factorial(1, m);
      double lgamma_mp1 = lgamma(m + 1);

      int n = 0;
      scalar_t inner_diff = 0;

      while ((inner_diff > log_precision) & (n < max_steps)) {
        // Numerator term
        scalar_t term1_mn = (m + n) * log_z
                            + sum(log_rising_factorial(ap1, m + n))
                            + log_phammer_1m + log_rising_factorial(1, n);
        // Denominator term
        scalar_t term2_mn = lgamma_mp1 + lgamma(n + 1)
                            + sum(log_rising_factorial(bp1, m + n))
                            + log_rising_factorial(2, m + n);
        if (calc_a) {
          // Division (on log scale) for the a & b partials
          da_mn = (term1_mn + log_rising_factorial(a, n).array())
                  - (term2_mn + log_rising_factorial(ap1, n).array());

          // Perform a row-wise log_sum_exp to accumulate current iteration
          da_iter_m = da_iter_m.binaryExpr(
              da_mn, [&](auto& a, auto& b) { return log_sum_exp(a, b); });
        }
        if (calc_b) {
          db_mn = (term1_mn + log_rising_factorial(b, n).array())
                  - (term2_mn + log_rising_factorial(bp1, n).array());
          db_iter_m = db_iter_m.binaryExpr(
              db_mn, [&](auto& a, auto& b) { return log_sum_exp(a, b); });
        }

        // Series convergence assessed by whether the sum of all terms is
        //   smaller than the specified criteria (precision)
        inner_diff = max(log_sum_exp(da_mn), log_sum_exp(db_mn));
        n += 1;
      }
      if (calc_a) {
        // Accumulate sums once the inner loop for the current iteration has
        //   converged
        da_infsum = da_infsum.binaryExpr(
            da_iter_m, [&](auto& a, auto& b) { return log_sum_exp(a, b); });
      }
      if (calc_b) {
        db_infsum = db_infsum.binaryExpr(
            db_iter_m, [&](auto& a, auto& b) { return log_sum_exp(a, b); });
      }

      // Assess convergence of outer loop
      outer_diff = max(log_sum_exp(da_iter_m), log_sum_exp(db_iter_m));
      m += 1;
    }
    if (m == max_steps) {
      throw_domain_error("grad_pFq", "k (internal counter)", max_steps,
                         "exceeded ",
                         " iterations, hypergeometric function gradient "
                         "did not converge.");
    }

    if (calc_a) {
      // Workaround to construct vector where each element is the product of
      //   all other elements
      Eigen::VectorXi ind_vector
          = Eigen::VectorXi::LinSpaced(a.size(), 0, a.size() - 1);

      Ta_plain prod_excl_curr = ind_vector.unaryExpr(
          [&log_a, &sum_log_a](int i) { return sum_log_a - log_a[i]; });
      T_vec pre_mult_a = (log_z + prod_excl_curr.array() - sum_log_b).matrix();

      // Evaluate gradients into provided containers
      std::get<0>(grad_tuple) = exp(pre_mult_a + da_infsum);
    }

    if (calc_b) {
      T_vec pre_mult_b = (log_z + sum_log_a) - (log_b.array() + sum_log_b);
      std::get<1>(grad_tuple) = -exp(pre_mult_b + db_infsum);
    }
  }

  if (calc_z) {
    std::get<2>(grad_tuple)
        = exp(sum_log_a - sum_log_b) * hypergeometric_pFq(ap1, bp1, z);
  }
}
}  // namespace internal

/**
 * Wrapper function for calculating gradients for the generalized
 * hypergeometric function. The function always returns a tuple with
 * three elements (gradients wrt a, b, and z, respectively), but the
 * elements will only be defined/calculated when the respective parameter
 * is not a primitive type.
 *
 * @tparam Ta Eigen type with either one row or column at compile time
 * @tparam Tb Eigen type with either one row or column at compile time
 * @tparam Tz Scalar type
 * @param[in] a Vector of 'a' arguments to function
 * @param[in] b Vector of 'b' arguments to function
 * @param[in] z Scalar z argument
 * @param[in] precision Convergence criteria for infinite sum
 * @param[in] max_steps Maximum number of iterations for infinite sum
 * @return Tuple of gradients
 */
template <typename Ta, typename Tb, typename Tz>
auto grad_pFq(const Ta& a, const Tb& b, const Tz& z, double precision = 1e-14,
              int max_steps = 1e6) {
  using partials_t = partials_return_t<Ta, Tb, Tz>;
  std::tuple<promote_scalar_t<partials_t, plain_type_t<Ta>>,
             promote_scalar_t<partials_t, plain_type_t<Tb>>,
             promote_scalar_t<partials_t, plain_type_t<Tz>>>
      ret_tuple;
  internal::grad_pFq_impl<!is_constant<Ta>::value, !is_constant<Tb>::value,
                          !is_constant<Tz>::value>(
      ret_tuple, value_of(a), value_of(b), value_of(z), precision, max_steps);
  return ret_tuple;
}

}  // namespace math
}  // namespace stan
#endif
<commit_msg>Construct lgamma and log_factorial iteratively & loosen inner convergence criteria<commit_after>#ifndef STAN_MATH_PRIM_FUN_GRAD_PFQ_HPP
#define STAN_MATH_PRIM_FUN_GRAD_PFQ_HPP

#include <stan/math/prim/meta.hpp>
#include <stan/math/prim/err.hpp>
#include <stan/math/prim/fun/constants.hpp>
#include <stan/math/prim/fun/exp.hpp>
#include <stan/math/prim/fun/log.hpp>
#include <stan/math/prim/fun/log_rising_factorial.hpp>
#include <stan/math/prim/fun/hypergeometric_pFq.hpp>
#include <stan/math/prim/fun/max.hpp>
#include <stan/math/prim/fun/log_sum_exp.hpp>
#include <cmath>

namespace stan {
namespace math {
namespace internal {

/**
 * Returns the gradient of generalised hypergeometric function wrt to the
 * input arguments:
 * \f$ _pF_q(a_1,...,a_p;b_1,...,b_q;z) \f$
 *
 * The derivatives wrt a and b are defined using a Kampé de Fériet function,
 *   (https://en.wikipedia.org/wiki/Kamp%C3%A9_de_F%C3%A9riet_function).
 *   This is implemented below as an infinite sum (on the log scale) until
 *   convergence.
 *
 * \f$ \frac{\partial}{\partial a_1} =
 *     \frac{z\prod_{j=2}^pa_j}{\prod_{j=1}^qb_j}
 *     F_{q+1\:0\;1}^{p\:1\:2}\left(\begin{array}&a_1+1,...,a_p+1;1;1,a_1\\
 *        2, b_1+1,...,b_1+1;;a_1+1\end{array};z,z\right) \f$
 *
 * \f$ \frac{\partial}{\partial b_1}=
 *     -\frac{z\prod_{j=1}^pa_j}{b_1\prod_{j=1}^qb_j}
 *     F_{q+1\:0\;1}^{p\:1\:2}\left(\begin{array}&a_1+1,...,a_p+1;1;1,b_1\\
 *        2, b_1+1,...,b_1+1;;b_1+1\end{array};z,z\right) \f$
 *
 * \f$ \frac{\partial}{\partial z}= \frac{\prod_{j=1}^pa_j}{\prod_{j=1}^qb_j}
 *      {}_pF_q(a_1 + 1,...,a_p + 1; b_1 +1,...,b_q+1;z) \f$
 *
 * @tparam calc_a Boolean for whether to calculate derivatives wrt to 'a'
 * @tparam calc_b Boolean for whether to calculate derivatives wrt to 'b'
 * @tparam calc_z Boolean for whether to calculate derivatives wrt to 'z'
 * @tparam TupleT Type of tuple containing objects to evaluate gradients into
 * @tparam Ta Eigen type with either one row or column at compile time
 * @tparam Tb Eigen type with either one row or column at compile time
 * @tparam Tz Scalar type
 * @param[in] grad_tuple Tuple of references to evaluate gradients into
 * @param[in] a Vector of 'a' arguments to function
 * @param[in] b Vector of 'b' arguments to function
 * @param[in] z Scalar z argument
 * @param[in] precision Convergence criteria for infinite sum
 * @param[in] max_steps Maximum number of iterations for infinite sum
 * @return Generalised hypergeometric function
 */
template <bool calc_a, bool calc_b, bool calc_z, typename TupleT, typename Ta,
          typename Tb, typename Tz,
          require_all_eigen_vector_t<Ta, Tb>* = nullptr,
          require_stan_scalar_t<Tz>* = nullptr>
void grad_pFq_impl(TupleT&& grad_tuple, const Ta& a, const Tb& b, const Tz& z,
                   double precision, int max_steps) {
  using std::max;
  using scalar_t = return_type_t<Ta, Tb, Tz>;
  using Ta_plain = plain_type_t<Ta>;
  using Tb_plain = plain_type_t<Tb>;
  using T_vec = Eigen::Matrix<scalar_t, -1, 1>;

  Ta_plain ap1 = (a.array() + 1).matrix();
  Tb_plain bp1 = (b.array() + 1).matrix();
  Ta_plain log_a = log(a);
  Tb_plain log_b = log(b);
  scalar_type_t<Tz> log_z = log(z);
  scalar_type_t<Ta> sum_log_a = sum(log_a);
  scalar_type_t<Tb> sum_log_b = sum(log_b);

  // Declare vectors to accumulate sums into
  // where NEGATIVE_INFTY is zero on the log scale
  T_vec da_infsum = T_vec::Constant(a.size(), NEGATIVE_INFTY);
  T_vec db_infsum = T_vec::Constant(b.size(), NEGATIVE_INFTY);
  // Vectors to accumulate outer sum into
  T_vec da_iter_m = T_vec::Constant(a.size(), NEGATIVE_INFTY);
  T_vec da_mn = T_vec::Constant(a.size(), NEGATIVE_INFTY);
  T_vec db_iter_m = T_vec::Constant(b.size(), NEGATIVE_INFTY);
  T_vec db_mn = T_vec::Constant(b.size(), NEGATIVE_INFTY);

  // Only need the infinite sum for partials wrt p & b
  if (calc_a || calc_b) {
    double outer_precision = log(precision);
    double inner_precision = log(precision) - LOG_TWO;

    int m = 0;
    scalar_t outer_diff = 0;

    da_infsum.setConstant(NEGATIVE_INFTY);
    db_infsum.setConstant(NEGATIVE_INFTY);

    double lgamma_mp1 = 0;
    double log_phammer_1m = 0;
    double log_phammer_2m = 0;
    Ta_plain log_phammer_ap1_m = Ta_plain::Zero(ap1.size());
    Tb_plain log_phammer_bp1_m = Tb_plain::Zero(bp1.size());

    double log_phammer_1n;
    double log_phammer_2_mpn;
    double lgamma_np1;
    Ta_plain log_phammer_an(a.size());
    Ta_plain log_phammer_ap1_n(a.size());
    Ta_plain log_phammer_bp1_n(b.size());
    Tb_plain log_phammer_bn(b.size());
    Ta_plain log_phammer_ap1_mpn(a.size());
    Tb_plain log_phammer_bp1_mpn(b.size());

    while ((outer_diff > outer_precision) && (m < max_steps)) {
      // Vectors to accumulate outer sum into
      da_iter_m.setConstant(NEGATIVE_INFTY);
      da_mn.setConstant(NEGATIVE_INFTY);
      db_iter_m.setConstant(NEGATIVE_INFTY);
      db_mn.setConstant(NEGATIVE_INFTY);

      int n = 0;
      scalar_t inner_diff = 0;
      lgamma_np1 = 0;

      log_phammer_1n = 0;
      log_phammer_an.setZero();
      log_phammer_ap1_n.setZero();
      log_phammer_bp1_n.setZero();
      log_phammer_bn.setZero();
      log_phammer_ap1_mpn = log_phammer_ap1_m;
      log_phammer_bp1_mpn = log_phammer_bp1_m;
      log_phammer_2_mpn = log_phammer_2m;

      while ((inner_diff > inner_precision) & (n < (max_steps / 2))) {
        // Numerator term
        scalar_t term1_mn = (m + n) * log_z + sum(log_phammer_ap1_mpn)
                            + log_phammer_1m + log_phammer_1n;
        // Denominator term
        scalar_t term2_mn = lgamma_mp1 + lgamma_np1 + sum(log_phammer_bp1_mpn)
                            + log_phammer_2_mpn;
        if (calc_a) {
          // Division (on log scale) for the a & b partials
          da_mn = (term1_mn + log_phammer_an.array())
                  - (term2_mn + log_phammer_ap1_n.array());

          // Perform a row-wise log_sum_exp to accumulate current iteration
          da_iter_m = da_iter_m.binaryExpr(
              da_mn, [&](auto& a, auto& b) { return log_sum_exp(a, b); });
        }
        if (calc_b) {
          db_mn = (term1_mn + log_phammer_bn.array())
                  - (term2_mn + log_phammer_bp1_n.array());
          db_iter_m = db_iter_m.binaryExpr(
              db_mn, [&](auto& a, auto& b) { return log_sum_exp(a, b); });
        }

        // Series convergence assessed by whether the sum of all terms is
        //   smaller than the specified criteria (precision)
        inner_diff = max(log_sum_exp(da_mn), log_sum_exp(db_mn));

        log_phammer_1n += log1p(n);
        log_phammer_2_mpn += log1p(1 + m + n);
        log_phammer_ap1_n.array() += log(ap1.array() + n);
        log_phammer_bp1_n.array() += log(bp1.array() + n);
        log_phammer_an.array() += log(a.array() + n);
        log_phammer_bn.array() += log(b.array() + n);
        log_phammer_ap1_mpn.array() += log(ap1.array() + m + n);
        log_phammer_bp1_mpn.array() += log(bp1.array() + m + n);
        n += 1;
        lgamma_np1 += log(n);
      }
      if (calc_a) {
        // Accumulate sums once the inner loop for the current iteration has
        //   converged
        da_infsum = da_infsum.binaryExpr(
            da_iter_m, [&](auto& a, auto& b) { return log_sum_exp(a, b); });
      }
      if (calc_b) {
        db_infsum = db_infsum.binaryExpr(
            db_iter_m, [&](auto& a, auto& b) { return log_sum_exp(a, b); });
      }

      // Assess convergence of outer loop
      outer_diff = max(log_sum_exp(da_iter_m), log_sum_exp(db_iter_m));

      log_phammer_1m += log1p(m);
      log_phammer_2m += log1p(1 + m);
      log_phammer_ap1_m.array() += log(ap1.array() + m);
      log_phammer_bp1_m.array() += log(bp1.array() + m);

      m += 1;

      lgamma_mp1 += log(m);
    }
    if (m == max_steps) {
      throw_domain_error("grad_pFq", "k (internal counter)", max_steps,
                         "exceeded ",
                         " iterations, hypergeometric function gradient "
                         "did not converge.");
    }

    if (calc_a) {
      // Workaround to construct vector where each element is the product of
      //   all other elements
      Eigen::VectorXi ind_vector
          = Eigen::VectorXi::LinSpaced(a.size(), 0, a.size() - 1);

      Ta_plain prod_excl_curr = ind_vector.unaryExpr(
          [&log_a, &sum_log_a](int i) { return sum_log_a - log_a[i]; });
      T_vec pre_mult_a = (log_z + prod_excl_curr.array() - sum_log_b).matrix();

      // Evaluate gradients into provided containers
      std::get<0>(grad_tuple) = exp(pre_mult_a + da_infsum);
    }

    if (calc_b) {
      T_vec pre_mult_b = (log_z + sum_log_a) - (log_b.array() + sum_log_b);
      std::get<1>(grad_tuple) = -exp(pre_mult_b + db_infsum);
    }
  }

  if (calc_z) {
    std::get<2>(grad_tuple)
        = exp(sum_log_a - sum_log_b) * hypergeometric_pFq(ap1, bp1, z);
  }
}
}  // namespace internal

/**
 * Wrapper function for calculating gradients for the generalized
 * hypergeometric function. The function always returns a tuple with
 * three elements (gradients wrt a, b, and z, respectively), but the
 * elements will only be defined/calculated when the respective parameter
 * is not a primitive type.
 *
 * @tparam Ta Eigen type with either one row or column at compile time
 * @tparam Tb Eigen type with either one row or column at compile time
 * @tparam Tz Scalar type
 * @param[in] a Vector of 'a' arguments to function
 * @param[in] b Vector of 'b' arguments to function
 * @param[in] z Scalar z argument
 * @param[in] precision Convergence criteria for infinite sum
 * @param[in] max_steps Maximum number of iterations for infinite sum
 * @return Tuple of gradients
 */
template <typename Ta, typename Tb, typename Tz>
auto grad_pFq(const Ta& a, const Tb& b, const Tz& z, double precision = 1e-10,
              int max_steps = 1e6) {
  using partials_t = partials_return_t<Ta, Tb, Tz>;
  std::tuple<promote_scalar_t<partials_t, plain_type_t<Ta>>,
             promote_scalar_t<partials_t, plain_type_t<Tb>>,
             promote_scalar_t<partials_t, plain_type_t<Tz>>>
      ret_tuple;
  internal::grad_pFq_impl<!is_constant<Ta>::value, !is_constant<Tb>::value,
                          !is_constant<Tz>::value>(
      ret_tuple, value_of(a), value_of(b), value_of(z), precision, max_steps);
  return ret_tuple;
}

}  // namespace math
}  // namespace stan
#endif
<|endoftext|>


<commit_before>// @(#)root/hist:$Name:  $:$Id: TLimit.cxx,v 1.2 2002/09/06 20:24:18 brun Exp $
// Author: Christophe.Delaere@cern.ch   21/08/2002

///////////////////////////////////////////////////////////////////////////
//
// TLimit
//
// Class to compute 95% CL limits
//
///////////////////////////////////////////////////////////////////////////

/*************************************************************************
 * C.Delaere                                                             *
 * adapted from the mclimit code from Tom Junk                           *
 * see http://cern.ch/thomasj/searchlimits/ecl.html                      *
 *************************************************************************/

#include "TLimit.h"
#include "TArrayF.h"
#include "TOrdCollection.h"
#include "TConfidenceLevel.h"
#include "TLimitDataSource.h"
#include "TRandom3.h"
#include "TH1.h"
#include "TObjArray.h"
#include "TMath.h"
#include "TIterator.h"
#include "TObjString.h"
#include "TClassTable.h"
#include "Riostream.h"

ClassImp(TLimit)

TArrayF *TLimit::fgTable = new TArrayF(0);
TOrdCollection *TLimit::fgSystNames = new TOrdCollection();

TConfidenceLevel *TLimit::ComputeLimit(TLimitDataSource * data,
                                       Int_t nmc, TRandom * generator,
                                       Double_t(*statistic) (Double_t,
                                                             Double_t,
                                                             Double_t))
{
   // class TLimit
   // ------------
   //
   // Algorithm to compute 95% C.L. limits using the Likelihood ratio
   // semi-bayesian method.
   // It takes signal, background and data histograms wrapped in a
   // TLimitDataSource as input and runs a set of Monte Carlo experiments in
   // order to compute the limits. If needed, inputs are fluctuated according
   // to systematics. The output is a TConfidenceLevel.
   //
   // class TLimitDataSource
   // ----------------------
   //
   // Takes the signal, background and data histograms as well as different
   // systematics sources to form the TLimit input.
   //
   //  class TConfidenceLevel
   //  ----------------------
   //
   // Final result of the TLimit algorithm. It is created just after the
   // time-consuming part and can be stored in a TFile for further processing.
   // It contains light methods to return CLs, CLb and other interesting
   // quantities.
   //
   // The actual algorithm...
   // From an input (TLimitDataSource) it produces an output TConfidenceLevel.
   // For this, nmc Monte Carlo experiments are performed.
   // As usual, the larger this number, the longer the compute time,
   // but the better the result.
   //Begin_Html
   /*

Supposing that there is a plotfile.root file containing 3 histograms
           (signal, background and data), you can imagine doing things like:

    TFile* infile=new TFile("plotfile.root","READ");
    infile->cd();
    TH1F* sh=(TH1F*)infile->Get("signal");
    TH1F* bh=(TH1F*)infile->Get("background");
    TH1F* dh=(TH1F*)infile->Get("data");
    TLimitDataSource* mydatasource = new TLimitDataSource(sh,bh,dh);
    TConfidenceLevel *myconfidence = TLimit::ComputeLimit(mydatasource,50000);
    cout &lt&lt "  CLs    : " &lt&lt myconfidence->CLs()  &lt&lt endl;
    cout &lt&lt "  CLsb   : " &lt&lt myconfidence->CLsb() &lt&lt endl;
    cout &lt&lt "  CLb    : " &lt&lt myconfidence->CLb()  &lt&lt endl;
    cout &lt&lt "&lt CLs &gt  : " &lt&lt myconfidence->GetExpectedCLs_b()  &lt&lt endl;
    cout &lt&lt "&lt CLsb &gt : " &lt&lt myconfidence->GetExpectedCLsb_b() &lt&lt endl;
    cout &lt&lt "&lt CLb &gt  : " &lt&lt myconfidence->GetExpectedCLb_b()  &lt&lt endl;
    delete myconfidence;
    delete mydatasource;
    infile->Close();

More informations can still be found on
   this page.

   */
   //End_Html

   // The final object returned...
   TConfidenceLevel *result = new TConfidenceLevel(nmc);
   // The random generator used...
   TRandom *myrandom = generator ? generator : new TRandom3;
   // Compute some total quantities on all the channels
   Int_t nbins   = 0;
   Int_t maxbins = 0;
   Double_t nsig = 0;
   Double_t nbg  = 0;
   Int_t ncand   = 0;
   Int_t i;
   for (i = 0; i <= data->GetSignal()->GetLast(); i++) {
      nbins  += ((TH1F *) (data->GetSignal()->At(i)))->GetNbinsX();
      maxbins = ((TH1F *) (data->GetSignal()->At(i)))->GetNbinsX() > maxbins ?
	        ((TH1F *) (data->GetSignal()->At(i)))->GetNbinsX() + 1 : maxbins;
      nsig   += ((TH1F *) (data->GetSignal()->At(i)))->Integral();
      nbg    += ((TH1F *) (data->GetBackground()->At(i)))->Integral();
      ncand  += (Int_t) ((TH1F *) (data->GetCandidates()->At(i)))->Integral();
   }
   result->SetBtot(nbg);
   result->SetStot(nsig);
   result->SetDtot(ncand);
   Double_t buffer = 0;
   fgTable->Set(maxbins * (data->GetSignal()->GetLast() + 1));
   for (Int_t channel = 0; channel <= data->GetSignal()->GetLast(); channel++)
      for (Int_t bin = 0;
           bin <= ((TH1F *) (data->GetSignal()->At(channel)))->GetNbinsX();
           bin++) {
         Double_t s = (Double_t) ((TH1F *) (data->GetSignal()->At(channel)))->GetBinContent(bin);
         Double_t b = (Double_t) ((TH1F *) (data->GetBackground()->At(channel)))->GetBinContent(bin);
         Double_t d = (Double_t) ((TH1F *) (data->GetCandidates()->At(channel)))->GetBinContent(bin);
         // Compute the value of the "-2lnQ" for the actual data
         if ((b == 0) && (s > 0)) {
            cout << "WARNING: Ignoring bin " << bin << " of channel "
                 << channel << " which has s=" << s << " but b=" << b << endl;
            cout << "         Maybe the MC statistic has to be improved..." << endl;
         }
         if ((s > 0) && (b > 0))
            buffer += statistic(s, b, d);
         // precompute the log(1+s/b)'s in an array to speed up computation
         // background-free bins are set to have a maximum t.s. value
         // for protection (corresponding to s/b of about 5E8)
         if ((s > 0) && (b > 0))
            fgTable->AddAt(statistic(s, b, 1), (channel * maxbins) + bin);
         else if ((s > 0) && (b == 0))
            fgTable->AddAt(20, (channel * maxbins) + bin);
      }
   result->SetTSD(buffer);
   // accumulate MC experiments.  Hold the test statistic function fixed, but
   // fluctuate s and b within syst. errors for computing probabilities of
   // having that outcome.  (Alex Read's prescription -- errors are on the ensemble,
   // not on the observed test statistic.  This technique does not split outcomes.)
   // keep the tstats as sum log(1+s/b). convert to -2lnQ when preparing the results
   // (reason -- like to keep the < signs right)
   Double_t *tss = new Double_t[nmc];
   Double_t *tsb = new Double_t[nmc];
   Double_t *lrs = new Double_t[nmc];
   Double_t *lrb = new Double_t[nmc];
   for (i = 0; i < nmc; i++) {
      tss[i] = 0;
      tsb[i] = 0;
      lrs[i] = 0;
      lrb[i] = 0;
      // fluctuate signal and background
      TLimitDataSource *fluctuated = Fluctuate(data, !i, myrandom);
      for (Int_t channel = 0;
           channel <= fluctuated->GetSignal()->GetLast(); channel++) {
         for (Int_t bin = 0;
              bin <=((TH1F *) (fluctuated->GetSignal()->At(channel)))->GetNbinsX();
              bin++) {
            if ((Double_t) ((TH1F *) (fluctuated->GetSignal()->At(channel)))->GetBinContent(bin) != 0) {
               // s+b hypothesis
               Double_t rate = (Double_t) ((TH1F *) (fluctuated->GetSignal()->At(channel)))->GetBinContent(bin) +
                               (Double_t) ((TH1F *) (fluctuated->GetBackground()->At(channel)))->GetBinContent(bin);
               Double_t rand = myrandom->Poisson(rate);
               tss[i] += rand * fgTable->At((channel * maxbins) + bin);
               Double_t s = (Double_t) ((TH1F *) (fluctuated->GetSignal()->At(channel)))->GetBinContent(bin);
               Double_t b = (Double_t) ((TH1F *) (fluctuated->GetBackground()->At(channel)))->GetBinContent(bin);
               if ((s > 0) && (b > 0))
                  lrs[i] += statistic(s, b, rand) - s;
               else if ((s > 0) && (b = 0))
                  lrs[i] += 20 * rand - s;
               // b hypothesis
               rate = (Double_t) ((TH1F *) (fluctuated->GetBackground()->At(channel)))->GetBinContent(bin);
               rand = myrandom->Poisson(rate);
               tsb[i] += rand * fgTable->At((channel * maxbins) + bin);
               if ((s > 0) && (b > 0))
                  lrb[i] += statistic(s, b, rand) - s;
               else if ((s > 0) && (b = 0))
                  lrb[i] += 20 * rand - s;
            }
         }
      }
      lrs[i] = TMath::Exp(lrs[i]);
      lrb[i] = TMath::Exp(lrb[i]);
      if (data != fluctuated)
         delete fluctuated;
   }
   // lrs and lrb are the LR's (no logs) = prob(s+b)/prob(b) for
   // that choice of s and b within syst. errors in the ensemble.  These are
   // the MC experiment weights for relating the s+b and b PDF's of the unsmeared
   // test statistic (in which cas one can use another test statistic if one likes).

   // Now produce the output object.
   // The final quantities are computed on-demand form the arrays tss, tsb, lrs and lrb.
   result->SetTSS(tss);
   result->SetTSB(tsb);
   result->SetLRS(lrs);
   result->SetLRB(lrb);
   if (!generator)
      delete myrandom;
   return result;
}

TLimitDataSource *TLimit::Fluctuate(TLimitDataSource * input, bool init,
                                    TRandom * generator)
{
   // initialisation: create a sorted list of all the names of systematics
   if (init) {
      // create a "map" with the systematics names
      TIterator *errornames = input->GetErrorNames()->MakeIterator();
      TObjArray *listofnames = 0;
      while ((listofnames = ((TObjArray *) errornames->Next()))) {
         TObjString *name = NULL;
         TIterator *loniter = listofnames->MakeIterator();
         while ((name = (TObjString *) (loniter->Next())))
            if ((fgSystNames->IndexOf(name)) < 0)
               fgSystNames->AddLast(name);
      }
      fgSystNames->Sort();
   }
   // if there are no systematics, just returns the input as "fluctuated" output
   if (fgSystNames->GetSize() <= 0)
      return input;
   // Find a choice for the random variation and
   // re-toss all random numbers if any background or signal
   // goes negative.  (background = 0 is bad too, so put a little protection
   // around it -- must have at least 10% of the bg estimate).
   bool retoss = kTRUE;
   Double_t *serrf = NULL;
   Double_t *berrf = NULL;
   do {
      Double_t *toss = new Double_t[fgSystNames->GetSize()];
      for (Int_t i = 0; i < fgSystNames->GetSize(); i++)
         toss[i] = generator->Gaus(0, 1);
      retoss = kFALSE;
      serrf = new Double_t[(input->GetSignal()->GetLast()) + 1];
      berrf = new Double_t[(input->GetSignal()->GetLast()) + 1];
      for (Int_t channel = 0;
           channel <= input->GetSignal()->GetLast();
           channel++) {
         serrf[channel] = 0;
         berrf[channel] = 0;
         for (Int_t bin = 0;
              bin <=((TH1F *) (input->GetErrorOnSignal()->At(channel)))->GetNbinsX();
	      bin++) {
            serrf[channel] += ((TH1F *) (input->GetErrorOnSignal()->At(channel)))->GetBinContent(bin) *
                toss[fgSystNames->BinarySearch((TObjString*) (((TObjArray *) (input->GetErrorNames()->At(channel)))->At(bin)))];
            berrf[channel] += ((TH1F *) (input->GetErrorOnBackground()->At(channel)))->GetBinContent(bin) *
                toss[fgSystNames->BinarySearch((TObjString*) (((TObjArray *) (input->GetErrorNames()->At(channel)))->At(bin)))];
         }
         if ((serrf[channel] < -1.0) || (berrf[channel] < -0.9)) {
            retoss = kTRUE;
            continue;
         }
      }
      delete[]toss;
   } while (retoss);
   // adjust the fluctuated signal and background counts with a legal set
   // of random fluctuations above.
   TLimitDataSource *result = new TLimitDataSource();
   result->SetOwner();
   for (Int_t channel = 0; channel <= input->GetSignal()->GetLast();
        channel++) {
      TH1F *newsignal = new TH1F(*(TH1F *) (input->GetSignal()->At(channel)));
      newsignal->Scale(1 + serrf[channel]);
      newsignal->SetDirectory(0);
      TH1F *newbackground = new TH1F(*(TH1F *) (input->GetBackground()->At(channel)));
      newbackground->Scale(1 + berrf[channel]);
      newbackground->SetDirectory(0);
      TH1F *newcandidates = new TH1F(*(TH1F *) (input->GetCandidates()));
      newcandidates->SetDirectory(0);
      result->AddChannel(newsignal, newbackground, newcandidates);
   }
   delete[] serrf;
   delete[] berrf;
   return result;
}

<commit_msg>change (b = 0) to (b == 0) in if statement.<commit_after>// @(#)root/hist:$Name:  $:$Id: TLimit.cxx,v 1.3 2002/09/06 21:41:23 brun Exp $
// Author: Christophe.Delaere@cern.ch   21/08/2002

///////////////////////////////////////////////////////////////////////////
//
// TLimit
//
// Class to compute 95% CL limits
//
///////////////////////////////////////////////////////////////////////////

/*************************************************************************
 * C.Delaere                                                             *
 * adapted from the mclimit code from Tom Junk                           *
 * see http://cern.ch/thomasj/searchlimits/ecl.html                      *
 *************************************************************************/

#include "TLimit.h"
#include "TArrayF.h"
#include "TOrdCollection.h"
#include "TConfidenceLevel.h"
#include "TLimitDataSource.h"
#include "TRandom3.h"
#include "TH1.h"
#include "TObjArray.h"
#include "TMath.h"
#include "TIterator.h"
#include "TObjString.h"
#include "TClassTable.h"
#include "Riostream.h"

ClassImp(TLimit)

TArrayF *TLimit::fgTable = new TArrayF(0);
TOrdCollection *TLimit::fgSystNames = new TOrdCollection();

TConfidenceLevel *TLimit::ComputeLimit(TLimitDataSource * data,
                                       Int_t nmc, TRandom * generator,
                                       Double_t(*statistic) (Double_t,
                                                             Double_t,
                                                             Double_t))
{
   // class TLimit
   // ------------
   //
   // Algorithm to compute 95% C.L. limits using the Likelihood ratio
   // semi-bayesian method.
   // It takes signal, background and data histograms wrapped in a
   // TLimitDataSource as input and runs a set of Monte Carlo experiments in
   // order to compute the limits. If needed, inputs are fluctuated according
   // to systematics. The output is a TConfidenceLevel.
   //
   // class TLimitDataSource
   // ----------------------
   //
   // Takes the signal, background and data histograms as well as different
   // systematics sources to form the TLimit input.
   //
   //  class TConfidenceLevel
   //  ----------------------
   //
   // Final result of the TLimit algorithm. It is created just after the
   // time-consuming part and can be stored in a TFile for further processing.
   // It contains light methods to return CLs, CLb and other interesting
   // quantities.
   //
   // The actual algorithm...
   // From an input (TLimitDataSource) it produces an output TConfidenceLevel.
   // For this, nmc Monte Carlo experiments are performed.
   // As usual, the larger this number, the longer the compute time,
   // but the better the result.
   //Begin_Html
   /*

Supposing that there is a plotfile.root file containing 3 histograms
           (signal, background and data), you can imagine doing things like:

    TFile* infile=new TFile("plotfile.root","READ");
    infile->cd();
    TH1F* sh=(TH1F*)infile->Get("signal");
    TH1F* bh=(TH1F*)infile->Get("background");
    TH1F* dh=(TH1F*)infile->Get("data");
    TLimitDataSource* mydatasource = new TLimitDataSource(sh,bh,dh);
    TConfidenceLevel *myconfidence = TLimit::ComputeLimit(mydatasource,50000);
    cout &lt&lt "  CLs    : " &lt&lt myconfidence->CLs()  &lt&lt endl;
    cout &lt&lt "  CLsb   : " &lt&lt myconfidence->CLsb() &lt&lt endl;
    cout &lt&lt "  CLb    : " &lt&lt myconfidence->CLb()  &lt&lt endl;
    cout &lt&lt "&lt CLs &gt  : " &lt&lt myconfidence->GetExpectedCLs_b()  &lt&lt endl;
    cout &lt&lt "&lt CLsb &gt : " &lt&lt myconfidence->GetExpectedCLsb_b() &lt&lt endl;
    cout &lt&lt "&lt CLb &gt  : " &lt&lt myconfidence->GetExpectedCLb_b()  &lt&lt endl;
    delete myconfidence;
    delete mydatasource;
    infile->Close();

More informations can still be found on
   this page.

   */
   //End_Html

   // The final object returned...
   TConfidenceLevel *result = new TConfidenceLevel(nmc);
   // The random generator used...
   TRandom *myrandom = generator ? generator : new TRandom3;
   // Compute some total quantities on all the channels
   Int_t nbins   = 0;
   Int_t maxbins = 0;
   Double_t nsig = 0;
   Double_t nbg  = 0;
   Int_t ncand   = 0;
   Int_t i;
   for (i = 0; i <= data->GetSignal()->GetLast(); i++) {
      nbins  += ((TH1F *) (data->GetSignal()->At(i)))->GetNbinsX();
      maxbins = ((TH1F *) (data->GetSignal()->At(i)))->GetNbinsX() > maxbins ?
	        ((TH1F *) (data->GetSignal()->At(i)))->GetNbinsX() + 1 : maxbins;
      nsig   += ((TH1F *) (data->GetSignal()->At(i)))->Integral();
      nbg    += ((TH1F *) (data->GetBackground()->At(i)))->Integral();
      ncand  += (Int_t) ((TH1F *) (data->GetCandidates()->At(i)))->Integral();
   }
   result->SetBtot(nbg);
   result->SetStot(nsig);
   result->SetDtot(ncand);
   Double_t buffer = 0;
   fgTable->Set(maxbins * (data->GetSignal()->GetLast() + 1));
   for (Int_t channel = 0; channel <= data->GetSignal()->GetLast(); channel++)
      for (Int_t bin = 0;
           bin <= ((TH1F *) (data->GetSignal()->At(channel)))->GetNbinsX();
           bin++) {
         Double_t s = (Double_t) ((TH1F *) (data->GetSignal()->At(channel)))->GetBinContent(bin);
         Double_t b = (Double_t) ((TH1F *) (data->GetBackground()->At(channel)))->GetBinContent(bin);
         Double_t d = (Double_t) ((TH1F *) (data->GetCandidates()->At(channel)))->GetBinContent(bin);
         // Compute the value of the "-2lnQ" for the actual data
         if ((b == 0) && (s > 0)) {
            cout << "WARNING: Ignoring bin " << bin << " of channel "
                 << channel << " which has s=" << s << " but b=" << b << endl;
            cout << "         Maybe the MC statistic has to be improved..." << endl;
         }
         if ((s > 0) && (b > 0))
            buffer += statistic(s, b, d);
         // precompute the log(1+s/b)'s in an array to speed up computation
         // background-free bins are set to have a maximum t.s. value
         // for protection (corresponding to s/b of about 5E8)
         if ((s > 0) && (b > 0))
            fgTable->AddAt(statistic(s, b, 1), (channel * maxbins) + bin);
         else if ((s > 0) && (b == 0))
            fgTable->AddAt(20, (channel * maxbins) + bin);
      }
   result->SetTSD(buffer);
   // accumulate MC experiments.  Hold the test statistic function fixed, but
   // fluctuate s and b within syst. errors for computing probabilities of
   // having that outcome.  (Alex Read's prescription -- errors are on the ensemble,
   // not on the observed test statistic.  This technique does not split outcomes.)
   // keep the tstats as sum log(1+s/b). convert to -2lnQ when preparing the results
   // (reason -- like to keep the < signs right)
   Double_t *tss = new Double_t[nmc];
   Double_t *tsb = new Double_t[nmc];
   Double_t *lrs = new Double_t[nmc];
   Double_t *lrb = new Double_t[nmc];
   for (i = 0; i < nmc; i++) {
      tss[i] = 0;
      tsb[i] = 0;
      lrs[i] = 0;
      lrb[i] = 0;
      // fluctuate signal and background
      TLimitDataSource *fluctuated = Fluctuate(data, !i, myrandom);
      for (Int_t channel = 0;
           channel <= fluctuated->GetSignal()->GetLast(); channel++) {
         for (Int_t bin = 0;
              bin <=((TH1F *) (fluctuated->GetSignal()->At(channel)))->GetNbinsX();
              bin++) {
            if ((Double_t) ((TH1F *) (fluctuated->GetSignal()->At(channel)))->GetBinContent(bin) != 0) {
               // s+b hypothesis
               Double_t rate = (Double_t) ((TH1F *) (fluctuated->GetSignal()->At(channel)))->GetBinContent(bin) +
                               (Double_t) ((TH1F *) (fluctuated->GetBackground()->At(channel)))->GetBinContent(bin);
               Double_t rand = myrandom->Poisson(rate);
               tss[i] += rand * fgTable->At((channel * maxbins) + bin);
               Double_t s = (Double_t) ((TH1F *) (fluctuated->GetSignal()->At(channel)))->GetBinContent(bin);
               Double_t b = (Double_t) ((TH1F *) (fluctuated->GetBackground()->At(channel)))->GetBinContent(bin);
               if ((s > 0) && (b > 0))
                  lrs[i] += statistic(s, b, rand) - s;
               else if ((s > 0) && (b == 0))
                  lrs[i] += 20 * rand - s;
               // b hypothesis
               rate = (Double_t) ((TH1F *) (fluctuated->GetBackground()->At(channel)))->GetBinContent(bin);
               rand = myrandom->Poisson(rate);
               tsb[i] += rand * fgTable->At((channel * maxbins) + bin);
               if ((s > 0) && (b > 0))
                  lrb[i] += statistic(s, b, rand) - s;
               else if ((s > 0) && (b == 0))
                  lrb[i] += 20 * rand - s;
            }
         }
      }
      lrs[i] = TMath::Exp(lrs[i]);
      lrb[i] = TMath::Exp(lrb[i]);
      if (data != fluctuated)
         delete fluctuated;
   }
   // lrs and lrb are the LR's (no logs) = prob(s+b)/prob(b) for
   // that choice of s and b within syst. errors in the ensemble.  These are
   // the MC experiment weights for relating the s+b and b PDF's of the unsmeared
   // test statistic (in which cas one can use another test statistic if one likes).

   // Now produce the output object.
   // The final quantities are computed on-demand form the arrays tss, tsb, lrs and lrb.
   result->SetTSS(tss);
   result->SetTSB(tsb);
   result->SetLRS(lrs);
   result->SetLRB(lrb);
   if (!generator)
      delete myrandom;
   return result;
}

TLimitDataSource *TLimit::Fluctuate(TLimitDataSource * input, bool init,
                                    TRandom * generator)
{
   // initialisation: create a sorted list of all the names of systematics
   if (init) {
      // create a "map" with the systematics names
      TIterator *errornames = input->GetErrorNames()->MakeIterator();
      TObjArray *listofnames = 0;
      while ((listofnames = ((TObjArray *) errornames->Next()))) {
         TObjString *name = NULL;
         TIterator *loniter = listofnames->MakeIterator();
         while ((name = (TObjString *) (loniter->Next())))
            if ((fgSystNames->IndexOf(name)) < 0)
               fgSystNames->AddLast(name);
      }
      fgSystNames->Sort();
   }
   // if there are no systematics, just returns the input as "fluctuated" output
   if (fgSystNames->GetSize() <= 0)
      return input;
   // Find a choice for the random variation and
   // re-toss all random numbers if any background or signal
   // goes negative.  (background = 0 is bad too, so put a little protection
   // around it -- must have at least 10% of the bg estimate).
   bool retoss = kTRUE;
   Double_t *serrf = NULL;
   Double_t *berrf = NULL;
   do {
      Double_t *toss = new Double_t[fgSystNames->GetSize()];
      for (Int_t i = 0; i < fgSystNames->GetSize(); i++)
         toss[i] = generator->Gaus(0, 1);
      retoss = kFALSE;
      serrf = new Double_t[(input->GetSignal()->GetLast()) + 1];
      berrf = new Double_t[(input->GetSignal()->GetLast()) + 1];
      for (Int_t channel = 0;
           channel <= input->GetSignal()->GetLast();
           channel++) {
         serrf[channel] = 0;
         berrf[channel] = 0;
         for (Int_t bin = 0;
              bin <=((TH1F *) (input->GetErrorOnSignal()->At(channel)))->GetNbinsX();
	      bin++) {
            serrf[channel] += ((TH1F *) (input->GetErrorOnSignal()->At(channel)))->GetBinContent(bin) *
                toss[fgSystNames->BinarySearch((TObjString*) (((TObjArray *) (input->GetErrorNames()->At(channel)))->At(bin)))];
            berrf[channel] += ((TH1F *) (input->GetErrorOnBackground()->At(channel)))->GetBinContent(bin) *
                toss[fgSystNames->BinarySearch((TObjString*) (((TObjArray *) (input->GetErrorNames()->At(channel)))->At(bin)))];
         }
         if ((serrf[channel] < -1.0) || (berrf[channel] < -0.9)) {
            retoss = kTRUE;
            continue;
         }
      }
      delete[]toss;
   } while (retoss);
   // adjust the fluctuated signal and background counts with a legal set
   // of random fluctuations above.
   TLimitDataSource *result = new TLimitDataSource();
   result->SetOwner();
   for (Int_t channel = 0; channel <= input->GetSignal()->GetLast();
        channel++) {
      TH1F *newsignal = new TH1F(*(TH1F *) (input->GetSignal()->At(channel)));
      newsignal->Scale(1 + serrf[channel]);
      newsignal->SetDirectory(0);
      TH1F *newbackground = new TH1F(*(TH1F *) (input->GetBackground()->At(channel)));
      newbackground->Scale(1 + berrf[channel]);
      newbackground->SetDirectory(0);
      TH1F *newcandidates = new TH1F(*(TH1F *) (input->GetCandidates()));
      newcandidates->SetDirectory(0);
      result->AddChannel(newsignal, newbackground, newcandidates);
   }
   delete[] serrf;
   delete[] berrf;
   return result;
}

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2012 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "V8CustomEvent.h"

#include "V8Event.h"
#include "bindings/v8/Dictionary.h"
#include "bindings/v8/ScriptState.h"
#include "bindings/v8/ScriptValue.h"
#include "bindings/v8/V8Binding.h"
#include "bindings/v8/V8DOMWrapper.h"
#include "bindings/v8/V8HiddenPropertyName.h"
#include "core/dom/ContextFeatures.h"
#include "core/dom/ExceptionCode.h"
#include "core/page/Frame.h"
#include "RuntimeEnabledFeatures.h"

namespace WebCore {

static v8::Handle<v8::Value> cacheState(v8::Handle<v8::Object> customEvent, v8::Handle<v8::Value> detail)
{
    customEvent->SetHiddenValue(V8HiddenPropertyName::detail(), detail);
    return detail;
}

void V8CustomEvent::detailAttrGetterCustom(v8::Local<v8::String> name, const v8::PropertyCallbackInfo<v8::Value>& info)
{
    CustomEvent* event = V8CustomEvent::toNative(info.Holder());
    ASSERT(!event->serializedScriptValue().get());

    v8::Handle<v8::Value> result = info.Holder()->GetHiddenValue(V8HiddenPropertyName::detail());

    if (!result.IsEmpty()) {
        v8SetReturnValue(info, result);
        return;
    }

    RefPtr<SerializedScriptValue> serialized = event->serializedScriptValue();
    if (serialized) {
        result = serialized->deserialize();
        v8SetReturnValue(info, cacheState(info.Holder(), result));
        return;
    }

    v8SetReturnValue(info, cacheState(info.Holder(), v8::Null(info.GetIsolate())));
}

void V8CustomEvent::initCustomEventMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args)
{
    CustomEvent* event = V8CustomEvent::toNative(args.Holder());

    V8TRYCATCH_FOR_V8STRINGRESOURCE_VOID(V8StringResource<>, typeArg, args[0]);
    V8TRYCATCH_VOID(bool, canBubbleArg, args[1]->BooleanValue());
    V8TRYCATCH_VOID(bool, cancelableArg, args[2]->BooleanValue());
    v8::Handle<v8::Value> detailsArg = args[3];

    args.Holder()->SetHiddenValue(V8HiddenPropertyName::detail(), detailsArg);
    event->initEvent(typeArg, canBubbleArg, cancelableArg);
}

} // namespace WebCore
<commit_msg>Moved broken assert in CustomEvent from detail getter to init. Assert was hit in browser_test WebViewTest.IndexedDBIsolation.<commit_after>/*
 * Copyright (C) 2012 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "V8CustomEvent.h"

#include "V8Event.h"
#include "bindings/v8/Dictionary.h"
#include "bindings/v8/ScriptState.h"
#include "bindings/v8/ScriptValue.h"
#include "bindings/v8/V8Binding.h"
#include "bindings/v8/V8DOMWrapper.h"
#include "bindings/v8/V8HiddenPropertyName.h"
#include "core/dom/ContextFeatures.h"
#include "core/dom/ExceptionCode.h"
#include "core/page/Frame.h"
#include "RuntimeEnabledFeatures.h"

namespace WebCore {

static v8::Handle<v8::Value> cacheState(v8::Handle<v8::Object> customEvent, v8::Handle<v8::Value> detail)
{
    customEvent->SetHiddenValue(V8HiddenPropertyName::detail(), detail);
    return detail;
}

void V8CustomEvent::detailAttrGetterCustom(v8::Local<v8::String> name, const v8::PropertyCallbackInfo<v8::Value>& info)
{
    CustomEvent* event = V8CustomEvent::toNative(info.Holder());

    v8::Handle<v8::Value> result = info.Holder()->GetHiddenValue(V8HiddenPropertyName::detail());

    if (!result.IsEmpty()) {
        v8SetReturnValue(info, result);
        return;
    }

    RefPtr<SerializedScriptValue> serialized = event->serializedScriptValue();
    if (serialized) {
        result = serialized->deserialize();
        v8SetReturnValue(info, cacheState(info.Holder(), result));
        return;
    }

    v8SetReturnValue(info, cacheState(info.Holder(), v8::Null(info.GetIsolate())));
}

void V8CustomEvent::initCustomEventMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args)
{
    CustomEvent* event = V8CustomEvent::toNative(args.Holder());
    ASSERT(!event->serializedScriptValue());

    V8TRYCATCH_FOR_V8STRINGRESOURCE_VOID(V8StringResource<>, typeArg, args[0]);
    V8TRYCATCH_VOID(bool, canBubbleArg, args[1]->BooleanValue());
    V8TRYCATCH_VOID(bool, cancelableArg, args[2]->BooleanValue());
    v8::Handle<v8::Value> detailsArg = args[3];

    args.Holder()->SetHiddenValue(V8HiddenPropertyName::detail(), detailsArg);
    event->initEvent(typeArg, canBubbleArg, cancelableArg);
}

} // namespace WebCore
<|endoftext|>