// PValue for finding a local p-value as observed in 'bin' or worse 
void ToyExperiments::printGlobalPValueOfLocalFluctuation(unsigned int bin, unsigned int nExperiments) const {
  std::cout << "Determining global p-value for observed fluctuation in bin " << bin << " from " << nExperiments << " toy experiments ...  " << std::flush;

  // Find the predicted yields that correspond
  // to the local p-value 'localPValue'
  std::vector<unsigned int> limitYields = yields(localPValue(bin,observedYields_.at(bin)));

  TH1* hIsAbovePValue = new TH1D("hIsAbovePValue","",2,0,2);

  const double minCorr = findMinValidRandomNumberForCorrelatedUncertainties();

  for(unsigned int p = 0; p < nExperiments; ++p) {
    bool isAbovePValue = false;
    double rCorr = rand_->Gaus(0.,1.);
    while( rCorr <= minCorr ) {
      rCorr = rand_->Gaus(0.,1.);
    }
    for(unsigned int b = 0; b < Parameters::nBins(); ++b) {
      double prediction = -1.;
      bool negativePrediction = true;
      while( negativePrediction ) {
	double rUncorr = rand_->Gaus(0.,1.);
	double uncorrVar = rUncorr * uncorrelatedUncerts_.at(b);
	double corrVar   = rCorr   * correlatedUncerts_.at(b);
	prediction = meanPredictions_.at(b) + uncorrVar + corrVar;
	if( prediction >= 0. ) {
	  negativePrediction = false;
	}
      }
      double predictedYield = rand_->Poisson(prediction);
      if( predictedYield >= limitYields.at(b) ) {
	isAbovePValue = true;
	break;
      }      
    }
    if( isAbovePValue ) {
      hIsAbovePValue->Fill(1);
    } else {
      hIsAbovePValue->Fill(0);
    }
  }
  std::cout << "ok" << std::endl;

  double lpv      = localPValue(bin,observedYields_.at(bin));
  double gpUncorr = 1. - pow(1.-lpv,Parameters::nBins());
  double gpCorr   = hIsAbovePValue->Integral(2,2)/hIsAbovePValue->Integral(1,2);

  std::cout << "\n\n----- Global p-value for observed fluctuation in bin " << bin << " -----" << std::endl;
  std::cout << "  local p-value                           : " << lpv << " (" << TMath::NormQuantile(1.-lpv) << "sig)" << std::endl;
  std::cout << "  global p-value (without correlations)   : " << gpUncorr  << " (" << TMath::NormQuantile(1.-gpUncorr) << "sig)" << std::endl;
  std::cout << "  global p-value (including correlations) : " << gpCorr  << " (" << TMath::NormQuantile(1.-gpCorr) << "sig)" << std::endl;
}
	void fillFirstSet (const std::set<std::string> nonterminals, 
		const std::set<std::string> terminals,
		const std::vector<std::string> LHS,
		const std::vector<std::string> RHS,
		const std::vector<std::vector<std::string>>& RHSStringList) {

		auto ntItr = nonterminals.begin();
		auto tItr = terminals.begin();

		for (; ntItr != nonterminals.end(); ++ntItr) {
			if (derivesLambda [*ntItr]) {
				firstSet[*ntItr].insert ("");
			} else {
				firstSet[*ntItr].clear ();
			}
		}

		for (; tItr != terminals.end(); ++tItr) {
			if (tItr->compare("") != 0){
				firstSet[*tItr].insert (*tItr);
			}

			for (ntItr = nonterminals.begin(); ntItr != nonterminals.end(); ++ntItr) {
				if (yields(*ntItr, *tItr, LHS, RHS)) {
					firstSet[*ntItr].insert (*tItr);
				}
			}
		}

		bool changes = true;
		while (changes) {
			auto prevFirstSet = firstSet;

			for (unsigned i = 0; i < LHS.size(); ++i) {
				auto rhsFirst = computeFirst (RHSStringList[i]);
				firstSet[LHS[i]].insert(rhsFirst.begin(), rhsFirst.end());
			}

			if (prevFirstSet == firstSet) {
				changes = false;
			}
		}


	}
	bool derives (const std::string& nonterminal,
		const std::string& terminal,
		const std::vector<std::string>& LHS,
		const std::vector<std::string>& RHS,
		const std::vector<std::vector<std::string> >& RHSStringList) {
		for (unsigned i = 0; i < LHS.size(); ++i) {
			if (LHS[i].compare(nonterminal) == 0) {
				for (unsigned j = 0; j < RHSStringList[i].size(); ++j) {
					// current right hand side element is a terminal
					if (RHSStringList[i][j].compare(terminal) == 0) {
						return true;
					}
					// current right hand side element is a nonterminal
					if (yields (RHSStringList[i][j], terminal, LHS, RHS)) {
						return true;
					}
				}
			}
		}

		return false;
	}