<commit_before>/*
 * LogOptions.cpp
 *
 * Copyright (C) 2020 by RStudio, PBC
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include <core/LogOptions.hpp>

#include <vector>

#include <core/system/Environment.hpp>
#include <core/system/System.hpp>
#include <core/system/Xdg.hpp>

#include "config.h"

namespace rstudio {
namespace core {
namespace log {

#define kLogLevel          "log-level"
#define kLoggerType        "logger-type"
#define kLogDir            "log-dir"
#define kLogFileMode       "log-file-mode"
#define kLogFileIncludePid "log-file-include-pid"
#define kRotate            "rotate"
#define kMaxSizeMb         "max-size-mb"
#define kLogConfFile       "logging.conf"
#define kLogConfEnvVar     "RS_LOG_CONF_FILE"

#define kFileLogger        "file"
#define kStdErrLogger      "stderr"
#define kSysLogger         "syslog"

#define kLoggingLevelDebug "debug"
#define kLoggingLevelInfo  "info"
#define kLoggingLevelWarn  "warn"
#define kLoggingLevelError "error"

#define kBaseLevel       0
#define kBinaryLevel     1
#define kLogSectionLevel 2

namespace {

// pick default log path location
#ifdef RSTUDIO_SERVER
const FilePath kDefaultLogPath("/var/log/rstudio-server");
#else
// desktop - store logs under user dir
const FilePath kDefaultLogPath = core::system:xdg::userDataDir().completePath("log");
#endif

std::string logLevelToString(LogLevel logLevel)
{
   switch (logLevel)
   {
      case LogLevel::DEBUG:
         return kLoggingLevelDebug;
      case LogLevel::INFO:
         return kLoggingLevelInfo;
      case LogLevel::WARN:
         return kLoggingLevelWarn;
      case LogLevel::ERR:
         return kLoggingLevelError;
      case LogLevel::OFF:
      default:
         return kLoggingLevelWarn;
   }
}

std::string loggerTypeToString(LoggerType loggerType)
{
   switch (loggerType)
   {
      case LoggerType::kFile:
         return kFileLogger;
      case LoggerType::kStdErr:
         return kStdErrLogger;
      case LoggerType::kSysLog:
         return kSysLogger;
      default:
         return kSysLogger;
   }
}

LogLevel strToLogLevel(const std::string& logLevelStr)
{
   if (logLevelStr == kLoggingLevelWarn)
      return LogLevel::WARN;
   else if (logLevelStr == kLoggingLevelError)
       return LogLevel::ERR;
   else if (logLevelStr == kLoggingLevelInfo)
       return LogLevel::INFO;
   else if (logLevelStr == kLoggingLevelDebug)
       return LogLevel::DEBUG;
   else
       return LogLevel::WARN;
}

LoggerType strToLoggerType(const std::string& loggerTypeStr)
{
   if (loggerTypeStr == kSysLogger)
      return LoggerType::kSysLog;
   else if (loggerTypeStr == kFileLogger)
      return LoggerType::kFile;
   else if (loggerTypeStr == kStdErrLogger)
      return LoggerType::kStdErr;
   else
      return LoggerType::kSysLog;
}

struct LoggerOptionsVisitor : boost::static_visitor<>
{
   LoggerOptionsVisitor(ConfigProfile& profile) :
      profile_(profile)
   {
   }

   void setDefaultFileLoggerOptions()
   {
      FileLogOptions defaultOptions(kDefaultLogPath);
      profile_.addParams(
         kLogDir, defaultOptions.getDirectory().getAbsolutePath(),
         kLogFileMode, defaultOptions.getFileMode(),
         kRotate, defaultOptions.doRotation(),
         kLogFileIncludePid, defaultOptions.includePid(),
         kMaxSizeMb, defaultOptions.getMaxSizeMb());
   }

   void operator()(const StdErrLogOptions& options)
   {
      setDefaultFileLoggerOptions();
   }

   void operator()(const SysLogOptions& options)
   {
      setDefaultFileLoggerOptions();
   }

   void operator()(const FileLogOptions& options)
   {
      // set file logger option defaults to those that were passed in
      profile_.addParams(
         kLogDir, options.getDirectory().getAbsolutePath(),
         kRotate, options.doRotation(),
         kMaxSizeMb, options.getMaxSizeMb(),
         kLogFileIncludePid, options.includePid(),
         kLogFileMode, options.getFileMode());
   }

   ConfigProfile& profile_;
};

} // anonymous namespace

LogOptions::LogOptions(const std::string& executableName) :
   executableName_(executableName),
   defaultLogLevel_(logLevelToString(LogLevel::WARN)),
   defaultLoggerType_(loggerTypeToString(LoggerType::kSysLog)),
   defaultLoggerOptions_(SysLogOptions()),
   lowestLogLevel_(LogLevel::WARN)
{
   initProfile();
}

LogOptions::LogOptions(const std::string& executableName,
                       LogLevel logLevel,
                       LoggerType loggerType,
                       const LoggerOptions& options) :
   executableName_(executableName),
   defaultLogLevel_(logLevelToString(logLevel)),
   defaultLoggerType_(loggerTypeToString(loggerType)),
   defaultLoggerOptions_(options),
   lowestLogLevel_(logLevel)
{
   initProfile();
}

void LogOptions::initProfile()
{
   // base level - * (applies to all loggers/binaries)
   // first override - @ (specific binary)
   // second override - (logger name)
   profile_.addSections(
      {{ kBaseLevel,       "*" },
       { kBinaryLevel,     "@" },
       { kLogSectionLevel, std::string() }});

   // add base params
   profile_.addParams(
      kLogLevel, defaultLogLevel_,
      kLoggerType, defaultLoggerType_);

   // add logger-specific params
   LoggerOptionsVisitor visitor(profile_);
   boost::apply_visitor(visitor, defaultLoggerOptions_);
}

Error LogOptions::read()
{
   // first, look for config file in a specific environment variable
   FilePath optionsFile(core::system::getenv(kLogConfEnvVar));
   if (!optionsFile.exists())
   {
   #ifdef RSTUDIO_SERVER
      optionsFile = core::system::xdg::systemConfigFile(kLogConfFile);
   #else
      // desktop - read user file first, and only read admin file if the user file does not exist
      optionsFile = core::system::xdg::userConfigDir().completeChildPath(kLogConfFile);
      if (!optionsFile.exists())
            optionsFile = core::system::xdg::systemConfigFile(kLogConfFile);
   #endif
   }

   // if the options file does not exist, that's fine - we'll just use default values
   if (!optionsFile.exists())
      return Success();

   Error error = profile_.load(optionsFile);
   if (error)
      return error;

   setLowestLogLevel();

   return Success();
}

void LogOptions::setLowestLogLevel()
{
   // first, set the log level for this particular binary
   std::string logLevel;
   profile_.getParam(
      kLogLevel, &logLevel, {{ kBaseLevel,   std::string() },
                             { kBinaryLevel, executableName_ }});
   lowestLogLevel_ = strToLogLevel(logLevel);

   // break out early if we are already at debug level (since we cannot go lower)
   if (lowestLogLevel_ == LogLevel::DEBUG)
      return;

   // now, override it with the lowest log level specified for named loggers
   std::vector<std::string> sectionNames = profile_.getLevelNames(kLogSectionLevel);
   for (const std::string& name : sectionNames)
   {
      profile_.getParam(
         kLogLevel, &logLevel, {{ kBaseLevel,       std::string() },
                                { kBinaryLevel,     executableName_ },
                                { kLogSectionLevel, name }});
      LogLevel level = strToLogLevel(logLevel);
      if (level > lowestLogLevel_)
         lowestLogLevel_ = level;

      if (lowestLogLevel_ == LogLevel::DEBUG)
         return;
   }
}

LogLevel LogOptions::logLevel(const std::string& loggerName) const
{
   std::vector<ConfigProfile::Level> levels = getLevels(loggerName);

   std::string logLevel = defaultLogLevel_;

   profile_.getParam(kLogLevel, &logLevel, levels);

   return strToLogLevel(logLevel);
}

LogLevel LogOptions::lowestLogLevel() const
{
   return lowestLogLevel_;
}

LoggerType LogOptions::loggerType(const std::string& loggerName) const
{
   std::vector<ConfigProfile::Level> levels = getLevels(loggerName);

   std::string loggerType = defaultLoggerType_;

   profile_.getParam(kLoggerType, &loggerType, levels);

   return strToLoggerType(loggerType);
}

LoggerOptions LogOptions::loggerOptions(const std::string& loggerName) const
{
   LoggerType type = loggerType(loggerName);

   switch (type)
   {
      case LoggerType::kFile:
      {
         std::vector<ConfigProfile::Level> levels = getLevels(loggerName);

         std::string logDir, fileMode;
         bool rotate, includePid;
         double maxSizeMb;

         profile_.getParam(kLogDir, &logDir, levels);
         profile_.getParam(kRotate, &rotate, levels);
         profile_.getParam(kMaxSizeMb, &maxSizeMb, levels);
         profile_.getParam(kLogFileIncludePid, &includePid, levels);
         profile_.getParam(kLogFileMode, &fileMode, levels);

         return FileLogOptions(FilePath(logDir), fileMode, maxSizeMb, rotate, includePid);
      }

      case LoggerType::kStdErr:
         return StdErrLogOptions();

      case LoggerType::kSysLog:
         return SysLogOptions();

      default:
         return SysLogOptions();
   }
}

std::vector<ConfigProfile::Level> LogOptions::getLevels(const std::string& loggerName) const
{
   std::vector<ConfigProfile::Level> levels = {{ kBaseLevel,   std::string() },
                                               { kBinaryLevel, executableName_ }};
   if (!loggerName.empty())
      levels.emplace_back(kLogSectionLevel, loggerName);
   return levels;
}

std::vector<std::string> LogOptions::loggerOverrides() const
{
   return profile_.getLevelNames(kLogSectionLevel);
}

} // namespace log
} // namespace core
} // namespace rstudio
<commit_msg>rebalance colons<commit_after>/*
 * LogOptions.cpp
 *
 * Copyright (C) 2020 by RStudio, PBC
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include <core/LogOptions.hpp>

#include <vector>

#include <core/system/Environment.hpp>
#include <core/system/System.hpp>
#include <core/system/Xdg.hpp>

#include "config.h"

namespace rstudio {
namespace core {
namespace log {

#define kLogLevel          "log-level"
#define kLoggerType        "logger-type"
#define kLogDir            "log-dir"
#define kLogFileMode       "log-file-mode"
#define kLogFileIncludePid "log-file-include-pid"
#define kRotate            "rotate"
#define kMaxSizeMb         "max-size-mb"
#define kLogConfFile       "logging.conf"
#define kLogConfEnvVar     "RS_LOG_CONF_FILE"

#define kFileLogger        "file"
#define kStdErrLogger      "stderr"
#define kSysLogger         "syslog"

#define kLoggingLevelDebug "debug"
#define kLoggingLevelInfo  "info"
#define kLoggingLevelWarn  "warn"
#define kLoggingLevelError "error"

#define kBaseLevel       0
#define kBinaryLevel     1
#define kLogSectionLevel 2

namespace {

// pick default log path location
#ifdef RSTUDIO_SERVER
const FilePath kDefaultLogPath("/var/log/rstudio-server");
#else
// desktop - store logs under user dir
const FilePath kDefaultLogPath = core::system::xdg::userDataDir().completePath("log");
#endif

std::string logLevelToString(LogLevel logLevel)
{
   switch (logLevel)
   {
      case LogLevel::DEBUG:
         return kLoggingLevelDebug;
      case LogLevel::INFO:
         return kLoggingLevelInfo;
      case LogLevel::WARN:
         return kLoggingLevelWarn;
      case LogLevel::ERR:
         return kLoggingLevelError;
      case LogLevel::OFF:
      default:
         return kLoggingLevelWarn;
   }
}

std::string loggerTypeToString(LoggerType loggerType)
{
   switch (loggerType)
   {
      case LoggerType::kFile:
         return kFileLogger;
      case LoggerType::kStdErr:
         return kStdErrLogger;
      case LoggerType::kSysLog:
         return kSysLogger;
      default:
         return kSysLogger;
   }
}

LogLevel strToLogLevel(const std::string& logLevelStr)
{
   if (logLevelStr == kLoggingLevelWarn)
      return LogLevel::WARN;
   else if (logLevelStr == kLoggingLevelError)
       return LogLevel::ERR;
   else if (logLevelStr == kLoggingLevelInfo)
       return LogLevel::INFO;
   else if (logLevelStr == kLoggingLevelDebug)
       return LogLevel::DEBUG;
   else
       return LogLevel::WARN;
}

LoggerType strToLoggerType(const std::string& loggerTypeStr)
{
   if (loggerTypeStr == kSysLogger)
      return LoggerType::kSysLog;
   else if (loggerTypeStr == kFileLogger)
      return LoggerType::kFile;
   else if (loggerTypeStr == kStdErrLogger)
      return LoggerType::kStdErr;
   else
      return LoggerType::kSysLog;
}

struct LoggerOptionsVisitor : boost::static_visitor<>
{
   LoggerOptionsVisitor(ConfigProfile& profile) :
      profile_(profile)
   {
   }

   void setDefaultFileLoggerOptions()
   {
      FileLogOptions defaultOptions(kDefaultLogPath);
      profile_.addParams(
         kLogDir, defaultOptions.getDirectory().getAbsolutePath(),
         kLogFileMode, defaultOptions.getFileMode(),
         kRotate, defaultOptions.doRotation(),
         kLogFileIncludePid, defaultOptions.includePid(),
         kMaxSizeMb, defaultOptions.getMaxSizeMb());
   }

   void operator()(const StdErrLogOptions& options)
   {
      setDefaultFileLoggerOptions();
   }

   void operator()(const SysLogOptions& options)
   {
      setDefaultFileLoggerOptions();
   }

   void operator()(const FileLogOptions& options)
   {
      // set file logger option defaults to those that were passed in
      profile_.addParams(
         kLogDir, options.getDirectory().getAbsolutePath(),
         kRotate, options.doRotation(),
         kMaxSizeMb, options.getMaxSizeMb(),
         kLogFileIncludePid, options.includePid(),
         kLogFileMode, options.getFileMode());
   }

   ConfigProfile& profile_;
};

} // anonymous namespace

LogOptions::LogOptions(const std::string& executableName) :
   executableName_(executableName),
   defaultLogLevel_(logLevelToString(LogLevel::WARN)),
   defaultLoggerType_(loggerTypeToString(LoggerType::kSysLog)),
   defaultLoggerOptions_(SysLogOptions()),
   lowestLogLevel_(LogLevel::WARN)
{
   initProfile();
}

LogOptions::LogOptions(const std::string& executableName,
                       LogLevel logLevel,
                       LoggerType loggerType,
                       const LoggerOptions& options) :
   executableName_(executableName),
   defaultLogLevel_(logLevelToString(logLevel)),
   defaultLoggerType_(loggerTypeToString(loggerType)),
   defaultLoggerOptions_(options),
   lowestLogLevel_(logLevel)
{
   initProfile();
}

void LogOptions::initProfile()
{
   // base level - * (applies to all loggers/binaries)
   // first override - @ (specific binary)
   // second override - (logger name)
   profile_.addSections(
      {{ kBaseLevel,       "*" },
       { kBinaryLevel,     "@" },
       { kLogSectionLevel, std::string() }});

   // add base params
   profile_.addParams(
      kLogLevel, defaultLogLevel_,
      kLoggerType, defaultLoggerType_);

   // add logger-specific params
   LoggerOptionsVisitor visitor(profile_);
   boost::apply_visitor(visitor, defaultLoggerOptions_);
}

Error LogOptions::read()
{
   // first, look for config file in a specific environment variable
   FilePath optionsFile(core::system::getenv(kLogConfEnvVar));
   if (!optionsFile.exists())
   {
   #ifdef RSTUDIO_SERVER
      optionsFile = core::system::xdg::systemConfigFile(kLogConfFile);
   #else
      // desktop - read user file first, and only read admin file if the user file does not exist
      optionsFile = core::system::xdg::userConfigDir().completeChildPath(kLogConfFile);
      if (!optionsFile.exists())
            optionsFile = core::system::xdg::systemConfigFile(kLogConfFile);
   #endif
   }

   // if the options file does not exist, that's fine - we'll just use default values
   if (!optionsFile.exists())
      return Success();

   Error error = profile_.load(optionsFile);
   if (error)
      return error;

   setLowestLogLevel();

   return Success();
}

void LogOptions::setLowestLogLevel()
{
   // first, set the log level for this particular binary
   std::string logLevel;
   profile_.getParam(
      kLogLevel, &logLevel, {{ kBaseLevel,   std::string() },
                             { kBinaryLevel, executableName_ }});
   lowestLogLevel_ = strToLogLevel(logLevel);

   // break out early if we are already at debug level (since we cannot go lower)
   if (lowestLogLevel_ == LogLevel::DEBUG)
      return;

   // now, override it with the lowest log level specified for named loggers
   std::vector<std::string> sectionNames = profile_.getLevelNames(kLogSectionLevel);
   for (const std::string& name : sectionNames)
   {
      profile_.getParam(
         kLogLevel, &logLevel, {{ kBaseLevel,       std::string() },
                                { kBinaryLevel,     executableName_ },
                                { kLogSectionLevel, name }});
      LogLevel level = strToLogLevel(logLevel);
      if (level > lowestLogLevel_)
         lowestLogLevel_ = level;

      if (lowestLogLevel_ == LogLevel::DEBUG)
         return;
   }
}

LogLevel LogOptions::logLevel(const std::string& loggerName) const
{
   std::vector<ConfigProfile::Level> levels = getLevels(loggerName);

   std::string logLevel = defaultLogLevel_;

   profile_.getParam(kLogLevel, &logLevel, levels);

   return strToLogLevel(logLevel);
}

LogLevel LogOptions::lowestLogLevel() const
{
   return lowestLogLevel_;
}

LoggerType LogOptions::loggerType(const std::string& loggerName) const
{
   std::vector<ConfigProfile::Level> levels = getLevels(loggerName);

   std::string loggerType = defaultLoggerType_;

   profile_.getParam(kLoggerType, &loggerType, levels);

   return strToLoggerType(loggerType);
}

LoggerOptions LogOptions::loggerOptions(const std::string& loggerName) const
{
   LoggerType type = loggerType(loggerName);

   switch (type)
   {
      case LoggerType::kFile:
      {
         std::vector<ConfigProfile::Level> levels = getLevels(loggerName);

         std::string logDir, fileMode;
         bool rotate, includePid;
         double maxSizeMb;

         profile_.getParam(kLogDir, &logDir, levels);
         profile_.getParam(kRotate, &rotate, levels);
         profile_.getParam(kMaxSizeMb, &maxSizeMb, levels);
         profile_.getParam(kLogFileIncludePid, &includePid, levels);
         profile_.getParam(kLogFileMode, &fileMode, levels);

         return FileLogOptions(FilePath(logDir), fileMode, maxSizeMb, rotate, includePid);
      }

      case LoggerType::kStdErr:
         return StdErrLogOptions();

      case LoggerType::kSysLog:
         return SysLogOptions();

      default:
         return SysLogOptions();
   }
}

std::vector<ConfigProfile::Level> LogOptions::getLevels(const std::string& loggerName) const
{
   std::vector<ConfigProfile::Level> levels = {{ kBaseLevel,   std::string() },
                                               { kBinaryLevel, executableName_ }};
   if (!loggerName.empty())
      levels.emplace_back(kLogSectionLevel, loggerName);
   return levels;
}

std::vector<std::string> LogOptions::loggerOverrides() const
{
   return profile_.getLevelNames(kLogSectionLevel);
}

} // namespace log
} // namespace core
} // namespace rstudio
<|endoftext|>


<commit_before>// @(#)root/base:$Name:  $:$Id: TVirtualFitter.cxx,v 1.7 2004/01/20 17:59:38 rdm Exp $
// Author: Rene Brun   31/08/99
/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "TROOT.h"
#include "TVirtualFitter.h"
#include "TPluginManager.h"
#include "TEnv.h"
#include "Api.h"

TVirtualFitter *TVirtualFitter::fgFitter    = 0;
Int_t           TVirtualFitter::fgMaxpar    = 0;
Int_t           TVirtualFitter::fgMaxiter   = 5000;
Double_t        TVirtualFitter::fgPrecision = 1e-6;
Double_t        TVirtualFitter::fgErrorDef  = 1;
TString         TVirtualFitter::fgDefault   = "";

ClassImp(TVirtualFitter)

//______________________________________________________________________________
TVirtualFitter::TVirtualFitter()
{
   fMethodCall = 0;
   fFCN        = 0;
}

//______________________________________________________________________________
TVirtualFitter::~TVirtualFitter()
{
   // Cleanup virtual fitter.

   delete fMethodCall;
   fgFitter    = 0;
   fgMaxpar    = 0;
   fMethodCall = 0;
   fFCN        = 0;
}

//______________________________________________________________________________
TVirtualFitter *TVirtualFitter::Fitter(TObject *obj, Int_t maxpar)
{
   // Static function returning a pointer to the current fitter.
   // If the fitter does not exist, the default TFitter is created.

   if (fgFitter && maxpar > fgMaxpar) {
      delete fgFitter;
      fgFitter = 0;
   }

   if (!fgFitter) {
      TPluginHandler *h;
      if (fgDefault.Length() == 0) fgDefault = gEnv->GetValue("Root.Fitter","Minuit");
      if ((h = gROOT->GetPluginManager()->FindHandler("TVirtualFitter",fgDefault))) {
         if (h->LoadPlugin() == -1)
            return 0;
         fgFitter = (TVirtualFitter*) h->ExecPlugin(1, maxpar);
         fgMaxpar = maxpar;
      }
   }

   if (fgFitter) fgFitter->SetObjectFit(obj);
   return fgFitter;
}

//______________________________________________________________________________
const char *TVirtualFitter::GetDefaultFitter()
{
   // static: return the name of the default fitter

   return fgDefault.Data();
}

//______________________________________________________________________________
TVirtualFitter *TVirtualFitter::GetFitter()
{
   // static: return the current Fitter
   return fgFitter;
}

//______________________________________________________________________________
Int_t TVirtualFitter::GetMaxIterations()
{
   // static: Return the maximum number of iterations

   return fgMaxiter;
}

//______________________________________________________________________________
Double_t TVirtualFitter::GetErrorDef()
{
   // static: Return the Error Definition

   return fgErrorDef;
}

//______________________________________________________________________________
Double_t TVirtualFitter::GetPrecision()
{
   // static: Return the fit relative precision

   return fgPrecision;
}

//______________________________________________________________________________
void TVirtualFitter::SetDefaultFitter(const char *name)
{
   // static: set name of default fitter

   if (fgDefault == name) return;
   delete fgFitter;
   fgFitter = 0;
   fgDefault = name;
}

//______________________________________________________________________________
void TVirtualFitter::SetFitter(TVirtualFitter *fitter, Int_t maxpar)
{
   // Static function to set an alternative fitter

   fgFitter = fitter;
   fgMaxpar = maxpar;
}

//______________________________________________________________________________
void TVirtualFitter::SetFCN(void (*fcn)(Int_t &, Double_t *, Double_t &f, Double_t *, Int_t))
{
   // To set the address of the minimization objective function
   // called by the native compiler (see function below when called by CINT)

   fFCN = fcn;
}

//______________________________________________________________________________
void InteractiveFCN(Int_t &npar, Double_t *gin, Double_t &f, Double_t *u, Int_t flag)
{
   // Static function called when SetFCN is called in interactive mode

   TMethodCall *m = TVirtualFitter::GetFitter()->GetMethodCall();
   if (!m) return;

   Long_t args[5];
   args[0] = (Long_t)∦
   args[1] = (Long_t)gin;
   args[2] = (Long_t)&f;
   args[3] = (Long_t)u;
   args[4] = (Long_t)flag;
   m->SetParamPtrs(args);
   Double_t result;
   m->Execute(result);
}

//______________________________________________________________________________
void TVirtualFitter::SetFCN(void *fcn)
{
   //  To set the address of the minimization objective function
   //
   //     this function is called by CINT instead of the function above

   if (!fcn) return;

   char *funcname = G__p2f2funcname(fcn);
   if (funcname) {
      delete fMethodCall;
      fMethodCall = new TMethodCall();
      fMethodCall->InitWithPrototype(funcname,"Int_t&,Double_t*,Double_t&,Double_t*,Int_t");
    }
   fFCN = InteractiveFCN;
}

//______________________________________________________________________________
void TVirtualFitter::SetMaxIterations(Int_t niter)
{
   // static: Set the maximum number of iterations

   fgMaxiter  = niter;
}

//______________________________________________________________________________
void TVirtualFitter::SetErrorDef(Double_t errdef)
{
   // static: Set the Error Definition (default=1)

   fgErrorDef = errdef;
   if (!fgFitter) return;
   Double_t arglist[1];
   arglist[0] = errdef;
   fgFitter->ExecuteCommand("SET ERRORDEF", arglist, 1);
}

//______________________________________________________________________________
void TVirtualFitter::SetPrecision(Double_t prec)
{
   // static: Set the fit relative precision

   fgPrecision = prec;
}
<commit_msg>add comment explaining not to delete the returned fitter object since it will be re-used.<commit_after>// @(#)root/base:$Name:  $:$Id: TVirtualFitter.cxx,v 1.8 2005/06/14 13:28:41 brun Exp $
// Author: Rene Brun   31/08/99
/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "TROOT.h"
#include "TVirtualFitter.h"
#include "TPluginManager.h"
#include "TEnv.h"
#include "Api.h"

TVirtualFitter *TVirtualFitter::fgFitter    = 0;
Int_t           TVirtualFitter::fgMaxpar    = 0;
Int_t           TVirtualFitter::fgMaxiter   = 5000;
Double_t        TVirtualFitter::fgPrecision = 1e-6;
Double_t        TVirtualFitter::fgErrorDef  = 1;
TString         TVirtualFitter::fgDefault   = "";

ClassImp(TVirtualFitter)

//______________________________________________________________________________
TVirtualFitter::TVirtualFitter()
{
   fMethodCall = 0;
   fFCN        = 0;
}

//______________________________________________________________________________
TVirtualFitter::~TVirtualFitter()
{
   // Cleanup virtual fitter.

   delete fMethodCall;
   fgFitter    = 0;
   fgMaxpar    = 0;
   fMethodCall = 0;
   fFCN        = 0;
}

//______________________________________________________________________________
TVirtualFitter *TVirtualFitter::Fitter(TObject *obj, Int_t maxpar)
{
   // Static function returning a pointer to the current fitter.
   // If the fitter does not exist, the default TFitter is created.
   // Don't delete the returned fitter object, it will be re-used.

   if (fgFitter && maxpar > fgMaxpar) {
      delete fgFitter;
      fgFitter = 0;
   }

   if (!fgFitter) {
      TPluginHandler *h;
      if (fgDefault.Length() == 0) fgDefault = gEnv->GetValue("Root.Fitter","Minuit");
      if ((h = gROOT->GetPluginManager()->FindHandler("TVirtualFitter",fgDefault))) {
         if (h->LoadPlugin() == -1)
            return 0;
         fgFitter = (TVirtualFitter*) h->ExecPlugin(1, maxpar);
         fgMaxpar = maxpar;
      }
   }

   if (fgFitter) fgFitter->SetObjectFit(obj);
   return fgFitter;
}

//______________________________________________________________________________
const char *TVirtualFitter::GetDefaultFitter()
{
   // static: return the name of the default fitter

   return fgDefault.Data();
}

//______________________________________________________________________________
TVirtualFitter *TVirtualFitter::GetFitter()
{
   // static: return the current Fitter
   return fgFitter;
}

//______________________________________________________________________________
Int_t TVirtualFitter::GetMaxIterations()
{
   // static: Return the maximum number of iterations

   return fgMaxiter;
}

//______________________________________________________________________________
Double_t TVirtualFitter::GetErrorDef()
{
   // static: Return the Error Definition

   return fgErrorDef;
}

//______________________________________________________________________________
Double_t TVirtualFitter::GetPrecision()
{
   // static: Return the fit relative precision

   return fgPrecision;
}

//______________________________________________________________________________
void TVirtualFitter::SetDefaultFitter(const char *name)
{
   // static: set name of default fitter

   if (fgDefault == name) return;
   delete fgFitter;
   fgFitter = 0;
   fgDefault = name;
}

//______________________________________________________________________________
void TVirtualFitter::SetFitter(TVirtualFitter *fitter, Int_t maxpar)
{
   // Static function to set an alternative fitter

   fgFitter = fitter;
   fgMaxpar = maxpar;
}

//______________________________________________________________________________
void TVirtualFitter::SetFCN(void (*fcn)(Int_t &, Double_t *, Double_t &f, Double_t *, Int_t))
{
   // To set the address of the minimization objective function
   // called by the native compiler (see function below when called by CINT)

   fFCN = fcn;
}

//______________________________________________________________________________
void InteractiveFCN(Int_t &npar, Double_t *gin, Double_t &f, Double_t *u, Int_t flag)
{
   // Static function called when SetFCN is called in interactive mode

   TMethodCall *m = TVirtualFitter::GetFitter()->GetMethodCall();
   if (!m) return;

   Long_t args[5];
   args[0] = (Long_t)∦
   args[1] = (Long_t)gin;
   args[2] = (Long_t)&f;
   args[3] = (Long_t)u;
   args[4] = (Long_t)flag;
   m->SetParamPtrs(args);
   Double_t result;
   m->Execute(result);
}

//______________________________________________________________________________
void TVirtualFitter::SetFCN(void *fcn)
{
   //  To set the address of the minimization objective function
   //
   //     this function is called by CINT instead of the function above

   if (!fcn) return;

   char *funcname = G__p2f2funcname(fcn);
   if (funcname) {
      delete fMethodCall;
      fMethodCall = new TMethodCall();
      fMethodCall->InitWithPrototype(funcname,"Int_t&,Double_t*,Double_t&,Double_t*,Int_t");
    }
   fFCN = InteractiveFCN;
}

//______________________________________________________________________________
void TVirtualFitter::SetMaxIterations(Int_t niter)
{
   // static: Set the maximum number of iterations

   fgMaxiter  = niter;
}

//______________________________________________________________________________
void TVirtualFitter::SetErrorDef(Double_t errdef)
{
   // static: Set the Error Definition (default=1)

   fgErrorDef = errdef;
   if (!fgFitter) return;
   Double_t arglist[1];
   arglist[0] = errdef;
   fgFitter->ExecuteCommand("SET ERRORDEF", arglist, 1);
}

//______________________________________________________________________________
void TVirtualFitter::SetPrecision(Double_t prec)
{
   // static: Set the fit relative precision

   fgPrecision = prec;
}
<|endoftext|>


<commit_before>#include "gen.h"
#include <cstdio>
#include <algorithm>
#include <tuple>
#include <vector>
#include <numeric>
using namespace std;

struct BiEdge {
    vid_t from, to;
    weight_t w;

    bool operator<(const BiEdge& o) const {
        return w < o.w;
    }
} *biedges;
eid_t biEdgesCount;

struct  {
    vid_t *cmp;

    void init(vid_t n) {
        cmp = static_cast<vid_t*>(malloc(sizeof(vid_t) * n));
        iota(cmp, cmp + n, 0);
    }

    vid_t get(vid_t v) {
        return cmp[v] == v ? v : cmp[v] = get(cmp[v]);
    }

    void merge(vid_t v, vid_t u) {
        //if (rand()&1) swap(v, u);
        cmp[v] = u;
    }

} snm;

int main(int argc, char *argv[]) {
    if (argc < 2) {
        fprintf(stderr, "Usage: %s input\n", argv[0]);
        return 1;
    }

    int64_t timeRead = -currentNanoTime();
    readAll(argv[1]);
    timeRead += currentNanoTime();

    int64_t timeInit = -currentNanoTime();
    biedges = static_cast<BiEdge*>(malloc(sizeof(BiEdge) * edgesCount));
    for (vid_t v = 0; v < vertexCount; ++v) {
        for (eid_t i = edgesIds[v]; i < edgesIds[v + 1]; ++i) {
            const vid_t u = edges[i].dest;
            if (u <= v) continue;
            const weight_t w = edges[i].weight;
            biedges[biEdgesCount++] = BiEdge{v, u, w};
        }
    }
    timeInit += currentNanoTime();

    int64_t timeSort = -currentNanoTime();
    sort(biedges, biedges + biEdgesCount);
    timeSort += currentNanoTime();

    int64_t timeBuild = -currentNanoTime();
    weight_t result = 0.0;
    snm.init(vertexCount);
    for (eid_t e = 0; e < biEdgesCount; ++e) {
        const int cv = snm.get(biedges[e].from);
        const int cu = snm.get(biedges[e].to);
        if (cv != cu) {
            result += biedges[e].w;
            snm.merge(cv, cu);
        }
    }
    timeBuild += currentNanoTime();

    printf("%.10lf\n", double(result));
    fprintf(stderr, "Read time: %.5lf\n", double(timeRead) / 1e6);
    fprintf(stderr, "Init time: %.5lf\n", double(timeInit) / 1e6);
    fprintf(stderr, "Sort time: %.5lf\n", double(timeSort) / 1e6);
    fprintf(stderr, "Bild time: %.5lf\n", double(timeBuild) / 1e6);

    return 0;
}
<commit_msg>Reference (Kruskal): fix time<commit_after>#include "gen.h"
#include <cstdio>
#include <algorithm>
#include <tuple>
#include <vector>
#include <numeric>
using namespace std;

struct BiEdge {
    vid_t from, to;
    weight_t w;

    bool operator<(const BiEdge& o) const {
        return w < o.w;
    }
} *biedges;
eid_t biEdgesCount;

struct  {
    vid_t *cmp;

    void init(vid_t n) {
        cmp = static_cast<vid_t*>(malloc(sizeof(vid_t) * n));
        iota(cmp, cmp + n, 0);
    }

    vid_t get(vid_t v) {
        return cmp[v] == v ? v : cmp[v] = get(cmp[v]);
    }

    void merge(vid_t v, vid_t u) {
        //if (rand()&1) swap(v, u);
        cmp[v] = u;
    }

} snm;

int main(int argc, char *argv[]) {
    if (argc < 2) {
        fprintf(stderr, "Usage: %s input\n", argv[0]);
        return 1;
    }

    int64_t timeRead = -currentNanoTime();
    readAll(argv[1]);
    timeRead += currentNanoTime();

    int64_t timeInit = -currentNanoTime();
    biedges = static_cast<BiEdge*>(malloc(sizeof(BiEdge) * edgesCount));
    for (vid_t v = 0; v < vertexCount; ++v) {
        for (eid_t i = edgesIds[v]; i < edgesIds[v + 1]; ++i) {
            const vid_t u = edges[i].dest;
            if (u <= v) continue;
            const weight_t w = edges[i].weight;
            biedges[biEdgesCount++] = BiEdge{v, u, w};
        }
    }
    timeInit += currentNanoTime();

    int64_t timeSort = -currentNanoTime();
    sort(biedges, biedges + biEdgesCount);
    timeSort += currentNanoTime();

    int64_t timeBuild = -currentNanoTime();
    weight_t result = 0.0;
    snm.init(vertexCount);
    for (eid_t e = 0; e < biEdgesCount; ++e) {
        const int cv = snm.get(biedges[e].from);
        const int cu = snm.get(biedges[e].to);
        if (cv != cu) {
            result += biedges[e].w;
            snm.merge(cv, cu);
        }
    }
    timeBuild += currentNanoTime();

    printf("%.10lf\n", double(result));
    fprintf(stderr, "Read time: %.5lf\n", double(timeRead) / 1e9);
    fprintf(stderr, "Init time: %.5lf\n", double(timeInit) / 1e9);
    fprintf(stderr, "Sort time: %.5lf\n", double(timeSort) / 1e9);
    fprintf(stderr, "Bild time: %.5lf\n", double(timeBuild) / 1e9);
    fprintf(stderr, "\n");
    fprintf(stderr, "%.3lf\n%.3lf\n", double(timeRead + timeInit) / 1e9, double(timeSort + timeBuild) / 1e9);

    return 0;
}
<|endoftext|>


<commit_before>/*
 * This is part of the FL library, a C++ Bayesian filtering library
 * (https://github.com/filtering-library)
 *
 * Copyright (c) 2014 Jan Issac (jan.issac@gmail.com)
 * Copyright (c) 2014 Manuel Wuthrich (manuel.wuthrich@gmail.com)
 *
 * Max-Planck Institute for Intelligent Systems, AMD Lab
 * University of Southern California, CLMC Lab
 *
 * This Source Code Form is subject to the terms of the MIT License (MIT).
 * A copy of the license can be found in the LICENSE file distributed with this
 * source code.
 */

/**
 * \file unscented_transform.hpp
 * \date October 2014
 * \author Jan Issac (jan.issac@gmail.com)
 */

#ifndef FL__FILTER__GAUSSIAN__UNSCENTED_TRANSFORM_HPP
#define FL__FILTER__GAUSSIAN__UNSCENTED_TRANSFORM_HPP

#include <fl/util/traits.hpp>
#include <fl/distribution/gaussian.hpp>
#include <fl/filter/gaussian/point_set_transform.hpp>

namespace fl
{

/**
 * \ingroup point_set_transform
 *
 * This is the Unscented Transform used in the Unscented Kalman Filter
 * \cite wan2000unscented . It implememnts the PointSetTransform interface.
 */
class UnscentedTransform
        : public PointSetTransform<UnscentedTransform>
{
public:
    /**
     * Creates a UnscentedTransform
     *
     * \param alpha     UT Scaling parameter alpha (distance to the mean)
     * \param beta      UT Scaling parameter beta  (2.0 is optimal for Gaussian)
     * \param kappa     UT Scaling parameter kappa (higher order parameter)
     */
    UnscentedTransform(double alpha = 1., double beta = 2., double kappa = 0.)
        : PointSetTransform<UnscentedTransform>(this),
          alpha_(alpha),
          beta_(beta),
          kappa_(kappa)
    { }

    /**
     * \copydoc PointSetTransform::forward(const Gaussian&,
     *                                     PointSet&) const
     *
     * \throws WrongSizeException
     * \throws ResizingFixedSizeEntityException
     */
    template <typename Gaussian_, typename PointSet_>
    void forward(const Gaussian_& gaussian,
                 PointSet_& point_set) const
    {
        forward(gaussian, gaussian.dimension(), 0, point_set);
    }

    /**
     * \copydoc PointSetTransform::forward(const Gaussian&,
     *                                     int global_dimension,
     *                                     int dimension_offset,
     *                                     PointSet&) const
     *
     * \throws WrongSizeException
     * \throws ResizingFixedSizeEntityException
     */
    template <typename Gaussian_, typename PointSet_>
    void forward(const Gaussian_& gaussian,
                 int global_dimension,
                 int dimension_offset,
                 PointSet_& point_set) const
    {
        typedef typename Traits<PointSet_>::Point  Point;
        typedef typename Traits<PointSet_>::Weight Weight;

        const double dim = double(global_dimension);
        const int point_count = number_of_points(dim);

        assert(point_count > 0);

        /**
         * \internal
         *
         * \remark
         * A PointSet with a fixed number of points must have the
         * correct number of points which is required by this transform
         */
        if (IsFixed<Traits<PointSet_>::NumberOfPoints>() &&
            Traits<PointSet_>::NumberOfPoints != point_count)
        {
            fl_throw(
                WrongSizeException("Incompatible number of points of the"
                                   " specified fixed-size PointSet"));
        }

        // will resize of transform size is different from point count.
        point_set.resize(size_t(point_count));

        auto&& covariance_sqrt = gaussian.square_root() * gamma_factor(dim);

        Point point_shift;
        const Point& mean = gaussian.mean();

        // set the first point
        point_set.point(0, mean, Weight{weight_mean_0(dim), weight_cov_0(dim)});

        // compute the remaining points
        Weight weight_i{weight_mean_i(dim), weight_cov_i(dim)};

        // use squential loops to enable loop unrolling
        const int start_1 = 1;
        const int limit_1 = start_1 + dimension_offset;
        const int limit_2 = limit_1 + gaussian.dimension();
        const int limit_3 = global_dimension;

        for (int i = start_1; i < limit_1; ++i)
        {
            point_set.point(i, mean, weight_i);
            point_set.point(global_dimension + i, mean, weight_i);
        }

        for (int i = limit_1; i < limit_2; ++i)
        {
            point_shift = covariance_sqrt.col(i - dimension_offset - 1);
            point_set.point(i, mean + point_shift, weight_i);
            point_set.point(global_dimension + i, mean - point_shift, weight_i);
        }

        for (int i = limit_2; i <= limit_3; ++i)
        {
            point_set.point(i, mean, weight_i);
            point_set.point(global_dimension + i, mean, weight_i);
        }
    }

    /**
     * \return Number of points generated by this transform
     *
     * \param dimension Dimension of the Gaussian
     */
    static constexpr int number_of_points(int dimension)
    {
        return (dimension != Eigen::Dynamic) ? 2 * dimension + 1 : -1;
    }

public:
    /** \cond INTERNAL */

    /**
     * \return First mean weight
     *
     * \param dim Dimension of the Gaussian
     */
    double weight_mean_0(double dim) const
    {
        return lambda_scalar(dim) / (dim + lambda_scalar(dim));
    }

    /**
     * \return First covariance weight
     *
     * \param dim Dimension of the Gaussian
     */
    double weight_cov_0(double dim) const
    {
        return weight_mean_0(dim) + (1 - alpha_ * alpha_ + beta_);
    }

    /**
     * \return i-th mean weight
     *
     * \param dimension Dimension of the Gaussian
     */
    double weight_mean_i(double dim) const
    {
        return 1. / (2. * (dim + lambda_scalar(dim)));
    }

    /**
     * \return i-th covariance weight
     *
     * \param dimension Dimension of the Gaussian
     */
    double weight_cov_i(double dim) const
    {
        return weight_mean_i(dim);
    }

    /**
     * \param dim Dimension of the Gaussian
     */
    double lambda_scalar(double dim) const
    {
        return alpha_ * alpha_ * (dim + kappa_) - dim;
    }

    /**
     * \param dim  Dimension of the Gaussian
     */
    double gamma_factor(double dim) const
    {
        return std::sqrt(dim + lambda_scalar(dim));
    }
    /** \endcond */

protected:
    /** \cond INTERNAL */
    double alpha_;
    double beta_;
    double kappa_;
    /** \endcond */
};

}

#endif
<commit_msg>remove size_t conversion on point_count<commit_after>/*
 * This is part of the FL library, a C++ Bayesian filtering library
 * (https://github.com/filtering-library)
 *
 * Copyright (c) 2014 Jan Issac (jan.issac@gmail.com)
 * Copyright (c) 2014 Manuel Wuthrich (manuel.wuthrich@gmail.com)
 *
 * Max-Planck Institute for Intelligent Systems, AMD Lab
 * University of Southern California, CLMC Lab
 *
 * This Source Code Form is subject to the terms of the MIT License (MIT).
 * A copy of the license can be found in the LICENSE file distributed with this
 * source code.
 */

/**
 * \file unscented_transform.hpp
 * \date October 2014
 * \author Jan Issac (jan.issac@gmail.com)
 */

#ifndef FL__FILTER__GAUSSIAN__UNSCENTED_TRANSFORM_HPP
#define FL__FILTER__GAUSSIAN__UNSCENTED_TRANSFORM_HPP

#include <fl/util/traits.hpp>
#include <fl/distribution/gaussian.hpp>
#include <fl/filter/gaussian/point_set_transform.hpp>

namespace fl
{

/**
 * \ingroup point_set_transform
 *
 * This is the Unscented Transform used in the Unscented Kalman Filter
 * \cite wan2000unscented . It implememnts the PointSetTransform interface.
 */
class UnscentedTransform
        : public PointSetTransform<UnscentedTransform>
{
public:
    /**
     * Creates a UnscentedTransform
     *
     * \param alpha     UT Scaling parameter alpha (distance to the mean)
     * \param beta      UT Scaling parameter beta  (2.0 is optimal for Gaussian)
     * \param kappa     UT Scaling parameter kappa (higher order parameter)
     */
    UnscentedTransform(double alpha = 1., double beta = 2., double kappa = 0.)
        : PointSetTransform<UnscentedTransform>(this),
          alpha_(alpha),
          beta_(beta),
          kappa_(kappa)
    { }

    /**
     * \copydoc PointSetTransform::forward(const Gaussian&,
     *                                     PointSet&) const
     *
     * \throws WrongSizeException
     * \throws ResizingFixedSizeEntityException
     */
    template <typename Gaussian_, typename PointSet_>
    void forward(const Gaussian_& gaussian,
                 PointSet_& point_set) const
    {
        forward(gaussian, gaussian.dimension(), 0, point_set);
    }

    /**
     * \copydoc PointSetTransform::forward(const Gaussian&,
     *                                     int global_dimension,
     *                                     int dimension_offset,
     *                                     PointSet&) const
     *
     * \throws WrongSizeException
     * \throws ResizingFixedSizeEntityException
     */
    template <typename Gaussian_, typename PointSet_>
    void forward(const Gaussian_& gaussian,
                 int global_dimension,
                 int dimension_offset,
                 PointSet_& point_set) const
    {
        typedef typename Traits<PointSet_>::Point  Point;
        typedef typename Traits<PointSet_>::Weight Weight;

        const double dim = double(global_dimension);
        const int point_count = number_of_points(dim);

        assert(point_count > 0);

        /**
         * \internal
         *
         * \remark
         * A PointSet with a fixed number of points must have the
         * correct number of points which is required by this transform
         */
        if (IsFixed<Traits<PointSet_>::NumberOfPoints>() &&
            Traits<PointSet_>::NumberOfPoints != point_count)
        {
            fl_throw(
                WrongSizeException("Incompatible number of points of the"
                                   " specified fixed-size PointSet"));
        }

        // will resize of transform size is different from point count.
        point_set.resize(point_count);

        auto&& covariance_sqrt = gaussian.square_root() * gamma_factor(dim);

        Point point_shift;
        const Point& mean = gaussian.mean();

        // set the first point
        point_set.point(0, mean, Weight{weight_mean_0(dim), weight_cov_0(dim)});

        // compute the remaining points
        Weight weight_i{weight_mean_i(dim), weight_cov_i(dim)};

        // use squential loops to enable loop unrolling
        const int start_1 = 1;
        const int limit_1 = start_1 + dimension_offset;
        const int limit_2 = limit_1 + gaussian.dimension();
        const int limit_3 = global_dimension;

        for (int i = start_1; i < limit_1; ++i)
        {
            point_set.point(i, mean, weight_i);
            point_set.point(global_dimension + i, mean, weight_i);
        }

        for (int i = limit_1; i < limit_2; ++i)
        {
            point_shift = covariance_sqrt.col(i - dimension_offset - 1);
            point_set.point(i, mean + point_shift, weight_i);
            point_set.point(global_dimension + i, mean - point_shift, weight_i);
        }

        for (int i = limit_2; i <= limit_3; ++i)
        {
            point_set.point(i, mean, weight_i);
            point_set.point(global_dimension + i, mean, weight_i);
        }
    }

    /**
     * \return Number of points generated by this transform
     *
     * \param dimension Dimension of the Gaussian
     */
    static constexpr int number_of_points(int dimension)
    {
        return (dimension != Eigen::Dynamic) ? 2 * dimension + 1 : -1;
    }

public:
    /** \cond INTERNAL */

    /**
     * \return First mean weight
     *
     * \param dim Dimension of the Gaussian
     */
    double weight_mean_0(double dim) const
    {
        return lambda_scalar(dim) / (dim + lambda_scalar(dim));
    }

    /**
     * \return First covariance weight
     *
     * \param dim Dimension of the Gaussian
     */
    double weight_cov_0(double dim) const
    {
        return weight_mean_0(dim) + (1 - alpha_ * alpha_ + beta_);
    }

    /**
     * \return i-th mean weight
     *
     * \param dimension Dimension of the Gaussian
     */
    double weight_mean_i(double dim) const
    {
        return 1. / (2. * (dim + lambda_scalar(dim)));
    }

    /**
     * \return i-th covariance weight
     *
     * \param dimension Dimension of the Gaussian
     */
    double weight_cov_i(double dim) const
    {
        return weight_mean_i(dim);
    }

    /**
     * \param dim Dimension of the Gaussian
     */
    double lambda_scalar(double dim) const
    {
        return alpha_ * alpha_ * (dim + kappa_) - dim;
    }

    /**
     * \param dim  Dimension of the Gaussian
     */
    double gamma_factor(double dim) const
    {
        return std::sqrt(dim + lambda_scalar(dim));
    }
    /** \endcond */

protected:
    /** \cond INTERNAL */
    double alpha_;
    double beta_;
    double kappa_;
    /** \endcond */
};

}

#endif
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
/// @brief application server scheduler implementation
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-2011 triagens GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
/// @author Copyright 2009-2011, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#include "ApplicationServerSchedulerImpl.h"

#include <Basics/Exceptions.h>
#include <Basics/Logger.h>
#include <Rest/PeriodicTask.h>
#include <Rest/SignalTask.h>

#include "Scheduler/SchedulerLibev.h"

using namespace std;
using namespace triagens::basics;
using namespace triagens::rest;

// -----------------------------------------------------------------------------
// helper classes and methods
// -----------------------------------------------------------------------------

namespace {

  ////////////////////////////////////////////////////////////////////////////////
  /// @brief handles control-c
  ////////////////////////////////////////////////////////////////////////////////

  class ControlCTask : public SignalTask {
    public:
      ControlCTask (ApplicationServer* server)
        : Task("Control-C"), SignalTask(), server(server) {
        addSignal(SIGINT);
        addSignal(SIGTERM);
        addSignal(SIGQUIT);
      }

    public:
      bool handleSignal () {
        LOGGER_INFO << "control-c received, shutting down";

        server->beginShutdown();

        return true;
      }

    private:
      ApplicationServer* server;
  };

  ////////////////////////////////////////////////////////////////////////////////
  /// @brief handles Hangup
  ////////////////////////////////////////////////////////////////////////////////

  class HangupTask : public SignalTask {
    public:
      HangupTask (ApplicationServerSchedulerImpl* server)
        : Task("Hangup"), SignalTask(), server(server) {
        addSignal(SIGHUP);
      }

    public:
      bool handleSignal () {
        LOGGER_INFO << "Hangup received, reopen logfile";
        TRI_ReopenLogging();
        LOGGER_INFO << "Hangup received, reopen logfile";
        return true;
      }

    private:
      ApplicationServerSchedulerImpl* server;
  };

  ////////////////////////////////////////////////////////////////////////////////
  /// @brief produces a scheduler status report
  ////////////////////////////////////////////////////////////////////////////////

  class SchedulerReporterTask : public PeriodicTask {
    public:
      SchedulerReporterTask (Scheduler* scheduler, double _reportIntervall)
        : Task("Scheduler-Reporter"), PeriodicTask(_reportIntervall * 0.1, _reportIntervall), scheduler(scheduler) {
      }

    public:
      bool handlePeriod () {
        scheduler->reportStatus();
        return true;
      }

    public:
      Scheduler* scheduler;
  };
}

namespace triagens {
  namespace rest {

    // -----------------------------------------------------------------------------
    // constructors and destructors
    // -----------------------------------------------------------------------------

    ApplicationServerSchedulerImpl::ApplicationServerSchedulerImpl (string const& description, string const& version)
      : ApplicationServerImpl(description, version),
        _reportIntervall(60.0),
        _multiSchedulerAllowed(false),
        _nrSchedulerThreads(1),
        _backend(0),
        reuseAddress(false),
        descriptorMinimum(0),

        _scheduler(0),
        _shutdownInProgress(false) {
    }

    ApplicationServerSchedulerImpl::~ApplicationServerSchedulerImpl () {

      // cleanup tasks and scheduler
      if (_scheduler != 0) {
        for (vector<Task*>::iterator i = _tasks.begin();  i != _tasks.end();  ++i) {
          _scheduler->destroyTask(*i);
        }

        delete _scheduler;
      }
    }

    // -----------------------------------------------------------------------------
    // public methods
    // -----------------------------------------------------------------------------

    void ApplicationServerSchedulerImpl::buildScheduler () {
      if (_scheduler != 0) {
        LOGGER_FATAL << "a scheduler has already been created";
        exit(EXIT_FAILURE);
      }

      _scheduler = new SchedulerLibev(_nrSchedulerThreads, _backend);
    }

    void ApplicationServerSchedulerImpl::buildSchedulerReporter () {
      if (0.0 < _reportIntervall) {
        registerTask(new SchedulerReporterTask(_scheduler, _reportIntervall));
      }
    }

    void ApplicationServerSchedulerImpl::buildControlCHandler () {
      if (_scheduler == 0) {
        LOGGER_FATAL << "no scheduler is known, cannot create control-c handler";
        exit(EXIT_FAILURE);
      }

      registerTask(new ControlCTask(this));
      registerTask(new HangupTask(this));
    }

    void ApplicationServerSchedulerImpl::installSignalHandler (SignalTask* task) {
      if (_scheduler == 0) {
        LOGGER_FATAL << "no scheduler is known, cannot install signal handler";
        exit(EXIT_FAILURE);
      }

      registerTask(task);
    }

    void ApplicationServerSchedulerImpl::start () {
      ApplicationServerImpl::start();

      if (_scheduler != 0) {
        bool ok = _scheduler->start(&_schedulerCond);

        if (! ok) {
          LOGGER_FATAL << "the scheduler cannot be started";
          exit(EXIT_FAILURE);
        }
      }
    }

    void ApplicationServerSchedulerImpl::wait () {
      ApplicationServerImpl::wait();

      if (_scheduler != 0) {
        bool ok = _schedulerCond.lock();

        if (! ok) {
          THROW_INTERNAL_ERROR("cannot lock scheduler condition");
        }

        while (_scheduler->isRunning()) {
          LOGGER_TRACE << "waiting for scheduler to stop";

          ok = _schedulerCond.wait();

          if (! ok) {
            THROW_INTERNAL_ERROR("cannot wait on scheduler condition");
          }
        }

        LOGGER_TRACE << "scheduler has stopped";

        ok = _schedulerCond.unlock();

        if (! ok) {
          THROW_INTERNAL_ERROR("cannot unlock scheduler condition");
        }
      }
    }

    void ApplicationServerSchedulerImpl::beginShutdown () {
      ApplicationServerImpl::beginShutdown();

      if (! _shutdownInProgress) {
        LOGGER_TRACE << "begin shutdown sequence of application server";

        if (_scheduler != 0) {
          _scheduler->beginShutdown();
        }

        _shutdownInProgress = true;
      }
      else {
        LOGGER_TRACE << "shutdown sequence of application server already initiated";
      }
    }

    void ApplicationServerSchedulerImpl::shutdown () {
      ApplicationServerImpl::shutdown();

      if (_scheduler != 0) {
        int count = 0;

        while (++count < 6 && _scheduler->isRunning()) {
          LOGGER_TRACE << "waiting for scheduler to stop";
          sleep(1);
        }
      }
    }

    // -----------------------------------------------------------------------------
    // protected methods
    // -----------------------------------------------------------------------------

    void ApplicationServerSchedulerImpl::registerTask (Task* task) {
      if (_scheduler == 0) {
        LOGGER_FATAL << "no scheduler is known, cannot create tasks";
        exit(EXIT_FAILURE);
      }

      _scheduler->registerTask(task);
      _tasks.push_back(task);
    }

    void ApplicationServerSchedulerImpl::setupOptions (map<string, ProgramOptionsDescription>& options) {
      ApplicationServerImpl::setupOptions(options);

      // .............................................................................
      // command line options
      // .............................................................................

      options[OPTIONS_CMDLINE + ":help-extended"]
        ("show-io-backends", "show available io backends")
      ;

      // .............................................................................
      // application server options
      // .............................................................................

      options[OPTIONS_SERVER + ":help-extended"]
        ("scheduler.backend", &_backend, "1: select, 2: poll, 4: epoll")
        ("server.reuse-address", "try to reuse address")
        ("server.report", &_reportIntervall, "report intervall")
#ifdef TRI_HAVE_GETRLIMIT
        ("server.descriptors-minimum", &descriptorMinimum, "minimum number of file descriptors needed to start")
#endif
      ;

      if (_multiSchedulerAllowed) {
        options[OPTIONS_SERVER + ":help-extended"]
          ("scheduler.threads", &_nrSchedulerThreads, "number of scheduler threads")
        ;
      }
    }

    bool ApplicationServerSchedulerImpl::parsePhase1 () {
      bool ok = ApplicationServerImpl::parsePhase1();

      if (! ok) {
        return false;
      }

      // show io backends
      if (options.has("show-io-backends")) {
        cout << "available io backends are: " << SchedulerLibev::availableBackends() << endl;
        exit(EXIT_SUCCESS);
      }

      return true;
    }

    bool ApplicationServerSchedulerImpl::parsePhase2 () {
      bool ok = ApplicationServerImpl::parsePhase2();

      if (! ok) {
        return false;
      }

      // check if want to reuse the address
      if (options.has("server.reuse-address")) {
        reuseAddress = true;
      }

      // adjust file descriptors
      adjustFileDescriptors();

      return true;
    }

    // -----------------------------------------------------------------------------
    // private methods
    // -----------------------------------------------------------------------------

    void ApplicationServerSchedulerImpl::adjustFileDescriptors () {
#ifdef TRI_HAVE_GETRLIMIT

      if (0 < descriptorMinimum) {
        struct rlimit rlim;
        int res = getrlimit(RLIMIT_NOFILE, &rlim);

        if (res != 0) {
          LOGGER_FATAL << "cannot get the file descriptor limit: " << strerror(errno) << "'";
          exit(EXIT_FAILURE);
        }

        LOGGER_DEBUG << "hard limit is " << rlim.rlim_max << ", soft limit is " << rlim.rlim_cur;

        bool changed = false;

        if (rlim.rlim_max < descriptorMinimum) {
          LOGGER_DEBUG << "hard limit " << rlim.rlim_max << " is too small, trying to raise";

          rlim.rlim_max = descriptorMinimum;
          rlim.rlim_cur = descriptorMinimum;

          res = setrlimit(RLIMIT_NOFILE, &rlim);

          if (res < 0) {
            LOGGER_FATAL << "cannot raise the file descriptor limit to '" << descriptorMinimum << "', got " << strerror(errno);
            exit(EXIT_FAILURE);
          }

          changed = true;
        }
        else if (rlim.rlim_cur < descriptorMinimum) {
          LOGGER_DEBUG << "soft limit " << rlim.rlim_cur << " is too small, trying to raise";

          rlim.rlim_cur = descriptorMinimum;

          res = setrlimit(RLIMIT_NOFILE, &rlim);

          if (res < 0) {
            LOGGER_FATAL << "cannot raise the file descriptor limit to '" << descriptorMinimum << "', got " << strerror(errno);
            exit(EXIT_FAILURE);
          }

          changed = true;
        }

        if (changed) {
          res = getrlimit(RLIMIT_NOFILE, &rlim);

          if (res != 0) {
            LOGGER_FATAL << "cannot get the file descriptor limit: " << strerror(errno) << "'";
            exit(EXIT_FAILURE);
          }

          LOGGER_DEBUG << "new hard limit is " << rlim.rlim_max << ", new soft limit is " << rlim.rlim_cur;
        }

        // the select backend has more restrictions
        if (_backend == 1) {
          if (FD_SETSIZE < descriptorMinimum) {
            LOGGER_FATAL << "i/o backend 'select' has been selected, which supports only " << FD_SETSIZE
                         << " descriptors, but " << descriptorMinimum << " are required";
            exit(EXIT_FAILURE);
          }
        }
      }

#endif
    }
  }
}
<commit_msg>changed return of locks<commit_after>////////////////////////////////////////////////////////////////////////////////
/// @brief application server scheduler implementation
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-2011 triagens GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
/// @author Copyright 2009-2011, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#include "ApplicationServerSchedulerImpl.h"

#include <Basics/Exceptions.h>
#include <Basics/Logger.h>
#include <Rest/PeriodicTask.h>
#include <Rest/SignalTask.h>

#include "Scheduler/SchedulerLibev.h"

using namespace std;
using namespace triagens::basics;
using namespace triagens::rest;

// -----------------------------------------------------------------------------
// helper classes and methods
// -----------------------------------------------------------------------------

namespace {

  ////////////////////////////////////////////////////////////////////////////////
  /// @brief handles control-c
  ////////////////////////////////////////////////////////////////////////////////

  class ControlCTask : public SignalTask {
    public:
      ControlCTask (ApplicationServer* server)
        : Task("Control-C"), SignalTask(), server(server) {
        addSignal(SIGINT);
        addSignal(SIGTERM);
        addSignal(SIGQUIT);
      }

    public:
      bool handleSignal () {
        LOGGER_INFO << "control-c received, shutting down";

        server->beginShutdown();

        return true;
      }

    private:
      ApplicationServer* server;
  };

  ////////////////////////////////////////////////////////////////////////////////
  /// @brief handles Hangup
  ////////////////////////////////////////////////////////////////////////////////

  class HangupTask : public SignalTask {
    public:
      HangupTask (ApplicationServerSchedulerImpl* server)
        : Task("Hangup"), SignalTask(), server(server) {
        addSignal(SIGHUP);
      }

    public:
      bool handleSignal () {
        LOGGER_INFO << "Hangup received, reopen logfile";
        TRI_ReopenLogging();
        LOGGER_INFO << "Hangup received, reopen logfile";
        return true;
      }

    private:
      ApplicationServerSchedulerImpl* server;
  };

  ////////////////////////////////////////////////////////////////////////////////
  /// @brief produces a scheduler status report
  ////////////////////////////////////////////////////////////////////////////////

  class SchedulerReporterTask : public PeriodicTask {
    public:
      SchedulerReporterTask (Scheduler* scheduler, double _reportIntervall)
        : Task("Scheduler-Reporter"), PeriodicTask(_reportIntervall * 0.1, _reportIntervall), scheduler(scheduler) {
      }

    public:
      bool handlePeriod () {
        scheduler->reportStatus();
        return true;
      }

    public:
      Scheduler* scheduler;
  };
}

namespace triagens {
  namespace rest {

    // -----------------------------------------------------------------------------
    // constructors and destructors
    // -----------------------------------------------------------------------------

    ApplicationServerSchedulerImpl::ApplicationServerSchedulerImpl (string const& description, string const& version)
      : ApplicationServerImpl(description, version),
        _reportIntervall(60.0),
        _multiSchedulerAllowed(false),
        _nrSchedulerThreads(1),
        _backend(0),
        reuseAddress(false),
        descriptorMinimum(0),

        _scheduler(0),
        _shutdownInProgress(false) {
    }

    ApplicationServerSchedulerImpl::~ApplicationServerSchedulerImpl () {

      // cleanup tasks and scheduler
      if (_scheduler != 0) {
        for (vector<Task*>::iterator i = _tasks.begin();  i != _tasks.end();  ++i) {
          _scheduler->destroyTask(*i);
        }

        delete _scheduler;
      }
    }

    // -----------------------------------------------------------------------------
    // public methods
    // -----------------------------------------------------------------------------

    void ApplicationServerSchedulerImpl::buildScheduler () {
      if (_scheduler != 0) {
        LOGGER_FATAL << "a scheduler has already been created";
        exit(EXIT_FAILURE);
      }

      _scheduler = new SchedulerLibev(_nrSchedulerThreads, _backend);
    }

    void ApplicationServerSchedulerImpl::buildSchedulerReporter () {
      if (0.0 < _reportIntervall) {
        registerTask(new SchedulerReporterTask(_scheduler, _reportIntervall));
      }
    }

    void ApplicationServerSchedulerImpl::buildControlCHandler () {
      if (_scheduler == 0) {
        LOGGER_FATAL << "no scheduler is known, cannot create control-c handler";
        exit(EXIT_FAILURE);
      }

      registerTask(new ControlCTask(this));
      registerTask(new HangupTask(this));
    }

    void ApplicationServerSchedulerImpl::installSignalHandler (SignalTask* task) {
      if (_scheduler == 0) {
        LOGGER_FATAL << "no scheduler is known, cannot install signal handler";
        exit(EXIT_FAILURE);
      }

      registerTask(task);
    }

    void ApplicationServerSchedulerImpl::start () {
      ApplicationServerImpl::start();

      if (_scheduler != 0) {
        bool ok = _scheduler->start(&_schedulerCond);

        if (! ok) {
          LOGGER_FATAL << "the scheduler cannot be started";
          exit(EXIT_FAILURE);
        }
      }
    }

    void ApplicationServerSchedulerImpl::wait () {
      ApplicationServerImpl::wait();

      if (_scheduler != 0) {
        _schedulerCond.lock();

        while (_scheduler->isRunning()) {
          LOGGER_TRACE << "waiting for scheduler to stop";
          _schedulerCond.wait();
        }

        LOGGER_TRACE << "scheduler has stopped";

        _schedulerCond.unlock();
      }
    }

    void ApplicationServerSchedulerImpl::beginShutdown () {
      ApplicationServerImpl::beginShutdown();

      if (! _shutdownInProgress) {
        LOGGER_TRACE << "begin shutdown sequence of application server";

        if (_scheduler != 0) {
          _scheduler->beginShutdown();
        }

        _shutdownInProgress = true;
      }
      else {
        LOGGER_TRACE << "shutdown sequence of application server already initiated";
      }
    }

    void ApplicationServerSchedulerImpl::shutdown () {
      ApplicationServerImpl::shutdown();

      if (_scheduler != 0) {
        int count = 0;

        while (++count < 6 && _scheduler->isRunning()) {
          LOGGER_TRACE << "waiting for scheduler to stop";
          sleep(1);
        }
      }
    }

    // -----------------------------------------------------------------------------
    // protected methods
    // -----------------------------------------------------------------------------

    void ApplicationServerSchedulerImpl::registerTask (Task* task) {
      if (_scheduler == 0) {
        LOGGER_FATAL << "no scheduler is known, cannot create tasks";
        exit(EXIT_FAILURE);
      }

      _scheduler->registerTask(task);
      _tasks.push_back(task);
    }

    void ApplicationServerSchedulerImpl::setupOptions (map<string, ProgramOptionsDescription>& options) {
      ApplicationServerImpl::setupOptions(options);

      // .............................................................................
      // command line options
      // .............................................................................

      options[OPTIONS_CMDLINE + ":help-extended"]
        ("show-io-backends", "show available io backends")
      ;

      // .............................................................................
      // application server options
      // .............................................................................

      options[OPTIONS_SERVER + ":help-extended"]
        ("scheduler.backend", &_backend, "1: select, 2: poll, 4: epoll")
        ("server.reuse-address", "try to reuse address")
        ("server.report", &_reportIntervall, "report intervall")
#ifdef TRI_HAVE_GETRLIMIT
        ("server.descriptors-minimum", &descriptorMinimum, "minimum number of file descriptors needed to start")
#endif
      ;

      if (_multiSchedulerAllowed) {
        options[OPTIONS_SERVER + ":help-extended"]
          ("scheduler.threads", &_nrSchedulerThreads, "number of scheduler threads")
        ;
      }
    }

    bool ApplicationServerSchedulerImpl::parsePhase1 () {
      bool ok = ApplicationServerImpl::parsePhase1();

      if (! ok) {
        return false;
      }

      // show io backends
      if (options.has("show-io-backends")) {
        cout << "available io backends are: " << SchedulerLibev::availableBackends() << endl;
        exit(EXIT_SUCCESS);
      }

      return true;
    }

    bool ApplicationServerSchedulerImpl::parsePhase2 () {
      bool ok = ApplicationServerImpl::parsePhase2();

      if (! ok) {
        return false;
      }

      // check if want to reuse the address
      if (options.has("server.reuse-address")) {
        reuseAddress = true;
      }

      // adjust file descriptors
      adjustFileDescriptors();

      return true;
    }

    // -----------------------------------------------------------------------------
    // private methods
    // -----------------------------------------------------------------------------

    void ApplicationServerSchedulerImpl::adjustFileDescriptors () {
#ifdef TRI_HAVE_GETRLIMIT

      if (0 < descriptorMinimum) {
        struct rlimit rlim;
        int res = getrlimit(RLIMIT_NOFILE, &rlim);

        if (res != 0) {
          LOGGER_FATAL << "cannot get the file descriptor limit: " << strerror(errno) << "'";
          exit(EXIT_FAILURE);
        }

        LOGGER_DEBUG << "hard limit is " << rlim.rlim_max << ", soft limit is " << rlim.rlim_cur;

        bool changed = false;

        if (rlim.rlim_max < descriptorMinimum) {
          LOGGER_DEBUG << "hard limit " << rlim.rlim_max << " is too small, trying to raise";

          rlim.rlim_max = descriptorMinimum;
          rlim.rlim_cur = descriptorMinimum;

          res = setrlimit(RLIMIT_NOFILE, &rlim);

          if (res < 0) {
            LOGGER_FATAL << "cannot raise the file descriptor limit to '" << descriptorMinimum << "', got " << strerror(errno);
            exit(EXIT_FAILURE);
          }

          changed = true;
        }
        else if (rlim.rlim_cur < descriptorMinimum) {
          LOGGER_DEBUG << "soft limit " << rlim.rlim_cur << " is too small, trying to raise";

          rlim.rlim_cur = descriptorMinimum;

          res = setrlimit(RLIMIT_NOFILE, &rlim);

          if (res < 0) {
            LOGGER_FATAL << "cannot raise the file descriptor limit to '" << descriptorMinimum << "', got " << strerror(errno);
            exit(EXIT_FAILURE);
          }

          changed = true;
        }

        if (changed) {
          res = getrlimit(RLIMIT_NOFILE, &rlim);

          if (res != 0) {
            LOGGER_FATAL << "cannot get the file descriptor limit: " << strerror(errno) << "'";
            exit(EXIT_FAILURE);
          }

          LOGGER_DEBUG << "new hard limit is " << rlim.rlim_max << ", new soft limit is " << rlim.rlim_cur;
        }

        // the select backend has more restrictions
        if (_backend == 1) {
          if (FD_SETSIZE < descriptorMinimum) {
            LOGGER_FATAL << "i/o backend 'select' has been selected, which supports only " << FD_SETSIZE
                         << " descriptors, but " << descriptorMinimum << " are required";
            exit(EXIT_FAILURE);
          }
        }
      }

#endif
    }
  }
}
<|endoftext|>


<commit_before>/*=========================================================================

  Library:   CTK

  Copyright (c) Kitware Inc.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0.txt

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

=========================================================================*/

#include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
#include "dcmtk/dcmnet/scu.h"

// STD includes
#include <cstdlib>
#include <iostream>
#include <fstream>

void print_usage()
{
  std::cerr << "Usage: \n";
  std::cerr << "  ctkDICOMDemoSCU peer port [peerAETitle]\n";
  std::cerr << "     Issues ECHO request to the given host and given port.\n";
  std::cerr << "     Optional peerAETitle tells what application entity to address.\n";
  return;
}

int main(int argc, char** argv)
{
  // Check whether host and port are given
  if (argc < 3)
  {
    print_usage();
    return 2;
  }

  OFString host(argv[1]);
  unsigned int port = atoi(argv[2]);
  OFString peerAET;
  if (argc > 3)
  {
    peerAET = argv[3];
  }

  // Setup SCU
  DcmSCU scu;
  scu.setPeerHostName(host);
  scu.setPeerPort(port);
  OFString verificationSOP = UID_VerificationSOPClass;
  OFList<OFString> ts;
  ts.push_back(UID_LittleEndianExplicitTransferSyntax);
  ts.push_back(UID_BigEndianExplicitTransferSyntax);
  ts.push_back(UID_LittleEndianImplicitTransferSyntax);
  scu.addPresentationContext(verificationSOP, ts);
  if (peerAET != "")
  {
    scu.setPeerAETitle(peerAET);
  }
  OFCondition result = scu.initNetwork();
  if (result.bad())
  {
    std::cerr << "Error setting up SCU: " << result.text() << "\n";
    return 2;
  }

  // Negotiate association
  result = scu.negotiateAssociation();
  if (result.bad())
  {
    std::cerr << "Error negotiating association: " << result.text() << "\n";
    return 2;
  }

  // Issue ECHO request and let scu find presentation context itself (0)
  result = scu.sendECHORequest(0);
  if (result.bad())
  {
    std::cerr << "Error issuing ECHO request or received rejecting response: " << result.text() << "\n";
    return 2;
  }
  std::cout << "Successfully sent DICOM Echo to host " << argv[1] << " on port " << argv[2] << "\n";
  return 0;

}
<commit_msg>Change test to use new ctkDcmSCU<commit_after>/*=========================================================================

  Library:   CTK

  Copyright (c) Kitware Inc.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0.txt

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

=========================================================================*/

#include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
#include "ctkDcmSCU.h"

// STD includes
#include <cstdlib>
#include <iostream>
#include <fstream>

void print_usage()
{
  std::cerr << "Usage: \n";
  std::cerr << "  ctkDICOMDemoSCU peer port [peerAETitle]\n";
  std::cerr << "     Issues ECHO request to the given host and given port.\n";
  std::cerr << "     Optional peerAETitle tells what application entity to address.\n";
  return;
}

int main(int argc, char** argv)
{
  // Check whether host and port are given
  if (argc < 3)
  {
    print_usage();
    return 2;
  }

  OFString host(argv[1]);
  unsigned int port = atoi(argv[2]);
  OFString peerAET;
  if (argc > 3)
  {
    peerAET = argv[3];
  }

  // Setup SCU
  ctkDcmSCU scu;
  scu.setPeerHostName(host);
  scu.setPeerPort(port);
  OFString verificationSOP = UID_VerificationSOPClass;
  OFList<OFString> ts;
  ts.push_back(UID_LittleEndianExplicitTransferSyntax);
  ts.push_back(UID_BigEndianExplicitTransferSyntax);
  ts.push_back(UID_LittleEndianImplicitTransferSyntax);
  scu.addPresentationContext(verificationSOP, ts);
  if (peerAET != "")
  {
    scu.setPeerAETitle(peerAET);
  }
  OFCondition result = scu.initNetwork();
  if (result.bad())
  {
    std::cerr << "Error setting up SCU: " << result.text() << "\n";
    return 2;
  }

  // Negotiate association
  result = scu.negotiateAssociation();
  if (result.bad())
  {
    std::cerr << "Error negotiating association: " << result.text() << "\n";
    return 2;
  }

  // Issue ECHO request and let scu find presentation context itself (0)
  result = scu.sendECHORequest(0);
  if (result.bad())
  {
    std::cerr << "Error issuing ECHO request or received rejecting response: " << result.text() << "\n";
    return 2;
  }
  std::cout << "Successfully sent DICOM Echo to host " << argv[1] << " on port " << argv[2] << "\n";
  return 0;

}
<|endoftext|>


<commit_before>//This program created by love by Hadi - Copyright(c) by Hadi Abdi Khojasteh - Summer 2017. All right reserved. / Email: hkhojasteh@iasbs.ac.ir, info@hadiabdikhojasteh.ir / Website: iasbs.ac.ir/~hkhojasteh, hadiabdikhojasteh.ir

#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/xfeatures2d.hpp>
#include <opencv2/ml/ml.hpp>

#include <iostream>
#include <vector>
#include <algorithm>
#include <random>
#include <math.h>
#include <time.h>

using namespace std;
using namespace cv;
using namespace cv::ml;

typedef tuple<char, uint32_t> enumerate;
struct IncGenerator {
	uint32_t current_;
	IncGenerator(uint32_t start) : current_(start) {}
	uint32_t operator() () { return current_++; }
};

vector<uint32_t> sample(Mat1d, uint32_t, uint32_t);
void lossFun(vector<enumerate> inputs, vector<enumerate> targets, Mat1d hprev);

uint32_t data_size, vocab_size;
Mat1d Wxh, Whh, Why, bh, by;							//model parameters

uint32_t main() {
	srand(time(NULL));

	vector<char> data;
	vector<char> chars;
	vector<enumerate> charenum;
	FILE* inputfile;
	string fileName = "input.txt";
	inputfile = fopen(fileName.c_str(), "r");

	uint32_t i = 0;
	while (!feof(inputfile)) {
		char inchar[1] = { 0 };
		fscanf(inputfile, "%c", inchar);
		data.push_back(inchar[0]);

		//auto it = find_if(chars.begin(), chars.end(),
		//	[&](const char element) { return element == inchar[0]; });
		//If this is not in the char set
		//if (it == end(chars)) {
			chars.push_back(inchar[0]);
			charenum.push_back(make_tuple(inchar[0], i));
			i++;
		//}
	}
	fclose(inputfile);

	data_size = data.size();
	vocab_size = chars.size();
	printf("data has %d characters, %d unique.\n", data_size, vocab_size);
	vector<enumerate> char_to_ix = charenum;
	reverse(charenum.begin(), charenum.end());
	vector<enumerate> ix_to_char = charenum;

	//hyperparameters
	uint32_t hidden_size = 100;							//size of hidden layer of neurons
	uint32_t seq_length = 25;							//number of steps to unroll the RNN for
	double learning_rate = 1e-1;

	Wxh.create(hidden_size, vocab_size);				//Or: Mat mat(2, 4, CV_64FC1);
	Whh.create(hidden_size, hidden_size);
	Why.create(vocab_size, hidden_size);
	double mean = 0.0, stddev = 1.0 / 3.0;				//99.7% of values will be inside [-1, +1] interval
	randn(Wxh, Scalar(mean), Scalar(stddev));			//input to hidden
	randn(Whh, Scalar(mean), Scalar(stddev));			//hidden to hidden
	randn(Why, Scalar(mean), Scalar(stddev));			//hidden to output
	bh = Mat::zeros(hidden_size, 1, CV_32F);			//hidden bias
	by = Mat::zeros(vocab_size, 1, CV_32F);				//output bias

	uint32_t n = 0, p = 0;
	//Make an array of zeros with the same shape and type as a Ws array.
	Mat1d mWxh = Mat::zeros(Wxh.size(), Wxh.type());
	Mat1d mWhh = Mat::zeros(Whh.size(), Whh.type());
	Mat1d mWhy = Mat::zeros(Why.size(), Why.type());
	Mat1d mbh = Mat::zeros(bh.size(), bh.type());		//memory variables for Adagrad
	Mat1d mby = Mat::zeros(by.size(), by.type());		//memory variables for Adagrad
	//loss at iteration 0
	double smooth_loss = -log(1.0 / vocab_size) * seq_length;

	Mat1d loss, dWxh, dWhh, dWhy, dbh, dby, hprev;
	vector<enumerate> inputs, targets;
	for (uint32_t i = 0; i < 1000; i++) {
		//Prepare inputs (we're sweeping from left to right in steps seq_length long)
		if (p + seq_length + 1 >= data.size() || n == 0) {
			hprev = Mat::zeros(hidden_size, 1, CV_32F);	//reset RNN memory
			p = 0;										//go from start of data
		}

		inputs.clear();
		targets.clear();
		for (uint32_t i = 0; i < seq_length && p + i < char_to_ix.size() - 1; i++) {
			inputs.push_back(char_to_ix[p + i]);
			targets.push_back(char_to_ix[p + 1 + i]);
		}

		//Sample from the model now and then
		if (n % 100 == 0) {
			vector<uint32_t> sampWords = sample(hprev, p + i, 200);
			for (uint32_t i = 0; i < sampWords.size(); i++) {
				printf("%c", get<0>(ix_to_char[sampWords[i]]));
			}
			printf("\n");
		}

		lossFun(inputs, targets, hprev);

		p += seq_length;								//move data pointer
		n += 1;											//iteration counter
	}
	return 0;
}

vector<uint32_t> sample(Mat1d h, uint32_t seed_ix, uint32_t n) {
	//sample a sequence of integers from the model h is memory state,
	//     seed_ix is seed letter for first time step
	Mat1d x = Mat::zeros(vocab_size, 1, CV_32F);
	x[seed_ix][0] = 1.0;
	vector<uint32_t> ixes;
	for (uint32_t i = 0; i < n; i++) {
		Mat1d t = (Wxh * x) + (Whh * h) + bh;
		Mat1d h = Mat::zeros(t.size(), t.type());
		for (uint32_t i = 0; i < t.rows; i++) {
			h[i][0] = tanh(t[i][0]);
		}
		Mat1d y = (Why * h) + by;
		Mat1d expy;
		exp(y, expy);
		Mat1d p = expy / sum(expy)[0];
		p = p.reshape(1, 1);

		//Generates a random sample from a given 1-D array
		default_random_engine generator;
		discrete_distribution<int> distribution(p.begin(), p.end());
		vector<double> indices(p.size().width);
		generate(indices.begin(), indices.end(), [&generator, &distribution]() { return distribution(generator); });
		vector<int> incNumbers(p.size().width);
		IncGenerator gi(0);
		generate(incNumbers.begin(), incNumbers.end(), gi);
		Mat1d x = Mat::zeros(vocab_size, 1, CV_32F);
		int randSelect = (uint32_t)rand() % vocab_size;
		x[randSelect][0] = 1.0;
		ixes.push_back(randSelect);
	}
	return ixes;
}

void lossFun(vector<enumerate> inputs, vector<enumerate> targets, Mat1d hprev) {
	//inputs, targets are both list of integers.
	//     hprev is Hx1 array of initial hidden state
	//     returns the loss, gradients on model parameters, and last hidden state
	Mat1d hs = hprev;
	double loss = 0.0;
	Mat1d ps;
	//forward pass
	for (uint32_t t = 0; t < inputs.size(); t++) {
		//encode in 1-of-k
		Mat1d xs = Mat::zeros(inputs.size(), vocab_size, CV_32F);
		xs[t][get<1>(inputs[t])] = 1;
		Mat1d val = (Wxh * xs.row(t).t());
		for (uint32_t i = 0; i < val.rows; i++) {
			hs[i][0] = tanh(val[i][0]);
			Mat1d temp = (Whh * hs[i - 1][0]);
			hs[i][0] += temp[i][0] + bh[i][0];				//hidden state
		}
		Mat1d ys = (Why * hs[t][0]) + by[t][0];				//unnormalized log probabilities for next chars
		//probabilities for next chars
		ps = Mat::zeros(ys.size(), ys.type());
		double sum = 0.0;
		for (uint32_t i = 0; i < ys.rows; i++) {
			sum += ps[t][i];
			ps[t][i] = exp(ys[t][i]);
		}
		for (uint32_t i = 0; i < ys.rows; i++) {
			ps[t][0] = ps[t][0] / sum;
		}
		loss += -log(ps[t][get<1>(targets[t])]);			//softmax (cross-entropy loss)
	}
	//backward pass: compute gradients going backwards
	Mat1d dWxh = Mat::zeros(Wxh.size(), Wxh.type());
	Mat1d dWhh = Mat::zeros(Whh.size(), Whh.type());
	Mat1d dWhy = Mat::zeros(Why.size(), Why.type());
	Mat1d dbh = Mat::zeros(bh.size(), bh.type());
	Mat1d dby = Mat::zeros(by.size(), by.type());
	Mat1d dhnext = Mat::zeros(hs.size(), hs.type());
	for (int32_t time = inputs.size() - 1; time >= 0; time--){
		//backprop into y
		cout << time;
		Mat1d dy = Mat::zeros(0, ps.cols, ps.type());
		dy.push_back(ps.row(time));
		dy[0][get<1>(targets[time])] -= 1;
		cout << dy << endl << endl ;
		dWhy += dy * hs;
	}
}
<commit_msg>now lossFun return loss value smooth_loss calculation improved xs variable scope changed hs calculation changed (calculate hidden state matrix (hidden x vocab_size)) developing backprop into y (working with hs)<commit_after>//This program created by love by Hadi - Copyright(c) by Hadi Abdi Khojasteh - Summer 2017. All right reserved. / Email: hkhojasteh@iasbs.ac.ir, info@hadiabdikhojasteh.ir / Website: iasbs.ac.ir/~hkhojasteh, hadiabdikhojasteh.ir

#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/xfeatures2d.hpp>
#include <opencv2/ml/ml.hpp>

#include <iostream>
#include <vector>
#include <algorithm>
#include <random>
#include <math.h>
#include <time.h>

using namespace std;
using namespace cv;
using namespace cv::ml;

typedef tuple<char, uint32_t> enumerate;
struct IncGenerator {
	uint32_t current_;
	IncGenerator(uint32_t start) : current_(start) {}
	uint32_t operator() () { return current_++; }
};

vector<uint32_t> sample(Mat1d, uint32_t, uint32_t);
double lossFun(vector<enumerate> inputs, vector<enumerate> targets, Mat1d hprev);

uint32_t data_size, vocab_size;
Mat1d Wxh, Whh, Why, bh, by;							//model parameters

uint32_t main() {
	srand(time(NULL));

	vector<char> data;
	vector<char> chars;
	vector<enumerate> charenum;
	FILE* inputfile;
	string fileName = "input.txt";
	inputfile = fopen(fileName.c_str(), "r");

	uint32_t i = 0;
	while (!feof(inputfile)) {
		char inchar[1] = { 0 };
		fscanf(inputfile, "%c", inchar);
		data.push_back(inchar[0]);

		//auto it = find_if(chars.begin(), chars.end(),
		//	[&](const char element) { return element == inchar[0]; });
		//If this is not in the char set
		//if (it == end(chars)) {
			chars.push_back(inchar[0]);
			charenum.push_back(make_tuple(inchar[0], i));
			i++;
		//}
	}
	fclose(inputfile);

	data_size = data.size();
	vocab_size = chars.size();
	printf("data has %d characters, %d unique.\n", data_size, vocab_size);
	vector<enumerate> char_to_ix = charenum;
	reverse(charenum.begin(), charenum.end());
	vector<enumerate> ix_to_char = charenum;

	//hyperparameters
	uint32_t hidden_size = 100;							//size of hidden layer of neurons
	uint32_t seq_length = 25;							//number of steps to unroll the RNN for
	double learning_rate = 1e-1;

	Wxh.create(hidden_size, vocab_size);				//Or: Mat mat(2, 4, CV_64FC1);
	Whh.create(hidden_size, hidden_size);
	Why.create(vocab_size, hidden_size);
	double mean = 0.0, stddev = 1.0 / 3.0;				//99.7% of values will be inside [-1, +1] interval
	randn(Wxh, Scalar(mean), Scalar(stddev));			//input to hidden
	randn(Whh, Scalar(mean), Scalar(stddev));			//hidden to hidden
	randn(Why, Scalar(mean), Scalar(stddev));			//hidden to output
	bh = Mat::zeros(hidden_size, 1, CV_32F);			//hidden bias
	by = Mat::zeros(vocab_size, 1, CV_32F);				//output bias

	uint32_t n = 0, p = 0;
	//Make an array of zeros with the same shape and type as a Ws array.
	Mat1d mWxh = Mat::zeros(Wxh.size(), Wxh.type());
	Mat1d mWhh = Mat::zeros(Whh.size(), Whh.type());
	Mat1d mWhy = Mat::zeros(Why.size(), Why.type());
	Mat1d mbh = Mat::zeros(bh.size(), bh.type());		//memory variables for Adagrad
	Mat1d mby = Mat::zeros(by.size(), by.type());		//memory variables for Adagrad
	//loss at iteration 0
	double smooth_loss = -log(1.0 / vocab_size) * seq_length, loss = 0.0;

	Mat1d dWxh, dWhh, dWhy, dbh, dby, hprev;
	vector<enumerate> inputs, targets;
	for (uint32_t i = 0; i < 1e10; i++) {
		//Prepare inputs (we're sweeping from left to right in steps seq_length long)
		if (p + seq_length + 1 >= data.size() || n == 0) {
			hprev = Mat::zeros(hidden_size, 1, CV_32F);	//reset RNN memory
			p = 0;										//go from start of data
		}

		inputs.clear();
		targets.clear();
		for (uint32_t i = 0; i < seq_length && p + i < char_to_ix.size() - 1; i++) {
			inputs.push_back(char_to_ix[p + i]);
			targets.push_back(char_to_ix[p + 1 + i]);
		}

		//Sample from the model now and then
		if (n % 100 == 0) {
			vector<uint32_t> sampWords = sample(hprev, p + i, 200);
			for (uint32_t i = 0; i < sampWords.size(); i++) {
				printf("%c", get<0>(ix_to_char[sampWords[i]]));
			}
		}

		loss = lossFun(inputs, targets, hprev);
		smooth_loss = smooth_loss * 0.999 + loss * 0.001;
		if (n % 100 == 0) {
			printf("\niter %d, loss: %f\n", n, smooth_loss);
		}

		p += seq_length;								//move data pointer
		n += 1;											//iteration counter
	}
	return 0;
}

vector<uint32_t> sample(Mat1d h, uint32_t seed_ix, uint32_t n) {
	//sample a sequence of integers from the model h is memory state,
	//     seed_ix is seed letter for first time step
	Mat1d x = Mat::zeros(vocab_size, 1, CV_32F);
	x[seed_ix][0] = 1.0;
	vector<uint32_t> ixes;
	for (uint32_t i = 0; i < n; i++) {
		Mat1d t = (Wxh * x) + (Whh * h) + bh;
		Mat1d h = Mat::zeros(t.size(), t.type());
		for (uint32_t i = 0; i < t.rows; i++) {
			h[i][0] = tanh(t[i][0]);
		}
		Mat1d y = (Why * h) + by;
		Mat1d expy;
		exp(y, expy);
		Mat1d p = expy / sum(expy)[0];
		p = p.reshape(1, 1);

		//Generates a random sample from a given 1-D array
		default_random_engine generator;
		discrete_distribution<int> distribution(p.begin(), p.end());
		vector<double> indices(p.size().width);
		generate(indices.begin(), indices.end(), [&generator, &distribution]() { return distribution(generator); });
		vector<int> incNumbers(p.size().width);
		IncGenerator gi(0);
		generate(incNumbers.begin(), incNumbers.end(), gi);
		Mat1d x = Mat::zeros(vocab_size, 1, CV_32F);
		int randSelect = (uint32_t)rand() % vocab_size;
		x[randSelect][0] = 1.0;
		ixes.push_back(randSelect);
	}
	return ixes;
}

double lossFun(vector<enumerate> inputs, vector<enumerate> targets, Mat1d hprev) {
	//inputs, targets are both list of integers.
	//     hprev is Hx1 array of initial hidden state
	//     returns the loss, gradients on model parameters, and last hidden state
	Mat1d xs;
	Mat1d hs = Mat::zeros(hprev.rows, 0, hprev.type());
	double loss = 0.0;
	Mat1d ps;
	//forward pass
	for (uint32_t t = 0; t < inputs.size(); t++) {
		//encode in 1-of-k
		xs = Mat::zeros(inputs.size(), vocab_size, CV_32F);
		xs[t][get<1>(inputs[t])] = 1;

		//calculate hidden state matrix (hidden x vocab_size)
		Mat1d val = (Wxh * xs.row(t).t());
		Mat1d hsTemp = Mat::zeros(hs.rows, 1, hs.type());
		//because of hs[-1] = np.copy(hprev) we must:
		hsTemp[0][0] = tanh(val[0][0]);
		Mat1d temp = (Whh * hprev[0][0]);
		hsTemp[0][0] += temp[0][0] + bh[0][0];

		for (uint32_t i = 1; i < val.rows; i++) {
			hsTemp[i][0] = tanh(val[i][0]);
			Mat1d temp = (Whh * hsTemp[i - 1][0]);
			hsTemp[i][0] += temp[i][0] + bh[i][0];			//hidden state
		}
		hconcat(hs, hsTemp, hs);

		//unnormalized log probabilities for next chars
		Mat1d ys = (Why * hs[0][t]) + by[t][0];				//unnormalized log probabilities for next chars
		//probabilities for next chars
		ps = Mat::zeros(ys.size(), ys.type());
		double sum = 0.0;
		for (uint32_t i = 0; i < ys.rows; i++) {
			sum += ps[t][i];
			ps[t][i] = exp(ys[t][i]);
		}
		for (uint32_t i = 0; i < ys.rows; i++) {
			ps[t][0] = ps[t][0] / sum;
		}
		loss += -log(ps[t][get<1>(targets[t])]);			//softmax (cross-entropy loss)
	}
	//backward pass: compute gradients going backwards
	Mat1d dWxh = Mat::zeros(Wxh.size(), Wxh.type());
	Mat1d dWhh = Mat::zeros(Whh.size(), Whh.type());
	Mat1d dWhy = Mat::zeros(Why.size(), Why.type());
	Mat1d dbh = Mat::zeros(bh.size(), bh.type());
	Mat1d dby = Mat::zeros(by.size(), by.type());
	Mat1d dhnext = Mat::zeros(hs.rows, 1, hs.type());
	for (int32_t t = inputs.size() - 1; t >= 0; t--){
		//backprop into y
		Mat1d dy = Mat::zeros(0, ps.cols, ps.type());
		dy.push_back(ps.col(t));
		dy[0][get<1>(targets[t])] -= 1;
		//cout << dy << endl << endl ;
		dWhy += dy * hs.col(t).t();
		dby += dy;
		Mat1d dh = (Why.t() * dy) + dhnext;
		Mat1d dhraw = (1 - (hs[t][0] * hs[t][0])) * dh;
		dbh += dhraw;
		dWxh += dhraw * xs.row(t);
		//dWhh += dhraw * hs.t();
	}
	return loss;
}
<|endoftext|>