<commit_before>/**************************************************************************
 * Copyright(c) 1998-2000, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/
//.
//.
//.
//.
//.
#include <AliRun.h>
#include <AliRunLoader.h>
#include "AliRunDigitizer.h"
#include <AliLoader.h>
#include "AliLog.h"
#include <AliCDBEntry.h>
#include <AliCDBManager.h>
#include "AliHMPIDDigitizer.h"
#include "AliHMPIDReconstructor.h"
#include "AliHMPIDDigit.h"
#include "AliHMPID.h"
#include "AliHMPIDParam.h"
#include <TRandom.h>
#include <TMath.h>
#include <TTree.h>
#include <TObjArray.h>

ClassImp(AliHMPIDDigitizer)

Bool_t AliHMPIDDigitizer::fgDoNoise=kTRUE;
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void AliHMPIDDigitizer::Exec(Option_t*)
{
// This methode is responsible for merging sdigits to a list of digits
//Disintegration leeds to the fact that one hit affects several neighbouring pads, which means that the same pad might be affected by few hits.
  AliDebug(1,Form("Start with %i input(s) for event %i",fManager->GetNinputs(),fManager->GetOutputEventNr()));
//First we read all sdigits from all inputs
  AliRunLoader *pInRunLoader=0;//in and out Run loaders
  AliLoader    *pInRichLoader=0;//in and out HMPID loaders
  static TClonesArray sdigs("AliHMPIDDigit");//tmp storage for sdigits sum up from all input files
  Int_t total=0;
  for(Int_t inFileN=0;inFileN<fManager->GetNinputs();inFileN++){//files loop
    pInRunLoader  = AliRunLoader::GetRunLoader(fManager->GetInputFolderName(inFileN));          //get run loader from current input
    pInRichLoader = pInRunLoader->GetLoader("HMPIDLoader"); if(pInRichLoader==0) continue;       //no HMPID in this input, check the next input
    if (!pInRunLoader->GetAliRun()) pInRunLoader->LoadgAlice();
    AliHMPID* pInRich=(AliHMPID*)pInRunLoader->GetAliRun()->GetDetector("HMPID");                  //take HMPID from current input
    pInRichLoader->LoadSDigits(); pInRichLoader->TreeS()->GetEntry(0);                          //take list of HMPID sdigits from current input
    AliDebug(1,Form("input %i has %i sdigits",inFileN,pInRich->SdiLst()->GetEntries()));
    for(Int_t i=0;i<pInRich->SdiLst()->GetEntries();i++){                                        //collect sdigits from current input
      AliHMPIDDigit *pSDig=(AliHMPIDDigit*)pInRich->SdiLst()->At(i);
      pSDig->AddTidOffset(fManager->GetMask(inFileN));                                          //apply TID shift since all inputs count tracks independently starting from 0
      new(sdigs[total++]) AliHMPIDDigit(*pSDig);
    }
    pInRichLoader->UnloadSDigits();   pInRich->SdiReset(); //close current input and reset
  }//files loop

  //PH  if(sdigs.GetEntries()==0) return;                                                              //no sdigits collected, nothing to convert

  AliRunLoader *pOutRunLoader  = AliRunLoader::GetRunLoader(fManager->GetOutputFolderName());    //open output stream (only 1 possible)
  AliLoader    *pOutRichLoader = pOutRunLoader->GetLoader("HMPIDLoader");                         //take output HMPID loader
  AliRun *pArun = pOutRunLoader->GetAliRun();
  AliHMPID      *pOutRich       = (AliHMPID*)pArun->GetDetector("HMPID");      //take output HMPID
  pOutRichLoader->MakeTree("D");   pOutRich->MakeBranch("D");                                    //create TreeD in output stream

  Sdi2Dig(&sdigs,pOutRich->DigLst());

  pOutRichLoader->TreeD()->Fill();              //fill the output tree with the list of digits
  pOutRichLoader->WriteDigits("OVERWRITE");     //serialize them to file

  sdigs.Clear();                      //remove all tmp sdigits
  pOutRichLoader->UnloadDigits();   pOutRich->DigReset();
}//Exec()
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void AliHMPIDDigitizer::Sdi2Dig(TClonesArray *pSdiLst,TObjArray *pDigLst)
{
// Converts list of sdigits to 7 lists of digits, one per each chamber
// Arguments: pSDigLst - list of all sdigits
//            pDigLst  - list of 7 lists of digits
//   Returns: none

  TClonesArray *pLst[7]; Int_t iCnt[7];

  for(Int_t i=0;i<7;i++){
    pLst[i]=(TClonesArray*)(*pDigLst)[i];
    iCnt[i]=0; if(pLst[i]->GetEntries()!=0) AliErrorClass("Some of digits lists is not empty");         //in principle those lists should be empty
  }

  TMatrixF *pM[7];

  AliCDBEntry *pDaqSigEnt = AliCDBManager::Instance()->Get("HMPID/Calib/DaqSig");  //contains TObjArray of TObjArray 14 TMatrixF sigmas values for pads
  if(pDaqSigEnt){
    TObjArray *pDaqSig = (TObjArray*)pDaqSigEnt->GetObject();
    for(Int_t iCh=AliHMPIDParam::kMinCh;iCh<=AliHMPIDParam::kMaxCh;iCh++){                  //chambers loop
      pM[iCh] = (TMatrixF*)pDaqSig->At(iCh);
    }
  }
  else{
      for (Int_t iCh=0; iCh<7; iCh++)
        for (Int_t i=0; i<160; i++)
          for (Int_t j=0; j<144; j++)
            (*pM[iCh])(i,j) = 1.0;
     }

  // make noise array
  Float_t arrNoise[7][6][80][48];
  if(fgDoNoise) {
    for (Int_t iCh=AliHMPIDParam::kMinCh;iCh<=AliHMPIDParam::kMaxCh;iCh++)
      for (Int_t iPc=AliHMPIDParam::kMinPc;iPc<=AliHMPIDParam::kMaxPc;iPc++)
        for(Int_t iPx=AliHMPIDParam::kMinPx;iPx<=AliHMPIDParam::kMaxPx;iPx++)
          for(Int_t iPy=AliHMPIDParam::kMinPy;iPy<=AliHMPIDParam::kMaxPy;iPy++){
            Int_t padX = (iPc%2)*AliHMPIDParam::kPadPcX+iPx;
            Int_t padY = (iPc/2)*AliHMPIDParam::kPadPcY+iPy;
            arrNoise[iCh][iPc][iPx][iPy] = gRandom->Gaus(0,(*pM[iCh])(padX,padY));
          }
  }

  pSdiLst->Sort();

  Int_t iPad=-1,iCh=-1,iNdigPad=-1,aTids[3]={-1,-1,-1}; Float_t q=-1;
  for(Int_t i=0;i<pSdiLst->GetEntries();i++){                                                                  //sdigits loop (sorted)
    AliHMPIDDigit *pSdig=(AliHMPIDDigit*)pSdiLst->At(i);                                                       //take current sdigit
    if(pSdig->Pad()==iPad){                                                                                //if the same pad
      q+=pSdig->Q();                                                                                //sum up charge
      iNdigPad++; if(iNdigPad<=3) aTids[iNdigPad-1]=pSdig->GetTrack(0);                                        //collect TID
      continue;
    }
    if(i!=0 && iCh>=AliHMPIDParam::kMinCh && iCh<=AliHMPIDParam::kMaxCh){
      AliHMPIDParam::Instance()->SetThreshold(TMath::Nint(((*pM[iCh])(pSdig->PadChX(),pSdig->PadChY()))*AliHMPIDParam::Nsig()));
      if(AliHMPIDParam::IsOverTh(q)) new((*pLst[iCh])[iCnt[iCh]++]) AliHMPIDDigit(iPad,(Int_t)q,aTids);}  //do not create digit for the very first sdigit

    iPad=pSdig->Pad(); iCh=AliHMPIDParam::A2C(iPad);                                                            //new sdigit comes, reset collectors
    iNdigPad=1;
    aTids[0]=pSdig->GetTrack(0);aTids[1]=aTids[2]=-1;
    q=pSdig->Q();
    if(fgDoNoise) q+=arrNoise[iCh][pSdig->Pc()][pSdig->PadPcX()][pSdig->PadPcY()];
    arrNoise[iCh][pSdig->Pc()][pSdig->PadPcX()][pSdig->PadPcY()]=0;
  }//sdigits loop (sorted)

  if(iCh>=AliHMPIDParam::kMinCh && iCh<=AliHMPIDParam::kMaxCh){
    Int_t pc = AliHMPIDParam::A2P(iPad);
    Int_t padX = (pc%2)*AliHMPIDParam::kPadPcX+AliHMPIDParam::A2X(iPad);
    Int_t padY = (pc/2)*AliHMPIDParam::kPadPcY+AliHMPIDParam::A2Y(iPad);
    AliHMPIDParam::Instance()->SetThreshold(TMath::Nint(((*pM[iCh])(padX,padY))*AliHMPIDParam::Nsig()));
    if(AliHMPIDParam::IsOverTh(q)) new((*pLst[iCh])[iCnt[iCh]++]) AliHMPIDDigit(iPad,(Int_t)q,aTids);}  //add the last one, in case of empty sdigits list q=-1

// add noise pad above threshold with no signal merged...if any
  if(!fgDoNoise) return;

  aTids[0]=aTids[1]=aTids[2]=-1;
  for (Int_t iChCurr=AliHMPIDParam::kMinCh;iChCurr<=AliHMPIDParam::kMaxCh;iChCurr++){
    for (Int_t iPc=AliHMPIDParam::kMinPc;iPc<=AliHMPIDParam::kMaxPc;iPc++)
      for(Int_t iPx=AliHMPIDParam::kMinPx;iPx<=AliHMPIDParam::kMaxPx;iPx++)
        for(Int_t iPy=AliHMPIDParam::kMinPy;iPy<=AliHMPIDParam::kMaxPy;iPy++) {
          Float_t qNoise = arrNoise[iChCurr][iPc][iPx][iPy];
          Int_t padX = (iPc%2)*AliHMPIDParam::kPadPcX+iPx;
          Int_t padY = (iPc/2)*AliHMPIDParam::kPadPcY+iPy;
          AliHMPIDParam::Instance()->SetThreshold(TMath::Nint(((*pM[iChCurr])(padX,padY))*AliHMPIDParam::Nsig()));
          if(AliHMPIDParam::IsOverTh(qNoise)) new((*pLst[iChCurr])[iCnt[iChCurr]++]) AliHMPIDDigit(AliHMPIDParam::Abs(iChCurr,iPc,iPx,iPy),(Int_t)qNoise,aTids);
        }
  }
}//Sdi2Dig()
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
<commit_msg>Minors<commit_after>/**************************************************************************
 * Copyright(c) 1998-2000, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/
//.
//.
//.
//.
//.
#include <AliRun.h>
#include <AliRunLoader.h>
#include "AliRunDigitizer.h"
#include <AliLoader.h>
#include "AliLog.h"
#include <AliCDBEntry.h>
#include <AliCDBManager.h>
#include "AliHMPIDDigitizer.h"
#include "AliHMPIDReconstructor.h"
#include "AliHMPIDDigit.h"
#include "AliHMPID.h"
#include "AliHMPIDParam.h"
#include <TRandom.h>
#include <TMath.h>
#include <TTree.h>
#include <TObjArray.h>

ClassImp(AliHMPIDDigitizer)

Bool_t AliHMPIDDigitizer::fgDoNoise=kTRUE;
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void AliHMPIDDigitizer::Exec(Option_t*)
{
// This methode is responsible for merging sdigits to a list of digits
//Disintegration leeds to the fact that one hit affects several neighbouring pads, which means that the same pad might be affected by few hits.
  AliDebug(1,Form("Start with %i input(s) for event %i",fManager->GetNinputs(),fManager->GetOutputEventNr()));
//First we read all sdigits from all inputs
  AliRunLoader *pInRunLoader=0;//in and out Run loaders
  AliLoader    *pInRichLoader=0;//in and out HMPID loaders
  static TClonesArray sdigs("AliHMPIDDigit");//tmp storage for sdigits sum up from all input files
  Int_t total=0;
  for(Int_t inFileN=0;inFileN<fManager->GetNinputs();inFileN++){//files loop
    pInRunLoader  = AliRunLoader::GetRunLoader(fManager->GetInputFolderName(inFileN));          //get run loader from current input
    pInRichLoader = pInRunLoader->GetLoader("HMPIDLoader"); if(pInRichLoader==0) continue;       //no HMPID in this input, check the next input
    if (!pInRunLoader->GetAliRun()) pInRunLoader->LoadgAlice();
    AliHMPID* pInRich=(AliHMPID*)pInRunLoader->GetAliRun()->GetDetector("HMPID");                  //take HMPID from current input
    pInRichLoader->LoadSDigits(); pInRichLoader->TreeS()->GetEntry(0);                          //take list of HMPID sdigits from current input
    AliDebug(1,Form("input %i has %i sdigits",inFileN,pInRich->SdiLst()->GetEntries()));
    for(Int_t i=0;i<pInRich->SdiLst()->GetEntries();i++){                                        //collect sdigits from current input
      AliHMPIDDigit *pSDig=(AliHMPIDDigit*)pInRich->SdiLst()->At(i);
      pSDig->AddTidOffset(fManager->GetMask(inFileN));                                          //apply TID shift since all inputs count tracks independently starting from 0
      new(sdigs[total++]) AliHMPIDDigit(*pSDig);
    }
    pInRichLoader->UnloadSDigits();   pInRich->SdiReset(); //close current input and reset
  }//files loop

  //PH  if(sdigs.GetEntries()==0) return;                                                              //no sdigits collected, nothing to convert

  AliRunLoader *pOutRunLoader  = AliRunLoader::GetRunLoader(fManager->GetOutputFolderName());    //open output stream (only 1 possible)
  AliLoader    *pOutRichLoader = pOutRunLoader->GetLoader("HMPIDLoader");                         //take output HMPID loader
  AliRun *pArun = pOutRunLoader->GetAliRun();
  AliHMPID      *pOutRich       = (AliHMPID*)pArun->GetDetector("HMPID");      //take output HMPID
  pOutRichLoader->MakeTree("D");   pOutRich->MakeBranch("D");                                    //create TreeD in output stream

  Sdi2Dig(&sdigs,pOutRich->DigLst());

  pOutRichLoader->TreeD()->Fill();              //fill the output tree with the list of digits
  pOutRichLoader->WriteDigits("OVERWRITE");     //serialize them to file

  sdigs.Clear();                      //remove all tmp sdigits
  pOutRichLoader->UnloadDigits();   pOutRich->DigReset();
}//Exec()
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void AliHMPIDDigitizer::Sdi2Dig(TClonesArray *pSdiLst,TObjArray *pDigLst)
{
// Converts list of sdigits to 7 lists of digits, one per each chamber
// Arguments: pSDigLst - list of all sdigits
//            pDigLst  - list of 7 lists of digits
//   Returns: none

  TClonesArray *pLst[7]; Int_t iCnt[7];

  for(Int_t i=0;i<7;i++){
    pLst[i]=(TClonesArray*)(*pDigLst)[i];
    iCnt[i]=0; if(pLst[i]->GetEntries()!=0) AliErrorClass("Some of digits lists is not empty");         //in principle those lists should be empty
  }

  // make noise array
  Float_t arrNoise[7][6][80][48], arrSigmaPed[7][6][80][48];
  if(fgDoNoise) {
    for (Int_t iCh=AliHMPIDParam::kMinCh;iCh<=AliHMPIDParam::kMaxCh;iCh++)
      for (Int_t iPc=AliHMPIDParam::kMinPc;iPc<=AliHMPIDParam::kMaxPc;iPc++)
        for(Int_t iPx=AliHMPIDParam::kMinPx;iPx<=AliHMPIDParam::kMaxPx;iPx++)
          for(Int_t iPy=AliHMPIDParam::kMinPy;iPy<=AliHMPIDParam::kMaxPy;iPy++){
            arrNoise[iCh][iPc][iPx][iPy] = gRandom->Gaus(0,1.);
            arrSigmaPed[iCh][iPc][iPx][iPy] = 1.;
          }

    AliCDBEntry *pDaqSigEnt = AliCDBManager::Instance()->Get("HMPID/Calib/DaqSig");  //contains TObjArray of TObjArray 14 TMatrixF sigmas values for pads

    if(pDaqSigEnt){
      TObjArray *pDaqSig = (TObjArray*)pDaqSigEnt->GetObject();
      for(Int_t iCh=AliHMPIDParam::kMinCh;iCh<=AliHMPIDParam::kMaxCh;iCh++){                  //chambers loop
	TMatrixF *pM = (TMatrixF*)pDaqSig->At(iCh);
	for (Int_t iPc=AliHMPIDParam::kMinPc;iPc<=AliHMPIDParam::kMaxPc;iPc++)
	  for(Int_t iPx=AliHMPIDParam::kMinPx;iPx<=AliHMPIDParam::kMaxPx;iPx++)
	    for(Int_t iPy=AliHMPIDParam::kMinPy;iPy<=AliHMPIDParam::kMaxPy;iPy++){
	      Int_t padX = (iPc%2)*AliHMPIDParam::kPadPcX+iPx;
	      Int_t padY = (iPc/2)*AliHMPIDParam::kPadPcY+iPy;
	      if((*pM)(padX,padY)>0.){
		arrNoise[iCh][iPc][iPx][iPy] = gRandom->Gaus(0,(*pM)(padX,padY));
		arrSigmaPed[iCh][iPc][iPx][iPy] = (*pM)(padX,padY);}
	      else{
		arrNoise[iCh][iPc][iPx][iPy] = gRandom->Gaus(0,1.);
		arrSigmaPed[iCh][iPc][iPx][iPy] = 1.;}
	    }
      }
    }
  }

  pSdiLst->Sort();

  Int_t iPad=-1,iCh=-1,iNdigPad=-1,aTids[3]={-1,-1,-1}; Float_t q=-1;
  for(Int_t i=0;i<pSdiLst->GetEntries();i++){                                                                  //sdigits loop (sorted)
    AliHMPIDDigit *pSdig=(AliHMPIDDigit*)pSdiLst->At(i);                                                       //take current sdigit
    if(pSdig->Pad()==iPad){                                                                                //if the same pad
      q+=pSdig->Q();                                                                                //sum up charge
      iNdigPad++; if(iNdigPad<=3) aTids[iNdigPad-1]=pSdig->GetTrack(0);                                        //collect TID
      continue;
    }
    if(i!=0 && iCh>=AliHMPIDParam::kMinCh && iCh<=AliHMPIDParam::kMaxCh){
      AliHMPIDParam::Instance()->SetThreshold((TMath::Nint(arrSigmaPed[iCh][pSdig->Pc()][pSdig->PadPcX()][pSdig->PadPcY()])*AliHMPIDParam::Nsig()));
      if(AliHMPIDParam::IsOverTh(q)) new((*pLst[iCh])[iCnt[iCh]++]) AliHMPIDDigit(iPad,(Int_t)q,aTids);}  //do not create digit for the very first sdigit

    iPad=pSdig->Pad(); iCh=AliHMPIDParam::A2C(iPad);                                                            //new sdigit comes, reset collectors
    iNdigPad=1;
    aTids[0]=pSdig->GetTrack(0);aTids[1]=aTids[2]=-1;
    q=pSdig->Q();
    if(fgDoNoise) q+=arrNoise[iCh][pSdig->Pc()][pSdig->PadPcX()][pSdig->PadPcY()];
    arrNoise[iCh][pSdig->Pc()][pSdig->PadPcX()][pSdig->PadPcY()]=0;
  }//sdigits loop (sorted)

  if(iCh>=AliHMPIDParam::kMinCh && iCh<=AliHMPIDParam::kMaxCh){
    Int_t pc = AliHMPIDParam::A2P(iPad);
    Int_t px = AliHMPIDParam::A2X(iPad);
    Int_t py = AliHMPIDParam::A2Y(iPad);
    AliHMPIDParam::Instance()->SetThreshold((TMath::Nint(arrSigmaPed[iCh][pc][px][py])*AliHMPIDParam::Nsig()));
    if(AliHMPIDParam::IsOverTh(q)) new((*pLst[iCh])[iCnt[iCh]++]) AliHMPIDDigit(iPad,(Int_t)q,aTids);
  }  //add the last one, in case of empty sdigits list q=-1

// add noise pad above threshold with no signal merged...if any
  if(!fgDoNoise) return;

  aTids[0]=aTids[1]=aTids[2]=-1;
  for (Int_t iChCurr=AliHMPIDParam::kMinCh;iChCurr<=AliHMPIDParam::kMaxCh;iChCurr++){
    for (Int_t iPc=AliHMPIDParam::kMinPc;iPc<=AliHMPIDParam::kMaxPc;iPc++)
      for(Int_t iPx=AliHMPIDParam::kMinPx;iPx<=AliHMPIDParam::kMaxPx;iPx++)
        for(Int_t iPy=AliHMPIDParam::kMinPy;iPy<=AliHMPIDParam::kMaxPy;iPy++) {
          Float_t qNoise = arrNoise[iChCurr][iPc][iPx][iPy];
          AliHMPIDParam::Instance()->SetThreshold((TMath::Nint(arrSigmaPed[iChCurr][iPc][iPx][iPy])*AliHMPIDParam::Nsig()));
          if(AliHMPIDParam::IsOverTh(qNoise)) new((*pLst[iChCurr])[iCnt[iChCurr]++]) AliHMPIDDigit(AliHMPIDParam::Abs(iChCurr,iPc,iPx,iPy),(Int_t)qNoise,aTids);
        }
  }
}//Sdi2Dig()
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
<|endoftext|>


<commit_before>#ifndef STAN_MATH_PRIM_SCAL_FUN_GRAD_2F1_HPP
#define STAN_MATH_PRIM_SCAL_FUN_GRAD_2F1_HPP

#include <stan/math/prim/scal/err/domain_error.hpp>
#include <stan/math/prim/scal/fun/is_nan.hpp>
#include <cmath>

namespace stan {
  namespace math {

    // Gradient of the hypergeometric function 2F1(a, b | c | z)
    // with respect to a and c
    /**
     * Gradient of the hypergeometric function, 2F1(a1, a2, b1, z)
     * with respect to a1 and b1 only.
     *
     * The generalized hypergeometric function is a power series. This
     * implementation computes gradient by computing the power series
     * directly stopping when the series converges to within
     * precision or takes max_steps.
     *
     * If more than max_steps are taken without
     * converging, the function will throw a domain_error.
     *
     * @tparam T type of arguments and result
     * @param[out] gradA11 output argument for partial w.r.t. a1
     * @param[out] gradB1 output argument for partial w.r.t. b1
     * @param[in] a1 a1, see generalized hypergeometric function definition.
     * @param[in] a2 a2, see generalized hypergeometric function definition.
     * @param[in] b1 b1, see generalized hypergeometric function definition.
     * @param[in] z z, see generalized hypergeometric function definition.
     * @param[in] precision precision of the infinite sum. defaults to 1e-6
     * @param[in] max_steps number of steps to take. defaults to 10000
     * @throw @throws std::domain_error if not converged after max_steps
     *
     */
    template<typename T>
    void grad_2F1(T& gradA1, T& gradB1, const T& a1, const T& a2,
      const T& b1, const T& z, T precision = 1e-6, int max_steps = 1e5) {
      using std::fabs;

      gradA1 = 0;
      gradB1 = 0;

      T gradA1old = 0;
      T gradB1old = 0;

      int k = 0;
      T tDak = 1.0 / (a1 - 1);

      do {
        const T r = ( (a1 + k) / (b1 + k) ) * ( (a2 + k) / (k + 1) ) * z;
        tDak = r * tDak * (a1 + (k - 1)) / (a1 + k);

        if (is_nan(r) || r == 0)
          break;

        gradA1old = r * gradA1old + tDak;
        gradB1old = r * gradB1old - tDak * ((a1 + k) / (b1 + k));

        gradA1 += gradA1old;
        gradB1 += gradB1old;

        ++k;
        if (k >= max_steps) {
          domain_error("grad_2F1", "k (internal counter)", max_steps,
            "exceeded ",
            " iterations, hypergeometric function did not converge.");
        }
      } while (fabs(tDak * (a1 + (k - 1)) ) > precision);
    }

  }
}
#endif
<commit_msg>Fix code tag.<commit_after>#ifndef STAN_MATH_PRIM_SCAL_FUN_GRAD_2F1_HPP
#define STAN_MATH_PRIM_SCAL_FUN_GRAD_2F1_HPP

#include <stan/math/prim/scal/err/domain_error.hpp>
#include <stan/math/prim/scal/fun/is_nan.hpp>
#include <cmath>

namespace stan {
  namespace math {

    // Gradient of the hypergeometric function 2F1(a, b | c | z)
    // with respect to a and c
    /**
     * Gradient of the hypergeometric function, 2F1(a1, a2, b1, z)
     * with respect to a1 and b1 only.
     *
     * The generalized hypergeometric function is a power series. This
     * implementation computes gradient by computing the power series
     * directly stopping when the series converges to within
     * precision or takes max_steps.
     *
     * If more than max_steps are taken without
     * converging, the function will throw a domain_error.
     *
     * @tparam T type of arguments and result
     * @param[out] gradA11 output argument for partial w.r.t. a1
     * @param[out] gradB1 output argument for partial w.r.t. b1
     * @param[in] a1 a1, see generalized hypergeometric function definition.
     * @param[in] a2 a2, see generalized hypergeometric function definition.
     * @param[in] b1 b1, see generalized hypergeometric function definition.
     * @param[in] z z, see generalized hypergeometric function definition.
     * @param[in] precision precision of the infinite sum. defaults to 1e-6
     * @param[in] max_steps number of steps to take. defaults to 10000
     * @throw @throws std::domain_error if not converged after max_steps
     *
     */
    template<typename T>
    void grad_2F1(T& gradA1, T& gradB1, const T& a1, const T& a2,
      const T& b1, const T& z, T precision = 1e-6, int max_steps = 1e5) {
      using std::fabs;

      gradA1 = 0;
      gradB1 = 0;

      T gradA1old = 0;
      T gradB1old = 0;

      int k = 0;
      T tDak = 1.0 / (a1 - 1);

      do {
        const T r = ( (a1 + k) / (b1 + k) ) * ( (a2 + k) / (k + 1) ) * z;
        tDak = r * tDak * (a1 + (k - 1)) / (a1 + k);

        if (is_nan(r) || r == 0)
          break;

        gradA1old = r * gradA1old + tDak;
        gradB1old = r * gradB1old - tDak * ((a1 + k) / (b1 + k));

        gradA1 += gradA1old;
        gradB1 += gradB1old;

        ++k;
        if (k >= max_steps) {
          domain_error("grad_2F1", "k (internal counter)", max_steps,
            "exceeded ",
            " iterations, hypergeometric function did not converge.");
        }
      } while (fabs(tDak * (a1 + (k - 1)) ) > precision);
    }

  }
}
#endif
<|endoftext|>


<commit_before>#ifndef STAN_MATH_REV_SCAL_FUNCTOR_REDUCE_SUM_HPP
#define STAN_MATH_REV_SCAL_FUNCTOR_REDUCE_SUM_HPP

#include <stan/math/prim/meta.hpp>
#include <stan/math/rev/fun/typedefs.hpp>

#include <tbb/task_arena.h>
#include <tbb/parallel_reduce.h>
#include <tbb/blocked_range.h>

#include <iostream>
#include <iterator>
#include <vector>

namespace stan {
namespace math {
namespace internal {

template <typename ReduceFunction, typename ReturnType, typename M,
          typename... Args>
struct reduce_sum_impl<ReduceFunction, require_var_t<ReturnType>, ReturnType, M,
                       Args...> {
  template <typename T>
  static T& deep_copy(T& arg) {
    return arg;
  }

  static var deep_copy(const var& arg) { return var(arg.val()); }

  static std::vector<var> deep_copy(const std::vector<var>& arg) {
    std::vector<var> copy(arg.size());
    for (size_t i = 0; i < arg.size(); ++i) {
      copy[i] = arg[i].val();
    }
    return copy;
  }

  template <int RowType, int ColType>
  static Eigen::Matrix<var, RowType, ColType> deep_copy(
      const Eigen::Matrix<var, RowType, ColType>& arg) {
    Eigen::Matrix<var, RowType, ColType> copy(arg.size());
    for (size_t i = 0; i < arg.size(); ++i) {
      copy(i) = arg(i).val();
    }
    return copy;
  }

  // TODO(Steve): Move this somewhere smarter
  // Fails to compile if type T does not have member operator(Integral)
  template <typename T>
  using operator_paren_access_t = decltype(std::declval<T>()(int{}));

  template <typename... Pargs>
  static double* accumulate_adjoints(double* dest, const var& x,
                                     const Pargs&... args) {
    *dest += x.adj();
    return accumulate_adjoints(dest + 1, args...);
  }

  // Works with anything that has operator[Integral] defined
  template <typename... Pargs, typename Vec,
            require_vector_like_vt<is_var, Vec>...>
  static double* accumulate_adjoints(double* dest, const Vec& x,
                                     const Pargs&... args) {
    for (size_t i = 0; i < x.size(); ++i) {
      dest[i] += x[i].adj();
    }
    return accumulate_adjoints(dest + x.size(), args...);
  }

  // Works on anything with a operator()
  template <typename... Pargs, typename Mat,
            require_t<is_detected<Mat, operator_paren_access_t>>...,
            require_t<is_var<value_type_t<Mat>>>...>
  static double* accumulate_adjoints(double* dest, const Mat& x,
                                     const Pargs&... args) {
    Eigen::Map<matrix_vi>(dest, x.size()) += x.adj();
    return accumulate_adjoints(dest + x.size(), args...);
  }

  // Anything with a scalar type of Arithmetic gets tossed
  template <typename Arith, require_arithmetic_t<scalar_type_t<Arith>>...,
            typename... Pargs>
  static double* accumulate_adjoints(double* dest, Arith&& x,
                                     const Pargs&... args) {
    return accumulate_adjoints(dest, args...);
  }

  static double* accumulate_adjoints(double* x) { return x; }

  struct recursive_reducer {
    size_t num_shared_terms_;
    const std::vector<M>& vmapped_;
    std::tuple<const Args&...> args_tuple_;
    size_t tuple_size_ = sizeof...(Args);

    double sum_;
    Eigen::VectorXd args_adjoints_;

    recursive_reducer(size_t num_shared_terms, const std::vector<M>& vmapped,
                      const Args&... args)
        : num_shared_terms_(num_shared_terms),
          vmapped_(vmapped),
          args_tuple_(args...),
          sum_(0.0),
          args_adjoints_(Eigen::VectorXd::Zero(num_shared_terms_)) {}

    recursive_reducer(recursive_reducer& other, tbb::split)
        : num_shared_terms_(other.num_shared_terms_),
          vmapped_(other.vmapped_),
          args_tuple_(other.args_tuple_),
          sum_(0.0),
          args_adjoints_(Eigen::VectorXd::Zero(num_shared_terms_)) {}

    void operator()(const tbb::blocked_range<size_t>& r) {
      if (r.empty())
        return;

      auto start = vmapped_.begin();
      std::advance(start, r.begin());
      auto end = vmapped_.begin();
      std::advance(end, r.end());
      std::vector<M> sub_slice(start, end);

      try {
        start_nested();

        // create a deep copy of all var's so that these are not
        // linked to any outer AD tree

        auto args_tuple_local_copy = apply(
            [&](auto&&... args) { return std::make_tuple(deep_copy(args)...); },
            args_tuple_);

        var sub_sum_v = apply(
            [&r, &sub_slice](auto&&... args) {
              return ReduceFunction()(r.begin(), r.end() - 1, sub_slice,
                                      args...);
            },
            args_tuple_local_copy);

        sub_sum_v.grad();

        sum_ += sub_sum_v.val();

        // This should accumulate the adjoints from args_tuple_local_copy into
        //  the memory of args_adjoints_
        apply(
            [&](auto&&... args) {
              return accumulate_adjoints(args_adjoints_.data(), args...);
            },
            args_tuple_local_copy);
      } catch (const std::exception& e) {
        recover_memory_nested();
        throw;
      }
      recover_memory_nested();
    }

    void join(const recursive_reducer& rhs) {
      sum_ += rhs.sum_;
      args_adjoints_ += rhs.args_adjoints_;
    }
  };

  // Fails to compile if type T does not have callable member size()
  template <typename T>
  using member_size_t = decltype(std::declval<T>().size());

  // TODO(Steve): add requires for generic containers
  template <typename Container,
            require_t<is_detected<Container, member_size_t>>...,
            require_t<is_var<value_type_t<Container>>>..., typename... Pargs>
  size_t count_var_impl(size_t count, const Container& x,
                        const Pargs&... args) const {
    return count_var_impl(count + x.size(), args...);
  }

  // TODO(Steve): add this back if you want it cause Ben commented it out cause
  //  it was causing ambiguities
  /*template <typename Container,
            require_t<is_detected<Container, member_size_t>>...,
            require_t<std::is_arithmetic<value_type_t<Container>>>...,
            typename... Pargs>
  size_t count_var_impl(size_t count, const Container& x,
                        const Pargs&... args) const {
    return count_var_impl(count, args...);
    }*/

  template <typename... Pargs>
  size_t count_var_impl(size_t count, const var& x,
                        const Pargs&... args) const {
    return count_var_impl(count + 1, args...);
  }

  template <typename... Pargs, typename Arith,
            require_arithmetic_t<scalar_type_t<Arith>>...>
  size_t count_var_impl(size_t count, Arith& x, const Pargs&... args) const {
    return count_var_impl(count, args...);
  }

  size_t count_var_impl(size_t count) const { return count; }

  /**
   * Count the number of scalars of type T in the input argument list
   *
   * @tparam Pargs Types of input arguments
   * @return Number of scalars of type T in input
   */
  template <typename... Pargs>
  size_t count_var(const Pargs&... args) const {
    return count_var_impl(0, args...);
  }

  template <typename... Pargs>
  void save_varis(vari** dest, const var& x, const Pargs&... args) const {
    *dest = x.vi_;
    save_varis(dest + 1, args...);
  }

  template <typename... Pargs, typename Vec,
            require_vector_like_vt<is_var, Vec>...>
  void save_varis(vari** dest, const Vec& x, const Pargs&... args) const {
    for (size_t i = 0; i < x.size(); ++i) {
      dest[i] = x[i].vi_;
    }
    save_varis(dest + x.size(), args...);
  }

  template <typename... Pargs, typename Mat,
            require_t<is_detected<Mat, operator_paren_access_t>>...,
            require_t<is_var<value_type_t<Mat>>>...>
  void save_varis(vari** dest, const Mat& x, const Pargs&... args) const {
    for (size_t i = 0; i < x.size(); ++i) {
      dest[i] = x(i).vi_;
    }
    save_varis(dest + x.size(), args...);
  }

  template <typename R, require_arithmetic_t<scalar_type_t<R>>...,
            typename... Pargs>
  void save_varis(vari** dest, const R& x, const Pargs&... args) const {
    save_varis(dest, args...);
  }

  void save_varis(vari**) const {}

  var operator()(const std::vector<M>& vmapped, std::size_t grainsize,
                 const Args&... args) const {
    const std::size_t num_jobs = vmapped.size();

    if (num_jobs == 0)
      return var(0.0);

    const std::size_t num_sliced_terms = count_var(vmapped);
    const std::size_t num_shared_terms = count_var(args...);

    auto vmapped_copy = deep_copy(vmapped);

    recursive_reducer worker(num_shared_terms, vmapped_copy, args...);

#ifdef STAN_DETERMINISTIC
    tbb::static_partitioner partitioner;
    tbb::parallel_deterministic_reduce(
        tbb::blocked_range<std::size_t>(0, num_jobs, grainsize), worker,
        partitioner);
#else
    tbb::parallel_reduce(
        tbb::blocked_range<std::size_t>(0, num_jobs, grainsize), worker);
#endif

    vari** varis = ChainableStack::instance_->memalloc_.alloc_array<vari*>(
        num_sliced_terms + num_shared_terms);
    double* partials = ChainableStack::instance_->memalloc_.alloc_array<double>(
        num_sliced_terms + num_shared_terms);

    save_varis(varis, vmapped);
    save_varis(varis + num_sliced_terms, args...);

    for (size_t i = 0; i < num_sliced_terms; ++i)
      partials[i] = 0.0;
    accumulate_adjoints(partials, vmapped_copy);

    for (size_t i = 0; i < num_shared_terms; ++i) {
      partials[num_sliced_terms + i] = worker.args_adjoints_(i);
    }

    return var(new precomputed_gradients_vari(
        worker.sum_, num_sliced_terms + num_shared_terms, varis, partials));
  }
};
}  // namespace internal

}  // namespace math
}  // namespace stan

#endif
<commit_msg>make things work with proper cleanup<commit_after>#ifndef STAN_MATH_REV_SCAL_FUNCTOR_REDUCE_SUM_HPP
#define STAN_MATH_REV_SCAL_FUNCTOR_REDUCE_SUM_HPP

#include <stan/math/prim/meta.hpp>
#include <stan/math/rev/fun/typedefs.hpp>

#include <tbb/task_arena.h>
#include <tbb/parallel_reduce.h>
#include <tbb/blocked_range.h>

#include <iostream>
#include <iterator>
#include <vector>

namespace stan {
namespace math {
namespace internal {

template <typename ReduceFunction, typename ReturnType, typename M,
          typename... Args>
struct reduce_sum_impl<ReduceFunction, require_var_t<ReturnType>, ReturnType, M,
                       Args...> {
  template <typename T>
  static T& deep_copy(T& arg) {
    return arg;
  }

  static var deep_copy(const var& arg) { return var(arg.val()); }

  static std::vector<var> deep_copy(const std::vector<var>& arg) {
    std::vector<var> copy(arg.size());
    for (size_t i = 0; i < arg.size(); ++i) {
      copy[i] = arg[i].val();
    }
    return copy;
  }

  template <int RowType, int ColType>
  static Eigen::Matrix<var, RowType, ColType> deep_copy(
      const Eigen::Matrix<var, RowType, ColType>& arg) {
    Eigen::Matrix<var, RowType, ColType> copy(arg.size());
    for (size_t i = 0; i < arg.size(); ++i) {
      copy(i) = arg(i).val();
    }
    return copy;
  }

  // TODO(Steve): Move this somewhere smarter
  // Fails to compile if type T does not have member operator(Integral)
  template <typename T>
  using operator_paren_access_t = decltype(std::declval<T>()(int{}));

  template <typename... Pargs>
  static double* accumulate_adjoints(double* dest, const var& x,
                                     const Pargs&... args) {
    *dest += x.adj();
    return accumulate_adjoints(dest + 1, args...);
  }

  // Works with anything that has operator[Integral] defined
  template <typename... Pargs, typename Vec,
            require_vector_like_vt<is_var, Vec>...>
  static double* accumulate_adjoints(double* dest, const Vec& x,
                                     const Pargs&... args) {
    for (size_t i = 0; i < x.size(); ++i) {
      dest[i] += x[i].adj();
    }
    return accumulate_adjoints(dest + x.size(), args...);
  }

  // Works on anything with a operator()
  template <typename... Pargs, typename Mat,
            require_t<is_detected<Mat, operator_paren_access_t>>...,
            require_t<is_var<value_type_t<Mat>>>...>
  static double* accumulate_adjoints(double* dest, const Mat& x,
                                     const Pargs&... args) {
    Eigen::Map<matrix_vi>(dest, x.size()) += x.adj();
    return accumulate_adjoints(dest + x.size(), args...);
  }

  // Anything with a scalar type of Arithmetic gets tossed
  template <typename Arith, require_arithmetic_t<scalar_type_t<Arith>>...,
            typename... Pargs>
  static double* accumulate_adjoints(double* dest, Arith&& x,
                                     const Pargs&... args) {
    return accumulate_adjoints(dest, args...);
  }

  static double* accumulate_adjoints(double* x) { return x; }

  struct recursive_reducer {
    size_t num_shared_terms_;
    const std::vector<M>& vmapped_;
    std::tuple<const Args&...> args_tuple_;
    size_t tuple_size_ = sizeof...(Args);

    double sum_;
    Eigen::VectorXd args_adjoints_;

    recursive_reducer(size_t num_shared_terms, const std::vector<M>& vmapped,
                      const Args&... args)
        : num_shared_terms_(num_shared_terms),
          vmapped_(vmapped),
          args_tuple_(args...),
          sum_(0.0),
          args_adjoints_(Eigen::VectorXd::Zero(num_shared_terms_)) {}

    recursive_reducer(recursive_reducer& other, tbb::split)
        : num_shared_terms_(other.num_shared_terms_),
          vmapped_(other.vmapped_),
          args_tuple_(other.args_tuple_),
          sum_(0.0),
          args_adjoints_(Eigen::VectorXd::Zero(num_shared_terms_)) {}

    void operator()(const tbb::blocked_range<size_t>& r) {
      if (r.empty())
        return;

      auto start = vmapped_.begin();
      std::advance(start, r.begin());
      auto end = vmapped_.begin();
      std::advance(end, r.end());

      try {
        start_nested();

        // create a deep copy of all var's so that these are not
        // linked to any outer AD tree
        const std::vector<M> sub_slice(start, end);

        auto args_tuple_local_copy = apply(
            [&](auto&&... args) { return std::make_tuple(deep_copy(args)...); },
            args_tuple_);

        var sub_sum_v = apply(
            [&r, &sub_slice](auto&&... args) {
              return ReduceFunction()(r.begin(), r.end() - 1, sub_slice,
                                      args...);
            },
            args_tuple_local_copy);

        sub_sum_v.grad();

        sum_ += sub_sum_v.val();

        // This should accumulate the adjoints from args_tuple_local_copy into
        //  the memory of args_adjoints_
        apply(
            [&](auto&&... args) {
              return accumulate_adjoints(args_adjoints_.data(), args...);
            },
            args_tuple_local_copy);
      } catch (const std::exception& e) {
        recover_memory_nested();
        throw;
      }
      recover_memory_nested();
    }

    void join(const recursive_reducer& rhs) {
      sum_ += rhs.sum_;
      args_adjoints_ += rhs.args_adjoints_;
    }
  };

  // Fails to compile if type T does not have callable member size()
  template <typename T>
  using member_size_t = decltype(std::declval<T>().size());

  // TODO(Steve): add requires for generic containers
  template <typename Container,
            require_t<is_detected<Container, member_size_t>>...,
            require_t<is_var<value_type_t<Container>>>..., typename... Pargs>
  size_t count_var_impl(size_t count, const Container& x,
                        const Pargs&... args) const {
    return count_var_impl(count + x.size(), args...);
  }

  // TODO(Steve): add this back if you want it cause Ben commented it out cause
  //  it was causing ambiguities
  /*template <typename Container,
            require_t<is_detected<Container, member_size_t>>...,
            require_t<std::is_arithmetic<value_type_t<Container>>>...,
            typename... Pargs>
  size_t count_var_impl(size_t count, const Container& x,
                        const Pargs&... args) const {
    return count_var_impl(count, args...);
    }*/

  template <typename... Pargs>
  size_t count_var_impl(size_t count, const var& x,
                        const Pargs&... args) const {
    return count_var_impl(count + 1, args...);
  }

  template <typename... Pargs, typename Arith,
            require_arithmetic_t<scalar_type_t<Arith>>...>
  size_t count_var_impl(size_t count, Arith& x, const Pargs&... args) const {
    return count_var_impl(count, args...);
  }

  size_t count_var_impl(size_t count) const { return count; }

  /**
   * Count the number of scalars of type T in the input argument list
   *
   * @tparam Pargs Types of input arguments
   * @return Number of scalars of type T in input
   */
  template <typename... Pargs>
  size_t count_var(const Pargs&... args) const {
    return count_var_impl(0, args...);
  }

  template <typename... Pargs>
  void save_varis(vari** dest, const var& x, const Pargs&... args) const {
    *dest = x.vi_;
    save_varis(dest + 1, args...);
  }

  template <typename... Pargs, typename Vec,
            require_vector_like_vt<is_var, Vec>...>
  void save_varis(vari** dest, const Vec& x, const Pargs&... args) const {
    for (size_t i = 0; i < x.size(); ++i) {
      dest[i] = x[i].vi_;
    }
    save_varis(dest + x.size(), args...);
  }

  template <typename... Pargs, typename Mat,
            require_t<is_detected<Mat, operator_paren_access_t>>...,
            require_t<is_var<value_type_t<Mat>>>...>
  void save_varis(vari** dest, const Mat& x, const Pargs&... args) const {
    for (size_t i = 0; i < x.size(); ++i) {
      dest[i] = x(i).vi_;
    }
    save_varis(dest + x.size(), args...);
  }

  template <typename R, require_arithmetic_t<scalar_type_t<R>>...,
            typename... Pargs>
  void save_varis(vari** dest, const R& x, const Pargs&... args) const {
    save_varis(dest, args...);
  }

  void save_varis(vari**) const {}

  var operator()(const std::vector<M>& vmapped, std::size_t grainsize,
                 const Args&... args) const {
    const std::size_t num_jobs = vmapped.size();

    if (num_jobs == 0)
      return var(0.0);

    const std::size_t num_sliced_terms = count_var(vmapped);
    const std::size_t num_shared_terms = count_var(args...);

    vari** varis = ChainableStack::instance_->memalloc_.alloc_array<vari*>(
        num_sliced_terms + num_shared_terms);
    double* partials = ChainableStack::instance_->memalloc_.alloc_array<double>(
        num_sliced_terms + num_shared_terms);

    double sum = 0;

    try {
      start_nested();

      auto vmapped_copy = deep_copy(vmapped);

      recursive_reducer worker(num_shared_terms, vmapped_copy, args...);

#ifdef STAN_DETERMINISTIC
      tbb::static_partitioner partitioner;
      tbb::parallel_deterministic_reduce(
          tbb::blocked_range<std::size_t>(0, num_jobs, grainsize), worker,
          partitioner);
#else
      tbb::parallel_reduce(
          tbb::blocked_range<std::size_t>(0, num_jobs, grainsize), worker);
#endif

      save_varis(varis, vmapped);
      save_varis(varis + num_sliced_terms, args...);

      for (size_t i = 0; i < num_sliced_terms; ++i)
        partials[i] = 0.0;
      accumulate_adjoints(partials, vmapped_copy);

      for (size_t i = 0; i < num_shared_terms; ++i) {
        partials[num_sliced_terms + i] = worker.args_adjoints_(i);
      }

      sum = worker.sum_;

    } catch (const std::exception& e) {
      recover_memory_nested();
      throw;
    }
    recover_memory_nested();

    return var(new precomputed_gradients_vari(
        sum, num_sliced_terms + num_shared_terms, varis, partials));
  }
};
}  // namespace internal

}  // namespace math
}  // namespace stan

#endif
<|endoftext|>


<commit_before>/**
 * @file
 *
 * @brief Tests for leaf plugin
 *
 * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
 *
 */

#include "leaf.hpp"

#include <kdbmodule.h>
#include <kdbprivate.h>

#include <tests.hpp>

using ckdb::keyNew;

using CppKeySet = kdb::KeySet;
using CppKey = kdb::Key;

// -- Macros -------------------------------------------------------------------------------------------------------------------------------

#define OPEN_PLUGIN(parentName, filepath)                                                                                \
	CppKeySet modules{ 0, KS_END };                                                                                \
	CppKeySet config{ 0, KS_END };                                                                                \
	elektraModulesInit (modules.getKeySet (), 0);                                                                                \
	CppKey parent{ parentName, KEY_VALUE, filepath, KEY_END };                                                                         \
	Plugin * plugin = elektraPluginOpen ("leaf", modules.getKeySet (), config.getKeySet (), *parent);                                  \
	exit_if_fail (plugin != NULL, "Could not open leaf plugin");

#define CLOSE_PLUGIN()                                                                                \
	ksDel (modules.release ());                                                                                \
	config.release ();                                                                                \
	elektraPluginClose (plugin, 0);                                                                                \
	elektraModulesClose (modules.getKeySet (), 0)

#define PREFIX "user/tests/leaf/"

// -- Functions ----------------------------------------------------------------------------------------------------------------------------

void test_set (CppKeySet keys, CppKeySet expected, int const status = ELEKTRA_PLUGIN_STATUS_SUCCESS)
{
	OPEN_PLUGIN (PREFIX, "file/path"); //! OCLint (too few branches switch, empty if statement)

	succeed_if_same (plugin->kdbSet (plugin, keys.getKeySet (), *parent), //! OCLint (too few branches switch, empty if statement)
			 status, "Call of `kdbSet` failed");

	compare_keyset (keys, expected); //! OCLint (too few branches switch)

	CLOSE_PLUGIN ();
}

void test_get (CppKeySet keys, CppKeySet expected, int const status = ELEKTRA_PLUGIN_STATUS_SUCCESS)
{
	OPEN_PLUGIN (PREFIX, "file/path"); //! OCLint (too few branches switch, empty if statement)

	succeed_if_same (plugin->kdbGet (plugin, keys.getKeySet (), *parent), //! OCLint (too few branches switch, empty if statement)
			 status, "Call of `kdbGet` failed");

	compare_keyset (keys, expected); //! OCLint (too few branches switch)

	CLOSE_PLUGIN ();
}

// -- Tests --------------------------------------------------------------------------------------------------------------------------------

TEST (leaf, basics)
{
	OPEN_PLUGIN ("system/elektra/modules/leaf", "")

	CppKeySet keys{ 0, KS_END };
	succeed_if_same (plugin->kdbGet (plugin, keys.getKeySet (), *parent), ELEKTRA_PLUGIN_STATUS_SUCCESS,
			 "Unable to retrieve plugin contract");

	CLOSE_PLUGIN ();
}

TEST (leaf, get)
{
	test_get (
#include "leaf/simple_set.hpp"
		,
#include "leaf/simple_get.hpp"
	);
}

TEST (leaf, set)
{
	test_set (
#include "leaf/empty.hpp"
		,
#include "leaf/empty.hpp"
		, ELEKTRA_PLUGIN_STATUS_NO_UPDATE);

	test_set (
#include "leaf/simple_get.hpp"
		,
#include "leaf/simple_set.hpp"
	);
}
<commit_msg>Leaf: Add roundtrip test<commit_after>/**
 * @file
 *
 * @brief Tests for leaf plugin
 *
 * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
 *
 */

#include "leaf.hpp"

#include <kdbmodule.h>
#include <kdbprivate.h>

#include <tests.hpp>

using ckdb::keyNew;

using CppKeySet = kdb::KeySet;
using CppKey = kdb::Key;

// -- Macros -------------------------------------------------------------------------------------------------------------------------------

#define OPEN_PLUGIN(parentName, filepath)                                                                                \
	CppKeySet modules{ 0, KS_END };                                                                                \
	CppKeySet config{ 0, KS_END };                                                                                \
	elektraModulesInit (modules.getKeySet (), 0);                                                                                \
	CppKey parent{ parentName, KEY_VALUE, filepath, KEY_END };                                                                         \
	Plugin * plugin = elektraPluginOpen ("leaf", modules.getKeySet (), config.getKeySet (), *parent);                                  \
	exit_if_fail (plugin != NULL, "Could not open leaf plugin");

#define CLOSE_PLUGIN()                                                                                \
	ksDel (modules.release ());                                                                                \
	config.release ();                                                                                \
	elektraPluginClose (plugin, 0);                                                                                \
	elektraModulesClose (modules.getKeySet (), 0)

#define PREFIX "user/tests/leaf/"

// -- Functions ----------------------------------------------------------------------------------------------------------------------------

void test_set (CppKeySet keys, CppKeySet expected, int const status = ELEKTRA_PLUGIN_STATUS_SUCCESS)
{
	OPEN_PLUGIN (PREFIX, "file/path"); //! OCLint (too few branches switch, empty if statement)

	succeed_if_same (plugin->kdbSet (plugin, keys.getKeySet (), *parent), //! OCLint (too few branches switch, empty if statement)
			 status, "Call of `kdbSet` failed");

	compare_keyset (keys, expected); //! OCLint (too few branches switch)

	CLOSE_PLUGIN ();
}

void test_get (CppKeySet keys, CppKeySet expected, int const status = ELEKTRA_PLUGIN_STATUS_SUCCESS)
{
	OPEN_PLUGIN (PREFIX, "file/path"); //! OCLint (too few branches switch, empty if statement)

	succeed_if_same (plugin->kdbGet (plugin, keys.getKeySet (), *parent), //! OCLint (too few branches switch, empty if statement)
			 status, "Call of `kdbGet` failed");

	compare_keyset (keys, expected); //! OCLint (too few branches switch)

	CLOSE_PLUGIN ();
}

void test_roundtrip (CppKeySet keys, int const status = ELEKTRA_PLUGIN_STATUS_SUCCESS)
#ifdef __llvm__
	__attribute__ ((annotate ("oclint:suppress[high ncss method]")))
#endif
{
	CppKeySet input = keys.dup ();

	OPEN_PLUGIN (PREFIX, "file/path"); //! OCLint (too few branches switch, empty if statement)

	succeed_if_same (plugin->kdbSet (plugin, keys.getKeySet (), *parent), //! OCLint (too few branches switch, empty if statement)
			 status, "Call of `kdbSet` failed");

	succeed_if_same (plugin->kdbGet (plugin, keys.getKeySet (), *parent), //! OCLint (too few branches switch, empty if statement)
			 status, "Call of `kdbGet` failed");

	compare_keyset (input, keys); //! OCLint (too few branches switch)

	CLOSE_PLUGIN ();
}

// -- Tests --------------------------------------------------------------------------------------------------------------------------------

TEST (leaf, basics)
{
	OPEN_PLUGIN ("system/elektra/modules/leaf", "")

	CppKeySet keys{ 0, KS_END };
	succeed_if_same (plugin->kdbGet (plugin, keys.getKeySet (), *parent), ELEKTRA_PLUGIN_STATUS_SUCCESS,
			 "Unable to retrieve plugin contract");

	CLOSE_PLUGIN ();
}

TEST (leaf, get)
{
	test_get (
#include "leaf/simple_set.hpp"
		,
#include "leaf/simple_get.hpp"
	);
}

TEST (leaf, set)
{
	test_set (
#include "leaf/empty.hpp"
		,
#include "leaf/empty.hpp"
		, ELEKTRA_PLUGIN_STATUS_NO_UPDATE);

	test_set (
#include "leaf/simple_get.hpp"
		,
#include "leaf/simple_set.hpp"
	);
}

TEST (leaf, roundtrip)
{
	test_roundtrip (
#include "leaf/simple_get.hpp"
	);
}
<|endoftext|>


<commit_before>#include "Dial.h"
//Constructor
Dial::Dial(){
	if(buf = (char *)malloc(BUF_SIZE+1)) memset(buf,0,BUF_SIZE+1); //Had to add one more, to avoid some bug
}

Dial::Dial(unsigned int radius, unsigned int minLimit, unsigned int setpoint, unsigned int maxLimit)
{
	if(buf = (char *)malloc(BUF_SIZE+1)) memset(buf,0,BUF_SIZE+1); //Had to add one more, to avoid some bug
	this->setSize(radius);
	this->setLimits(minLimit,setpoint,maxLimit);
	this->setColors(BLACK,BLUE,WHITE);
	init();
}

Dial::~Dial(){}

//Methods
void Dial::init(){
	Indicator::init();
	type = 0x21;
	this->hiLimit = scaleMax;
	this->lowLimit = scaleMin;
	this->currentValue = setpoint;
	this->maxDegree = 315;
	this->minDegree = 585;
	this->tickSize = 10;
	this->gap = 5;
	this->tickDegree = 45;
	this->showVal = true;
	this->showTicks = true;
}

void Dial::clear(){
	for(int i = BUF_SIZE-1; i >= 0; i--)
	{
			buf[i] = 0;
	}
}

void Dial::setSize(int radius){
	this->w = radius*2;
	this->h = radius*2;
	this->radius = radius;
}

void Dial::drawBorder(){
	int color = this->fgColor;
	/*
	if(currentValue >= hiLimit) color = hiLimitColor;
	if(currentValue <= lowLimit) color = lowLimitColor;

	/*
	for(int i=0; i < this->borderWidth; i++)
	{
  	myCanvas->tft->drawCircle(x,y,radius-i,color);
  }
	*/
	myCanvas->tft->fillCircle(x,y,radius,color);
	//myCanvas->tft->fillCircle(x,y,radius-borderWidth,bgColor);
	//drawFace();
}

void Dial::drawFace(){
	// Draw face
	myCanvas->tft->fillCircle(x,y,radius - this->borderWidth,this->bgColor);

	// Draw border
	//drawBorder();

	int X1,Y1,X2,Y2;

  // Draw ticks
	if(showTicks){
		for(int i=maxDegree; i<=minDegree; i+=tickDegree)
		{
			X1 = getX(x,i,radius-tickSize);
			Y1 = getY(y,i,radius-tickSize);
			X2 = getX(x,i,radius-borderWidth);
			Y2 = getY(y,i,radius-borderWidth);
			myCanvas->tft->drawLine(X1,Y1,X2,Y2,borderColor);
		}
	}else{
		int i = minDegree;
		X1 = getX(x,i,radius-tickSize);
		Y1 = getY(y,i,radius-tickSize);
		X2 = getX(x,i,radius-borderWidth);
		Y2 = getY(y,i,radius-borderWidth);
		myCanvas->tft->drawLine(X1,Y1,X2,Y2,borderColor);

		i = maxDegree;
		X1 = getX(x,i,radius-tickSize);
		Y1 = getY(y,i,radius-tickSize);
		X2 = getX(x,i,radius-borderWidth);
		Y2 = getY(y,i,radius-borderWidth);
		myCanvas->tft->drawLine(X1,Y1,X2,Y2,borderColor);
	}

	// Draw Setpoint line
	if(setpoint){
		int i = map(setpoint,scaleMin,scaleMax,minDegree,maxDegree);
		X1 = getX(x,i,radius-tickSize);
		Y1 = getY(y,i,radius-tickSize);
		X2 = getX(x,i,radius-borderWidth);
		Y2 = getY(y,i,radius-borderWidth);
		myCanvas->tft->drawLine(X1,Y1,X2,Y2,setpointColor);
	}

	// Draw High limit line
	if(hiLimit < scaleMax){
		int i = map(hiLimit,scaleMin,scaleMax,minDegree,maxDegree);
		X1 = getX(x,i,radius-tickSize);
		Y1 = getY(y,i,radius-tickSize);
		X2 = getX(x,i,radius-borderWidth);
		Y2 = getY(y,i,radius-borderWidth);
		myCanvas->tft->drawLine(X1,Y1,X2,Y2,hiLimitColor);
	}

	// Draw Low Limit line
	if(lowLimit > scaleMin){
		int i = map(lowLimit,scaleMin,scaleMax,minDegree,maxDegree);
		X1 = getX(x,i,radius-tickSize);
		Y1 = getY(y,i,radius-tickSize);
		X2 = getX(x,i,radius-borderWidth);
		Y2 = getY(y,i,radius-borderWidth);
		myCanvas->tft->drawLine(X1,Y1,X2,Y2,lowLimitColor);
	}

	// Draw min value
	setNum(scaleMin);
	myCanvas->tft->drawString(buf,x-radius+FONT_SPACE,y+radius-FONT_Y,1,borderColor);

	// Draw max value
	setNum(scaleMax);
	myCanvas->tft->drawString(buf,getX(x,maxDegree,radius-tickSize),y+radius-FONT_Y,1,borderColor);

}

void Dial::drawNeedle(int cX, int cY, int degree, int radius, int color){
	degree = map(constrain(degree,scaleMin,scaleMax),scaleMin,scaleMax,585,315);

	int pX1,pY1,pX2,pY2,pX3,pY3;

	pX1 = getX(cX,degree-90,4);
	pY1 = getY(cY,degree-90,4);
	pX2 = getX(cX,degree+90,4);
	pY2 = getY(cY,degree+90,4);
	pX3 = getX(cX,degree,radius);
	pY3 = getY(cY,degree,radius);

	myCanvas->tft->fillTriangle(pX1,pY1,pX2,pY2,pX3,pY3,color);
	myCanvas->tft->fillCircle(cX,cY,4,color);
	/*
	// Outer triangle
	myCanvas->tft->drawLine(pX1,pY1,pX2,pY2,color);
	myCanvas->tft->drawLine(pX1,pY1,pX3,pY3,color);
	myCanvas->tft->drawLine(pX2,pY2,pX3,pY3,color);

	pX1 = getX(cX,degree-90,2);
	pY1 = getY(cY,degree-90,2);
	pX2 = getX(cX,degree+90,2);
	pY2 = getY(cY,degree+90,2);

	// Inner Triangle
	myCanvas->tft->drawLine(pX1,pY1,pX2,pY2,color);
	myCanvas->tft->drawLine(pX1,pY1,pX3,pY3,color);
	myCanvas->tft->drawLine(pX2,pY2,pX3,pY3,color);

	// Center Line
	myCanvas->tft->drawLine(cX,cY,pX3,pY3,color);
	*/
}

void Dial::drawNeedleAndValue(){
	int color = fgColor;

	// Draw needle
	drawNeedle(x,y,previousValue,radius-tickSize-gap,bgColor);
	if(currentValue >= hiLimit) color = hiLimitColor;
	if(currentValue <= lowLimit) color = lowLimitColor;
	drawNeedle(x,y,currentValue,radius-tickSize-gap,color);

	if(showVal){
		// Draw current value
		int dSpace;
		int fontSize = 2;
		if(currentValue<10) dSpace = 3 * fontSize;
		if(currentValue>=10) dSpace = 6 * fontSize;
		if(currentValue>99) dSpace = 9 * fontSize;
		myCanvas->tft->fillRect(x-9*fontSize,y+radius-12*fontSize,18*fontSize,8*fontSize,bgColor);
		myCanvas->tft->drawNumber(currentValue,x-dSpace,y+radius-12*fontSize,fontSize,color);
	}
}

int Dial::getX(int cX,int deg, int radius){
	return (cX + radius * cos(deg*PI/180));
}

int Dial::getY(int cY, int deg, int radius){
	return (cY - radius * sin(deg*PI/180));
}

//Overriden virtual methods
void Dial::show(){
	// Draw face
	drawBorder();
	drawFace();
	drawNeedleAndValue();
	//update();
}

void Dial::update(){
	if(!visible) return;

	if(!forcedUpdate){
		if(previousValue == currentValue) return;
	}

	// Limit crossing forces border to redraw
	/*
	if(previousValue < hiLimit && previousValue > lowLimit){
		if(currentValue >= hiLimit || currentValue <= lowLimit) drawBorder();
	}
	if(previousValue >= hiLimit){
		if(currentValue < hiLimit) drawBorder();
	}
	if(previousValue <= lowLimit){
		if(currentValue > lowLimit) drawBorder();
	}
	*/
	drawNeedleAndValue();
}
<commit_msg>Update Dial<commit_after>#include "Dial.h"
//Constructor
Dial::Dial(){
	if(buf = (char *)malloc(BUF_SIZE+1)) memset(buf,0,BUF_SIZE+1); //Had to add one more, to avoid some bug
}

Dial::Dial(unsigned int radius, unsigned int minLimit, unsigned int setpoint, unsigned int maxLimit)
{
	if(buf = (char *)malloc(BUF_SIZE+1)) memset(buf,0,BUF_SIZE+1); //Had to add one more, to avoid some bug
	this->setSize(radius);
	this->setLimits(minLimit,setpoint,maxLimit);
	this->setColors(BLACK,BLUE,WHITE);
	init();
}

Dial::~Dial(){}

//Methods
void Dial::init(){
	Indicator::init();
	type = 0x21;
	this->hiLimit = scaleMax;
	this->lowLimit = scaleMin;
	this->currentValue = scaleMin;
	this->maxDegree = 315;
	this->minDegree = 585;
	this->tickSize = 10;
	this->gap = 5;
	this->tickDegree = 45;
	this->showVal = true;
	this->showTicks = true;
}

void Dial::clear(){
	for(int i = BUF_SIZE-1; i >= 0; i--)
	{
			buf[i] = 0;
	}
}

void Dial::setSize(int radius){
	this->w = radius*2;
	this->h = radius*2;
	this->radius = radius;
}

void Dial::drawBorder(){
	int color = this->fgColor;
	/*
	if(currentValue >= hiLimit) color = hiLimitColor;
	if(currentValue <= lowLimit) color = lowLimitColor;

	/*
	for(int i=0; i < this->borderWidth; i++)
	{
  	myCanvas->tft->drawCircle(x,y,radius-i,color);
  }
	*/
	myCanvas->tft->fillCircle(x,y,radius,color);
	//myCanvas->tft->fillCircle(x,y,radius-borderWidth,bgColor);
	//drawFace();
}

void Dial::drawFace(){
	// Draw face
	myCanvas->tft->fillCircle(x,y,radius - this->borderWidth,this->bgColor);

	// Draw border
	//drawBorder();

	int X1,Y1,X2,Y2;

  // Draw ticks
	if(showTicks){
		for(int i=maxDegree; i<=minDegree; i+=tickDegree)
		{
			X1 = getX(x,i,radius-tickSize);
			Y1 = getY(y,i,radius-tickSize);
			X2 = getX(x,i,radius-borderWidth);
			Y2 = getY(y,i,radius-borderWidth);
			myCanvas->tft->drawLine(X1,Y1,X2,Y2,borderColor);
		}
	}else{
		int i = minDegree;
		X1 = getX(x,i,radius-tickSize);
		Y1 = getY(y,i,radius-tickSize);
		X2 = getX(x,i,radius-borderWidth);
		Y2 = getY(y,i,radius-borderWidth);
		myCanvas->tft->drawLine(X1,Y1,X2,Y2,borderColor);

		i = maxDegree;
		X1 = getX(x,i,radius-tickSize);
		Y1 = getY(y,i,radius-tickSize);
		X2 = getX(x,i,radius-borderWidth);
		Y2 = getY(y,i,radius-borderWidth);
		myCanvas->tft->drawLine(X1,Y1,X2,Y2,borderColor);
	}

	// Draw Setpoint line
	if(setpoint){
		int i = map(setpoint,scaleMin,scaleMax,minDegree,maxDegree);
		X1 = getX(x,i,radius-tickSize);
		Y1 = getY(y,i,radius-tickSize);
		X2 = getX(x,i,radius-borderWidth);
		Y2 = getY(y,i,radius-borderWidth);
		myCanvas->tft->drawLine(X1,Y1,X2,Y2,setpointColor);
	}

	// Draw High limit line
	if(hiLimit < scaleMax){
		int i = map(hiLimit,scaleMin,scaleMax,minDegree,maxDegree);
		X1 = getX(x,i,radius-tickSize);
		Y1 = getY(y,i,radius-tickSize);
		X2 = getX(x,i,radius-borderWidth);
		Y2 = getY(y,i,radius-borderWidth);
		myCanvas->tft->drawLine(X1,Y1,X2,Y2,hiLimitColor);
	}

	// Draw Low Limit line
	if(lowLimit > scaleMin){
		int i = map(lowLimit,scaleMin,scaleMax,minDegree,maxDegree);
		X1 = getX(x,i,radius-tickSize);
		Y1 = getY(y,i,radius-tickSize);
		X2 = getX(x,i,radius-borderWidth);
		Y2 = getY(y,i,radius-borderWidth);
		myCanvas->tft->drawLine(X1,Y1,X2,Y2,lowLimitColor);
	}

	// Draw min value
	setNum(scaleMin);
	myCanvas->tft->drawString(buf,x-radius+FONT_SPACE,y+radius-FONT_Y,1,borderColor);

	// Draw max value
	setNum(scaleMax);
	myCanvas->tft->drawString(buf,getX(x,maxDegree,radius-tickSize),y+radius-FONT_Y,1,borderColor);

}

void Dial::drawNeedle(int cX, int cY, int degree, int radius, int color){
	degree = map(constrain(degree,scaleMin,scaleMax),scaleMin,scaleMax,585,315);

	int pX1,pY1,pX2,pY2,pX3,pY3;

	pX1 = getX(cX,degree-90,4);
	pY1 = getY(cY,degree-90,4);
	pX2 = getX(cX,degree+90,4);
	pY2 = getY(cY,degree+90,4);
	pX3 = getX(cX,degree,radius);
	pY3 = getY(cY,degree,radius);

	myCanvas->tft->fillTriangle(pX1,pY1,pX2,pY2,pX3,pY3,color);
	myCanvas->tft->fillCircle(cX,cY,4,color);
	/*
	// Outer triangle
	myCanvas->tft->drawLine(pX1,pY1,pX2,pY2,color);
	myCanvas->tft->drawLine(pX1,pY1,pX3,pY3,color);
	myCanvas->tft->drawLine(pX2,pY2,pX3,pY3,color);

	pX1 = getX(cX,degree-90,2);
	pY1 = getY(cY,degree-90,2);
	pX2 = getX(cX,degree+90,2);
	pY2 = getY(cY,degree+90,2);

	// Inner Triangle
	myCanvas->tft->drawLine(pX1,pY1,pX2,pY2,color);
	myCanvas->tft->drawLine(pX1,pY1,pX3,pY3,color);
	myCanvas->tft->drawLine(pX2,pY2,pX3,pY3,color);

	// Center Line
	myCanvas->tft->drawLine(cX,cY,pX3,pY3,color);
	*/
}

void Dial::drawNeedleAndValue(){
	int color = fgColor;

	// Draw needle
	drawNeedle(x,y,previousValue,radius-tickSize-gap,bgColor);
	if(currentValue >= hiLimit) color = hiLimitColor;
	if(currentValue <= lowLimit) color = lowLimitColor;
	drawNeedle(x,y,currentValue,radius-tickSize-gap,color);

	if(showVal){
		// Draw current value
		int dSpace;
		int fontSize = 2;
		if(currentValue<10) dSpace = 3 * fontSize;
		if(currentValue>=10) dSpace = 6 * fontSize;
		if(currentValue>99) dSpace = 9 * fontSize;
		if(currentValue>999) dSpace = 12 * fontSize;
		myCanvas->tft->fillRect(x-12*fontSize,y+radius-12*fontSize,24*fontSize,8*fontSize,bgColor);
		myCanvas->tft->drawNumber(currentValue,x-dSpace,y+radius-12*fontSize,fontSize,color);
	}
}

int Dial::getX(int cX,int deg, int radius){
	return (cX + radius * cos(deg*PI/180));
}

int Dial::getY(int cY, int deg, int radius){
	return (cY - radius * sin(deg*PI/180));
}

//Overriden virtual methods
void Dial::show(){
	// Draw face
	drawBorder();
	drawFace();
	drawNeedleAndValue();
	//update();
}

void Dial::update(){
	if(!visible) return;

	if(!forcedUpdate){
		if(previousValue == currentValue) return;
	}

	// Limit crossing forces border to redraw
	/*
	if(previousValue < hiLimit && previousValue > lowLimit){
		if(currentValue >= hiLimit || currentValue <= lowLimit) drawBorder();
	}
	if(previousValue >= hiLimit){
		if(currentValue < hiLimit) drawBorder();
	}
	if(previousValue <= lowLimit){
		if(currentValue > lowLimit) drawBorder();
	}
	*/
	drawNeedleAndValue();
}
<|endoftext|>


<commit_before><commit_msg>[generator] Fix build on OS X<commit_after><|endoftext|>


<commit_before>#include "Game.h"

Game::Game()
{
    //Set default variables
    width = 800;
    height = 600;
    vsync = false;
    fullscreen = false;
    fog = true;
    mazeSize = 40;

    //Try to load configuration
    loadConfig();

    //If user set wrong size, correct it
    if(mazeSize > MAZE_MAXSIZE)
        mazeSize = MAZE_MAXSIZE;

    if(mazeSize < MAZE_MINSIZE)
        mazeSize = MAZE_MINSIZE;
}

void Game::loadConfig()
{
    vector <std::string> options;
    std::string option, value;
    bool isOption = true;

    ifstream fin("config.cfg");

    if(!fin.is_open())
    {
        cout << "Failed to load config file. Setting default variables." << endl;
        return;
    }

    while(!fin.eof())
    {
        std::string tmp;
        fin >> tmp;
        options.push_back(tmp);
    }

    fin.close();

    for(unsigned int i = 0; i < options.size(); i++)
    {
        for(unsigned int j = 0; j < options[i].size(); j++)
        {
            //'=' catched, so now we picking value, not option
            if(options[i][j] == '=')
            {
                isOption = false;
                continue;
            }

            if(isOption)
                option += options[i][j];

            if(!isOption)
                value += options[i][j];
        }

        //Save game options
        if(option.compare("width") == 0)
            width = atoi(value.c_str());

        if(option.compare("height") == 0)
            height = atoi(value.c_str());

        if(option.compare("mazeSize") == 0)
            mazeSize = atoi(value.c_str());

        if(option.compare("vsync") == 0)
        {
            if(value.compare("true") == 0)
                vsync = true;
            else if (value.compare("false") == 0)
                vsync = false;
        }

        if(option.compare("fullscreen") == 0)
        {
            if(value.compare("true") == 0)
                fullscreen = true;
            else if (value.compare("false") == 0)
                fullscreen = false;
        }

        if(option.compare("fog") == 0)
        {
            if(value.compare("true") == 0)
                fog = true;
            else if (value.compare("false") == 0)
                fog = false;
        }

        //Clear variables to use it in next loop step
        option="";
        value="";
        isOption = true;
    }
}

void Game::startGame()
{
    //Create Irrlicht device and get pointer to driver and scene manager
    device = createDevice(EDT_OPENGL, dimension2d<u32>(width, height), 32, fullscreen, false, vsync, 0);

    srand(time(0));

    driver = device->getVideoDriver();
    scenemgr = device->getSceneManager();

    device->setWindowCaption(L"3D Maze");

    //Create map
    Map map(mazeSize);
    map.createMap(driver, scenemgr);

    IMeshSceneNode *mapNode = scenemgr->addMeshSceneNode(map.getMapMesh());
    mapNode->setMaterialFlag(EMF_LIGHTING, true);
    mapNode->getMaterial(0).FogEnable = false;

    ICameraSceneNode *camera = scenemgr->addCameraSceneNodeFPS();
    camera->setTarget(vector3df(90,4,45));
    camera->setFarValue(1000);
    device->getCursorControl()->setVisible(false);

    scenemgr->setAmbientLight(SColorf(1, 1, 1, 255));

    //Main loop
    while(device->run())
    {
        if(device->isWindowActive())
        {
            driver->beginScene(true, true, SColor(255,0,0,0));

            scenemgr->drawAll();

            driver->endScene();
        }
        else
            device->yield();
    }

    device->drop();
}

<commit_msg>Show debug messages<commit_after>#include "Game.h"

Game::Game()
{
    //Set default variables
    width = 800;
    height = 600;
    vsync = false;
    fullscreen = false;
    fog = true;
    mazeSize = 40;

    //Try to load configuration
    loadConfig();

    //If user set wrong size, correct it
    if(mazeSize > MAZE_MAXSIZE)
        mazeSize = MAZE_MAXSIZE;

    if(mazeSize < MAZE_MINSIZE)
        mazeSize = MAZE_MINSIZE;

    cout << "\nStarting mode " << width << "x" << height << ", vsync=" << vsync << ", fullscreen=" << fullscreen << ", maze size=" << mazeSize << ", fog=" << fog << endl;
}

void Game::loadConfig()
{
    vector <std::string> options;
    std::string option, value;
    bool isOption = true;

    ifstream fin("config.cfg");

    if(!fin.is_open())
    {
        cout << "Failed to load config file. Setting default variables." << endl;
        return;
    }

    while(!fin.eof())
    {
        std::string tmp;
        fin >> tmp;
        options.push_back(tmp);
    }

    fin.close();

    for(unsigned int i = 0; i < options.size(); i++)
    {
        for(unsigned int j = 0; j < options[i].size(); j++)
        {
            //'=' catched, so now we picking value, not option
            if(options[i][j] == '=')
            {
                isOption = false;
                continue;
            }

            if(isOption)
                option += options[i][j];

            if(!isOption)
                value += options[i][j];
        }

        //Save game options
        if(option.compare("width") == 0)
            width = atoi(value.c_str());

        if(option.compare("height") == 0)
            height = atoi(value.c_str());

        if(option.compare("mazeSize") == 0)
            mazeSize = atoi(value.c_str());

        if(option.compare("vsync") == 0)
        {
            if(value.compare("true") == 0)
                vsync = true;
            else if (value.compare("false") == 0)
                vsync = false;
        }

        if(option.compare("fullscreen") == 0)
        {
            if(value.compare("true") == 0)
                fullscreen = true;
            else if (value.compare("false") == 0)
                fullscreen = false;
        }

        if(option.compare("fog") == 0)
        {
            if(value.compare("true") == 0)
                fog = true;
            else if (value.compare("false") == 0)
                fog = false;
        }

        //Clear variables to use it in next loop step
        option="";
        value="";
        isOption = true;
    }
}

void Game::startGame()
{
    //Create Irrlicht device and get pointer to driver and scene manager
    device = createDevice(EDT_OPENGL, dimension2d<u32>(width, height), 32, fullscreen, false, vsync, 0);

    srand(time(0));

    driver = device->getVideoDriver();
    scenemgr = device->getSceneManager();

    device->setWindowCaption(L"3D Maze");

    //Create map
    Map map(mazeSize);
    map.createMap(driver, scenemgr);

    IMeshSceneNode *mapNode = scenemgr->addMeshSceneNode(map.getMapMesh());
    mapNode->setMaterialFlag(EMF_LIGHTING, true);
    mapNode->getMaterial(0).FogEnable = false;

    ICameraSceneNode *camera = scenemgr->addCameraSceneNodeFPS();
    camera->setTarget(vector3df(90,4,45));
    camera->setFarValue(1000);
    device->getCursorControl()->setVisible(false);

    scenemgr->setAmbientLight(SColorf(1, 1, 1, 255));

    //Main loop
    while(device->run())
    {
        if(device->isWindowActive())
        {
            driver->beginScene(true, true, SColor(255,0,0,0));

            scenemgr->drawAll();

            driver->endScene();
        }
        else
            device->yield();
    }

    device->drop();
}

<|endoftext|>


<commit_before>#include "evaluate_circuit.h"

#include "gmock/gmock.h"
#include "gtest/gtest.h"

namespace qflex {
namespace {

class GetOutputStatesTest : public testing::Test {
 public:
  void TestOutputExpectations() {
    get_output_states(ordering_, &final_qubits_, &output_states_);
    EXPECT_EQ(final_qubits_, expected_final_qubits_);
    EXPECT_EQ(output_states_, expected_output_states_);
  }

 protected:
  std::vector<std::vector<int>> final_qubits_, expected_final_qubits_;
  std::vector<std::string> output_states_, expected_output_states_;
  std::list<ContractionOperation> ordering_;
};

// ExpandPatch should not affect output states.
TEST_F(GetOutputStatesTest, IgnoresExpandPatch) {
  ordering_.emplace_back(ExpandPatch("a", {0, 0}));
  ordering_.emplace_back(ExpandPatch("a", {0, 1}));
  expected_final_qubits_ = {};
  expected_output_states_ = {""};
  TestOutputExpectations();
}

// MergePatches should not affect output states.
TEST_F(GetOutputStatesTest, IgnoresMergePatches) {
  ordering_.emplace_back(MergePatches("a", "b"));
  ordering_.emplace_back(MergePatches("b", "c"));
  expected_final_qubits_ = {};
  expected_output_states_ = {""};
  TestOutputExpectations();
}

// Non-terminal cuts should not affect output states.
TEST_F(GetOutputStatesTest, IgnoresNonTerminalCuts) {
  ordering_.emplace_back(CutIndex({{0, 0}, {0, 1}}, {1, 2}));
  ordering_.emplace_back(CutIndex({{0, 0}, {1, 0}}, {3}));
  expected_final_qubits_ = {};
  expected_output_states_ = {""};
  TestOutputExpectations();
}

// Terminal cuts are listed in the order applied.
TEST_F(GetOutputStatesTest, TerminalCutsDefineOutputStates) {
  ordering_.emplace_back(CutIndex({{0, 1}}, {0}));
  ordering_.emplace_back(CutIndex({{0, 0}}, {0, 1}));
  ordering_.emplace_back(CutIndex({{1, 0}}, {1}));
  expected_final_qubits_ = {{0, 1}, {0, 0}, {1, 0}};
  expected_output_states_ = {"001", "011"};
  TestOutputExpectations();
}

// Terminal cuts with no values will be evaluated as "0" and "1", since output
// states can only be one of those two values.
TEST_F(GetOutputStatesTest, BlankCutValuesEvaluateBothStates) {
  ordering_.emplace_back(CutIndex({{0, 1}}));
  ordering_.emplace_back(CutIndex({{0, 0}}));
  ordering_.emplace_back(CutIndex({{1, 0}}));
  expected_final_qubits_ = {{0, 1}, {0, 0}, {1, 0}};
  expected_output_states_ = {"000", "001", "010", "011",
                             "100", "101", "110", "111"};
  TestOutputExpectations();
}

// When a mixture of operations are applied, only terminal cuts affect the
// output states.
TEST_F(GetOutputStatesTest, OnlyUseTerminalCuts) {
  ordering_.emplace_back(CutIndex({{0, 1}, {1, 1}}, {1, 2}));
  ordering_.emplace_back(ExpandPatch("a", {0, 1}));
  ordering_.emplace_back(ExpandPatch("a", {0, 0}));
  ordering_.emplace_back(ExpandPatch("a", {1, 0}));
  ordering_.emplace_back(CutIndex({{2, 1}}));
  ordering_.emplace_back(ExpandPatch("b", {2, 1}));
  ordering_.emplace_back(ExpandPatch("b", {1, 1}));
  ordering_.emplace_back(MergePatches("a", "b"));
  expected_final_qubits_ = {{2, 1}};
  expected_output_states_ = {"0", "1"};
  TestOutputExpectations();
}

// Nullptr input in get_output_states()
TEST(GetOutputStatesDeathTest, InvalidInput) {
  std::list<ContractionOperation> ordering;
  std::vector<std::vector<int>> final_qubits;
  std::vector<std::string> output_states;

  // Final qubits cannot be null pointer.
  EXPECT_DEATH(get_output_states(ordering, nullptr, &output_states), "");

  // Output states cannot be null pointer.
  EXPECT_DEATH(get_output_states(ordering, &final_qubits, nullptr), "");
}

// Grid layout with trailing whitespace.
constexpr char kTestGrid[] = R"(0 1 1 0
                                1 1 1 1
                                0 1 0 0
                                )";

TEST(ReadGridTest, ValidGrid3x4) {
  std::stringstream stream(kTestGrid);
  std::vector<std::vector<int>> off_qubits =
      read_grid_layout_from_stream(&stream, 3, 4);
  std::vector<std::vector<int>> expected_off = {
      {0, 0}, {0, 3}, {2, 0}, {2, 2}, {2, 3}};
  EXPECT_EQ(off_qubits, expected_off);
}

TEST(ReadGridTest, ValidGrid6x2) {
  std::stringstream stream(kTestGrid);
  std::vector<std::vector<int>> off_qubits =
      read_grid_layout_from_stream(&stream, 6, 2);
  std::vector<std::vector<int>> expected_off = {
      {0, 0}, {1, 1}, {4, 0}, {5, 0}, {5, 1}};
  EXPECT_EQ(off_qubits, expected_off);
}

// Grid data is too large: 3 * 4 > 5 * 2
TEST(ReadGridDeathTest, InvalidGrid5x2) {
  std::stringstream stream(kTestGrid);
  EXPECT_DEATH(read_grid_layout_from_stream(&stream, 5, 2), "");
}

// Grid data is too small: 3 * 4 < 5 * 3
TEST(ReadGridDeathTest, InvalidGrid5x3) {
  std::stringstream stream(kTestGrid);
  EXPECT_DEATH(read_grid_layout_from_stream(&stream, 5, 3), "");
}

// Below are config strings for a simple grid with one "off" qubit and one cut:
//   0 - 1
//   |   x --> cut between (0,1) and (1,1)
//   2 - 3
//       |
//   4   5 --> qubit at (2,0) is off; (2,1) is in final region.
// This circuit should return the input string with amplitude ~= 1 when summing
// over the cut values, but only when the output of (2,1) is a zero.
constexpr char kSimpleCircuit[] = R"(5
0 h 0
0 h 1
0 h 2
0 h 3
0 h 5
1 t 0
1 t 1
1 t 2
1 t 3
1 t 5
1 cz 0 1
2 cx 0 2
3 cx 1 3
4 cz 2 3
5 cz 3 5
11 cz 0 1
12 cx 0 2
13 cx 1 3
14 cz 2 3
15 cx 3 5
17 h 0
17 h 1
17 h 2
17 h 3
17 h 5)";

constexpr char kSimpleOrdering[] = R"(#
cut () 1 3
expand a 1
expand a 0
expand a 2
cut () 5
expand b 5
expand b 3
merge a b
)";

constexpr char kSimpleGrid[] = R"(1 1
                                  1 1
                                  0 1)";

// Perform a full evaluation of a very simple circuit.
TEST(EvaluateCircuitTest, SimpleCircuit) {
  std::stringstream circuit_data(kSimpleCircuit);
  std::stringstream ordering_data(kSimpleOrdering);
  std::stringstream grid_data(kSimpleGrid);

  QflexInput input;
  input.I = 3;
  input.J = 2;
  input.K = 2;
  input.circuit_data = &circuit_data;
  input.ordering_data = &ordering_data;
  input.grid_data = &grid_data;
  input.initial_state = "00000";
  input.final_state_A = "1100";

  std::vector<std::pair<std::string, std::complex<double>>> amplitudes =
      EvaluateCircuit(&input);

  ASSERT_EQ(amplitudes.size(), 2);
  EXPECT_EQ(amplitudes[0].first, "1100 0");
  EXPECT_EQ(amplitudes[1].first, "1100 1");
  EXPECT_NEAR(amplitudes[0].second.real(), 0.10669, 1e-5);
  EXPECT_NEAR(amplitudes[0].second.imag(), 0.04419, 1e-5);
  EXPECT_NEAR(amplitudes[1].second.real(), -0.01831, 1e-5);
  EXPECT_NEAR(amplitudes[1].second.imag(), -0.25758, 1e-5);
}

// Nullptr input in EvaluateCircuit()
TEST(EvaluateCircuitDeathTest, InvalidInput) {
  // Input cannot be null pointer.
  EXPECT_DEATH(EvaluateCircuit(nullptr), "");
}

}  // namespace
}  // namespace qflex

int main(int argc, char** argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
<commit_msg>fixed SimpleCircuit test<commit_after>#include "evaluate_circuit.h"

#include "gmock/gmock.h"
#include "gtest/gtest.h"

namespace qflex {
namespace {

class GetOutputStatesTest : public testing::Test {
 public:
  void TestOutputExpectations() {
    get_output_states(ordering_, &final_qubits_, &output_states_);
    EXPECT_EQ(final_qubits_, expected_final_qubits_);
    EXPECT_EQ(output_states_, expected_output_states_);
  }

 protected:
  std::vector<std::vector<int>> final_qubits_, expected_final_qubits_;
  std::vector<std::string> output_states_, expected_output_states_;
  std::list<ContractionOperation> ordering_;
};

// ExpandPatch should not affect output states.
TEST_F(GetOutputStatesTest, IgnoresExpandPatch) {
  ordering_.emplace_back(ExpandPatch("a", {0, 0}));
  ordering_.emplace_back(ExpandPatch("a", {0, 1}));
  expected_final_qubits_ = {};
  expected_output_states_ = {""};
  TestOutputExpectations();
}

// MergePatches should not affect output states.
TEST_F(GetOutputStatesTest, IgnoresMergePatches) {
  ordering_.emplace_back(MergePatches("a", "b"));
  ordering_.emplace_back(MergePatches("b", "c"));
  expected_final_qubits_ = {};
  expected_output_states_ = {""};
  TestOutputExpectations();
}

// Non-terminal cuts should not affect output states.
TEST_F(GetOutputStatesTest, IgnoresNonTerminalCuts) {
  ordering_.emplace_back(CutIndex({{0, 0}, {0, 1}}, {1, 2}));
  ordering_.emplace_back(CutIndex({{0, 0}, {1, 0}}, {3}));
  expected_final_qubits_ = {};
  expected_output_states_ = {""};
  TestOutputExpectations();
}

// Terminal cuts are listed in the order applied.
TEST_F(GetOutputStatesTest, TerminalCutsDefineOutputStates) {
  ordering_.emplace_back(CutIndex({{0, 1}}, {0}));
  ordering_.emplace_back(CutIndex({{0, 0}}, {0, 1}));
  ordering_.emplace_back(CutIndex({{1, 0}}, {1}));
  expected_final_qubits_ = {{0, 1}, {0, 0}, {1, 0}};
  expected_output_states_ = {"001", "011"};
  TestOutputExpectations();
}

// Terminal cuts with no values will be evaluated as "0" and "1", since output
// states can only be one of those two values.
TEST_F(GetOutputStatesTest, BlankCutValuesEvaluateBothStates) {
  ordering_.emplace_back(CutIndex({{0, 1}}));
  ordering_.emplace_back(CutIndex({{0, 0}}));
  ordering_.emplace_back(CutIndex({{1, 0}}));
  expected_final_qubits_ = {{0, 1}, {0, 0}, {1, 0}};
  expected_output_states_ = {"000", "001", "010", "011",
                             "100", "101", "110", "111"};
  TestOutputExpectations();
}

// When a mixture of operations are applied, only terminal cuts affect the
// output states.
TEST_F(GetOutputStatesTest, OnlyUseTerminalCuts) {
  ordering_.emplace_back(CutIndex({{0, 1}, {1, 1}}, {1, 2}));
  ordering_.emplace_back(ExpandPatch("a", {0, 1}));
  ordering_.emplace_back(ExpandPatch("a", {0, 0}));
  ordering_.emplace_back(ExpandPatch("a", {1, 0}));
  ordering_.emplace_back(CutIndex({{2, 1}}));
  ordering_.emplace_back(ExpandPatch("b", {2, 1}));
  ordering_.emplace_back(ExpandPatch("b", {1, 1}));
  ordering_.emplace_back(MergePatches("a", "b"));
  expected_final_qubits_ = {{2, 1}};
  expected_output_states_ = {"0", "1"};
  TestOutputExpectations();
}

// Nullptr input in get_output_states()
TEST(GetOutputStatesDeathTest, InvalidInput) {
  std::list<ContractionOperation> ordering;
  std::vector<std::vector<int>> final_qubits;
  std::vector<std::string> output_states;

  // Final qubits cannot be null pointer.
  EXPECT_DEATH(get_output_states(ordering, nullptr, &output_states), "");

  // Output states cannot be null pointer.
  EXPECT_DEATH(get_output_states(ordering, &final_qubits, nullptr), "");
}

// Grid layout with trailing whitespace.
constexpr char kTestGrid[] = R"(0 1 1 0
                                1 1 1 1
                                0 1 0 0
                                )";

TEST(ReadGridTest, ValidGrid3x4) {
  std::stringstream stream(kTestGrid);
  std::vector<std::vector<int>> off_qubits =
      read_grid_layout_from_stream(&stream, 3, 4);
  std::vector<std::vector<int>> expected_off = {
      {0, 0}, {0, 3}, {2, 0}, {2, 2}, {2, 3}};
  EXPECT_EQ(off_qubits, expected_off);
}

TEST(ReadGridTest, ValidGrid6x2) {
  std::stringstream stream(kTestGrid);
  std::vector<std::vector<int>> off_qubits =
      read_grid_layout_from_stream(&stream, 6, 2);
  std::vector<std::vector<int>> expected_off = {
      {0, 0}, {1, 1}, {4, 0}, {5, 0}, {5, 1}};
  EXPECT_EQ(off_qubits, expected_off);
}

// Grid data is too large: 3 * 4 > 5 * 2
TEST(ReadGridDeathTest, InvalidGrid5x2) {
  std::stringstream stream(kTestGrid);
  EXPECT_DEATH(read_grid_layout_from_stream(&stream, 5, 2), "");
}

// Grid data is too small: 3 * 4 < 5 * 3
TEST(ReadGridDeathTest, InvalidGrid5x3) {
  std::stringstream stream(kTestGrid);
  EXPECT_DEATH(read_grid_layout_from_stream(&stream, 5, 3), "");
}

// Below are config strings for a simple grid with one "off" qubit and one cut:
//   0 - 1
//   |   x --> cut between (0,1) and (1,1)
//   2 - 3
//       |
//   4   5 --> qubit at (2,0) is off; (2,1) is in final region.
// This circuit should return the input string with amplitude ~= 1 when summing
// over the cut values, but only when the output of (2,1) is a zero.
constexpr char kSimpleCircuit[] = R"(5
0 h 0
0 h 1
0 h 2
0 h 3
0 h 5
1 t 0
1 t 1
1 t 2
1 t 3
1 t 5
2 cz 0 1
3 cx 0 2
4 cx 1 3
5 cz 2 3
6 cz 3 5
11 cz 0 1
12 cx 0 2
13 cx 1 3
14 cz 2 3
15 cx 3 5
17 h 0
17 h 1
17 h 2
17 h 3
17 h 5)";

constexpr char kSimpleOrdering[] = R"(#
cut () 1 3
expand a 1
expand a 0
expand a 2
cut () 5
expand b 5
expand b 3
merge a b
)";

constexpr char kSimpleGrid[] = R"(1 1
                                  1 1
                                  0 1)";

// Perform a full evaluation of a very simple circuit.
TEST(EvaluateCircuitTest, SimpleCircuit) {
  std::stringstream circuit_data(kSimpleCircuit);
  std::stringstream ordering_data(kSimpleOrdering);
  std::stringstream grid_data(kSimpleGrid);

  QflexInput input;
  input.I = 3;
  input.J = 2;
  input.K = 2;
  input.circuit_data = &circuit_data;
  input.ordering_data = &ordering_data;
  input.grid_data = &grid_data;
  input.initial_state = "00000";
  input.final_state_A = "1100";

  std::vector<std::pair<std::string, std::complex<double>>> amplitudes =
      EvaluateCircuit(&input);

  ASSERT_EQ(amplitudes.size(), 2);
  EXPECT_EQ(amplitudes[0].first, "1100 0");
  EXPECT_EQ(amplitudes[1].first, "1100 1");
  EXPECT_NEAR(amplitudes[0].second.real(), 0.10669, 1e-5);
  EXPECT_NEAR(amplitudes[0].second.imag(), 0.04419, 1e-5);
  EXPECT_NEAR(amplitudes[1].second.real(), -0.01831, 1e-5);
  EXPECT_NEAR(amplitudes[1].second.imag(), -0.25758, 1e-5);
}

// Nullptr input in EvaluateCircuit()
TEST(EvaluateCircuitDeathTest, InvalidInput) {
  // Input cannot be null pointer.
  EXPECT_DEATH(EvaluateCircuit(nullptr), "");
}

}  // namespace
}  // namespace qflex

int main(int argc, char** argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
<|endoftext|>