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

 Program:   ORFEO Toolbox
 Language:  C++
 Date:      $Date$
 Version:   $Revision$

 Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
 See OTBCopyright.txt for details.

 This software is distributed WITHOUT ANY WARRANTY; without even
 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 PURPOSE.  See the above copyright notices for more information.

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

#include "otbWrapperCommandLineLauncher.h"
#include "otb_tinyxml.h"
#include <vector>

#ifdef OTB_USE_MPI
#include "otbMPIConfig.h"
#endif

const std::string GetChildNodeTextOf(TiXmlElement *parentElement, std::string key);
std::string PrepareExpressionFromXML(std::string filename);
std::vector<std::string> PrepareVectorExpressionFromXML(std::string filename);
std::string CleanWord(const std::string & word);

std::string PrepareExpressionFromXML(std::string filename)
{
  std::string expression;

  if(filename.empty())
    {
    std::cerr <<"Input XML Filename is empty" << std::endl;
    return expression;
    }
  std::string ext = filename.substr(filename.size()-4,filename.size());
  if(ext != ".xml" )
    std::cerr << ext  << " is a wrong extension: Expected .xml " << __FILE__ << std::endl;

  // Open the xml file
  TiXmlDocument doc;

  //Use itksys::SystemTools::FOpen() and close it below because
  //TiXmlDocument::TiXmlFileOpen( ) is not exposed from tinyXML library. Even
  //though its available in the TiXmlDocument::SaveFile().
  FILE* fp =  itksys::SystemTools::Fopen(filename.c_str(), "rb");

  if (!doc.LoadFile(fp , TIXML_ENCODING_UTF8))
    {
    std::cerr << "Can't open file " << filename << std::endl;
    fclose(fp);
    exit(1);

    }

  TiXmlHandle handle(&doc);

  TiXmlElement *n_OTB;
  n_OTB = handle.FirstChild("OTB").Element();

  if(!n_OTB)
  {
    std::string info = "Input XML file " + filename + " is invalid.";
    std::cerr << info  << std::endl;
    fclose(fp);
    exit(1);
  }

  TiXmlElement *n_AppNode   = n_OTB->FirstChildElement("application");

  std::string moduleName;
  moduleName = GetChildNodeTextOf(n_AppNode, "name");
  /*
  AddMetaData("appname", app_Name);

  app_Descr = this_->GetChildNodeTextOf(n_AppNode, "descr");
  AddMetaData("appdescr", app_Descr);

  TiXmlElement* n_Doc    = n_AppNode->FirstChildElement("doc");

  std::string doc_Name, doc_Descr, doc_Author, doc_Limitation, doc_SeeAlso;

  doc_Name = this_->GetChildNodeTextOf(n_Doc, "name");
  AddMetaData("docname", doc_Name);

  doc_Descr = this_->GetChildNodeTextOf(n_Doc, "longdescr");
  AddMetaData("doclongdescr", doc_Descr);

  doc_Author = this_->GetChildNodeTextOf(n_Doc, "authors");
  AddMetaData("docauthors", doc_Author);

  doc_Limitation = this_->GetChildNodeTextOf(n_Doc, "limitations");
  AddMetaData("doclimitations", doc_Limitation);

  doc_SeeAlso = this_->GetChildNodeTextOf(n_Doc, "seealso");
  AddMetaData("docseealso", doc_SeeAlso);
  */

  expression.append(moduleName);

  for( TiXmlElement* n_Parameter = n_AppNode->FirstChildElement("parameter"); n_Parameter != ITK_NULLPTR;
       n_Parameter = n_Parameter->NextSiblingElement() )
    {
    std::string key="-";
    key.append(GetChildNodeTextOf(n_Parameter, "key"));

    TiXmlElement* n_Values = ITK_NULLPTR;
    n_Values = n_Parameter->FirstChildElement("values");
    if(n_Values)
      {
      std::string values;
      for(TiXmlElement* n_Value = n_Values->FirstChildElement("value"); n_Value != ITK_NULLPTR;
          n_Value = n_Value->NextSiblingElement())
        {
        values.append(n_Value->GetText());
        values.append(" ");
        }
      values = values.substr(0,values.size()-1);
      expression.append(" ");
      expression.append(key);
      expression.append(" ");
      expression.append(values);
      }
    else
      {
      std::string value;
      value = GetChildNodeTextOf(n_Parameter, "value");

      expression.append(" ");
      expression.append(key);
      expression.append(" ");
      expression.append(value);

      std::string type = GetChildNodeTextOf(n_Parameter, "type");
      if (type == "OutputImage")
        {
        std::string t = GetChildNodeTextOf(n_Parameter, "pixtype");
        expression.append(" ");
        expression.append(t);
        }
      }
    }

  fclose(fp);

  return expression;
}

std::vector<std::string> PrepareVectorExpressionFromXML(std::string filename)
{
  std::vector<std::string> expression;

  if(filename.empty())
    {
    std::cerr <<"Input XML Filename is empty" << std::endl;
    return expression;
    }
  std::string ext = filename.substr(filename.size()-4,filename.size());
  if(ext != ".xml" )
    std::cerr << ext  << " is a wrong extension: Expected .xml " << __FILE__ << std::endl;

  // Open the xml file
  TiXmlDocument doc;

  //Use itksys::SystemTools::FOpen() and close it below because
  //TiXmlDocument::TiXmlFileOpen( ) is not exposed from tinyXML library. Even
  //though its available in the TiXmlDocument::SaveFile().
  FILE* fp =  itksys::SystemTools::Fopen(filename.c_str(), "rb");

  if (!doc.LoadFile(fp , TIXML_ENCODING_UTF8))
    {
    std::cerr << "Can't open file " << filename << std::endl;
    fclose(fp);
    exit(1);

    }

  TiXmlHandle handle(&doc);

  TiXmlElement *n_OTB;
  n_OTB = handle.FirstChild("OTB").Element();

  if(!n_OTB)
  {
    std::string info = "Input XML file " + filename + " is invalid.";
    std::cerr << info  << std::endl;
    fclose(fp);
    exit(1);
  }

  TiXmlElement *n_AppNode   = n_OTB->FirstChildElement("application");

  std::string moduleName;
  moduleName = GetChildNodeTextOf(n_AppNode, "name");

  expression.push_back(CleanWord(moduleName));

  for( TiXmlElement* n_Parameter = n_AppNode->FirstChildElement("parameter"); n_Parameter != ITK_NULLPTR;
       n_Parameter = n_Parameter->NextSiblingElement() )
    {
    std::string key="-";
    key.append(GetChildNodeTextOf(n_Parameter, "key"));
    expression.push_back(CleanWord(key));

    TiXmlElement* n_Values = ITK_NULLPTR;
    n_Values = n_Parameter->FirstChildElement("values");
    if(n_Values)
      {
      std::string values;
      for(TiXmlElement* n_Value = n_Values->FirstChildElement("value"); n_Value != ITK_NULLPTR;
          n_Value = n_Value->NextSiblingElement())
        {
        expression.push_back(CleanWord(n_Value->GetText()));
        }
      }
    else
      {
      std::string value;
      value = GetChildNodeTextOf(n_Parameter, "value");
      expression.push_back(CleanWord(value));

      std::string type = GetChildNodeTextOf(n_Parameter, "type");
      if (type == "OutputImage")
        {
        std::string t = GetChildNodeTextOf(n_Parameter, "pixtype");
        expression.push_back(CleanWord(t));
        }
      }
    }

  fclose(fp);

  return expression;
}

std::string CleanWord(const std::string & word)
{
  std::string res("");
  // Suppress whitespace characters at the beginning and ending of the string
  std::string::size_type cleanStart = word.find_first_not_of(" \t");
  std::string::size_type cleanEnd = word.find_last_not_of(" \t\f\v\n\r");
  if (cleanEnd != std::string::npos)
    {
    res = word.substr(cleanStart,cleanEnd+1);
    }
  return res;
}

int main(int argc, char* argv[])
{
  #ifdef OTB_USE_MPI
  otb::MPIConfig::Instance()->Init(argc,argv);
  #endif

  if (argc < 2)
    {
    std::cerr << "Usage : " << argv[0] << " module_name [MODULEPATH] [arguments]" << std::endl;
    return EXIT_FAILURE;
    }

  std::vector<std::string> vexp;

  std::string exp;
  if (strcmp(argv[1], "-inxml") == 0)
    {
    //exp = PrepareExpressionFromXML(argv[2]);
    vexp = PrepareVectorExpressionFromXML(argv[2]);
    }
  else
    {
    // Construct the string expression
    for (int i = 1; i < argc; i++)
      {
      /*if (i != argc - 1)
        {
        exp.append(argv[i]);
        exp.append(" ");
        }
      else
        {
        exp.append(argv[i]);
        }*/
      std::string strarg(argv[i]);
      std::string cleanArg = CleanWord(strarg);
      if (cleanArg.empty())
        {
        // Empty argument !
        continue;
        }
      vexp.push_back(cleanArg);
      }
    }
  //  std::cerr << exp << ":\n";

  typedef otb::Wrapper::CommandLineLauncher LauncherType;
  LauncherType::Pointer launcher = LauncherType::New();

  //if (launcher->Load(exp) == true)
    if (launcher->Load(vexp) == true)
    {
    if (launcher->ExecuteAndWriteOutput() == false)
      {
      return EXIT_FAILURE;
      }
    }
  else
    {
    return EXIT_FAILURE;
    }

  return EXIT_SUCCESS;
}

const std::string GetChildNodeTextOf(TiXmlElement *parentElement, std::string key)
{
  std::string value="";

  if(parentElement)
    {
    TiXmlElement* childElement = ITK_NULLPTR;
    childElement = parentElement->FirstChildElement(key.c_str());

    //same as childElement->GetText() does but that call is failing if there is
    //no such node.
    //but the below code works and is a replacement for GetText()
    if(childElement)
      {
      const TiXmlNode* child = childElement->FirstChild();
      if ( child )
        {
        const TiXmlText* childText = child->ToText();
        if ( childText )
          {
          value = childText->Value();
          }
        }
      }
    }
  return value;
}
<commit_msg>BUG: Fix trailing whitespace trimming in otbApplicationLauncherCommandLine (kindly provided by Laurentiu Nicola)<commit_after>/*=========================================================================

 Program:   ORFEO Toolbox
 Language:  C++
 Date:      $Date$
 Version:   $Revision$

 Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
 See OTBCopyright.txt for details.

 This software is distributed WITHOUT ANY WARRANTY; without even
 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 PURPOSE.  See the above copyright notices for more information.

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

#include "otbWrapperCommandLineLauncher.h"
#include "otb_tinyxml.h"
#include <vector>

#ifdef OTB_USE_MPI
#include "otbMPIConfig.h"
#endif

const std::string GetChildNodeTextOf(TiXmlElement *parentElement, std::string key);
std::string PrepareExpressionFromXML(std::string filename);
std::vector<std::string> PrepareVectorExpressionFromXML(std::string filename);
std::string CleanWord(const std::string & word);

std::string PrepareExpressionFromXML(std::string filename)
{
  std::string expression;

  if(filename.empty())
    {
    std::cerr <<"Input XML Filename is empty" << std::endl;
    return expression;
    }
  std::string ext = filename.substr(filename.size()-4,filename.size());
  if(ext != ".xml" )
    std::cerr << ext  << " is a wrong extension: Expected .xml " << __FILE__ << std::endl;

  // Open the xml file
  TiXmlDocument doc;

  //Use itksys::SystemTools::FOpen() and close it below because
  //TiXmlDocument::TiXmlFileOpen( ) is not exposed from tinyXML library. Even
  //though its available in the TiXmlDocument::SaveFile().
  FILE* fp =  itksys::SystemTools::Fopen(filename.c_str(), "rb");

  if (!doc.LoadFile(fp , TIXML_ENCODING_UTF8))
    {
    std::cerr << "Can't open file " << filename << std::endl;
    fclose(fp);
    exit(1);

    }

  TiXmlHandle handle(&doc);

  TiXmlElement *n_OTB;
  n_OTB = handle.FirstChild("OTB").Element();

  if(!n_OTB)
  {
    std::string info = "Input XML file " + filename + " is invalid.";
    std::cerr << info  << std::endl;
    fclose(fp);
    exit(1);
  }

  TiXmlElement *n_AppNode   = n_OTB->FirstChildElement("application");

  std::string moduleName;
  moduleName = GetChildNodeTextOf(n_AppNode, "name");
  /*
  AddMetaData("appname", app_Name);

  app_Descr = this_->GetChildNodeTextOf(n_AppNode, "descr");
  AddMetaData("appdescr", app_Descr);

  TiXmlElement* n_Doc    = n_AppNode->FirstChildElement("doc");

  std::string doc_Name, doc_Descr, doc_Author, doc_Limitation, doc_SeeAlso;

  doc_Name = this_->GetChildNodeTextOf(n_Doc, "name");
  AddMetaData("docname", doc_Name);

  doc_Descr = this_->GetChildNodeTextOf(n_Doc, "longdescr");
  AddMetaData("doclongdescr", doc_Descr);

  doc_Author = this_->GetChildNodeTextOf(n_Doc, "authors");
  AddMetaData("docauthors", doc_Author);

  doc_Limitation = this_->GetChildNodeTextOf(n_Doc, "limitations");
  AddMetaData("doclimitations", doc_Limitation);

  doc_SeeAlso = this_->GetChildNodeTextOf(n_Doc, "seealso");
  AddMetaData("docseealso", doc_SeeAlso);
  */

  expression.append(moduleName);

  for( TiXmlElement* n_Parameter = n_AppNode->FirstChildElement("parameter"); n_Parameter != ITK_NULLPTR;
       n_Parameter = n_Parameter->NextSiblingElement() )
    {
    std::string key="-";
    key.append(GetChildNodeTextOf(n_Parameter, "key"));

    TiXmlElement* n_Values = ITK_NULLPTR;
    n_Values = n_Parameter->FirstChildElement("values");
    if(n_Values)
      {
      std::string values;
      for(TiXmlElement* n_Value = n_Values->FirstChildElement("value"); n_Value != ITK_NULLPTR;
          n_Value = n_Value->NextSiblingElement())
        {
        values.append(n_Value->GetText());
        values.append(" ");
        }
      values = values.substr(0,values.size()-1);
      expression.append(" ");
      expression.append(key);
      expression.append(" ");
      expression.append(values);
      }
    else
      {
      std::string value;
      value = GetChildNodeTextOf(n_Parameter, "value");

      expression.append(" ");
      expression.append(key);
      expression.append(" ");
      expression.append(value);

      std::string type = GetChildNodeTextOf(n_Parameter, "type");
      if (type == "OutputImage")
        {
        std::string t = GetChildNodeTextOf(n_Parameter, "pixtype");
        expression.append(" ");
        expression.append(t);
        }
      }
    }

  fclose(fp);

  return expression;
}

std::vector<std::string> PrepareVectorExpressionFromXML(std::string filename)
{
  std::vector<std::string> expression;

  if(filename.empty())
    {
    std::cerr <<"Input XML Filename is empty" << std::endl;
    return expression;
    }
  std::string ext = filename.substr(filename.size()-4,filename.size());
  if(ext != ".xml" )
    std::cerr << ext  << " is a wrong extension: Expected .xml " << __FILE__ << std::endl;

  // Open the xml file
  TiXmlDocument doc;

  //Use itksys::SystemTools::FOpen() and close it below because
  //TiXmlDocument::TiXmlFileOpen( ) is not exposed from tinyXML library. Even
  //though its available in the TiXmlDocument::SaveFile().
  FILE* fp =  itksys::SystemTools::Fopen(filename.c_str(), "rb");

  if (!doc.LoadFile(fp , TIXML_ENCODING_UTF8))
    {
    std::cerr << "Can't open file " << filename << std::endl;
    fclose(fp);
    exit(1);

    }

  TiXmlHandle handle(&doc);

  TiXmlElement *n_OTB;
  n_OTB = handle.FirstChild("OTB").Element();

  if(!n_OTB)
  {
    std::string info = "Input XML file " + filename + " is invalid.";
    std::cerr << info  << std::endl;
    fclose(fp);
    exit(1);
  }

  TiXmlElement *n_AppNode   = n_OTB->FirstChildElement("application");

  std::string moduleName;
  moduleName = GetChildNodeTextOf(n_AppNode, "name");

  expression.push_back(CleanWord(moduleName));

  for( TiXmlElement* n_Parameter = n_AppNode->FirstChildElement("parameter"); n_Parameter != ITK_NULLPTR;
       n_Parameter = n_Parameter->NextSiblingElement() )
    {
    std::string key="-";
    key.append(GetChildNodeTextOf(n_Parameter, "key"));
    expression.push_back(CleanWord(key));

    TiXmlElement* n_Values = ITK_NULLPTR;
    n_Values = n_Parameter->FirstChildElement("values");
    if(n_Values)
      {
      std::string values;
      for(TiXmlElement* n_Value = n_Values->FirstChildElement("value"); n_Value != ITK_NULLPTR;
          n_Value = n_Value->NextSiblingElement())
        {
        expression.push_back(CleanWord(n_Value->GetText()));
        }
      }
    else
      {
      std::string value;
      value = GetChildNodeTextOf(n_Parameter, "value");
      expression.push_back(CleanWord(value));

      std::string type = GetChildNodeTextOf(n_Parameter, "type");
      if (type == "OutputImage")
        {
        std::string t = GetChildNodeTextOf(n_Parameter, "pixtype");
        expression.push_back(CleanWord(t));
        }
      }
    }

  fclose(fp);

  return expression;
}

std::string CleanWord(const std::string & word)
{
  std::string res("");
  // Suppress whitespace characters at the beginning and ending of the string
  std::string::size_type cleanStart = word.find_first_not_of(" \t");
  std::string::size_type cleanEnd = word.find_last_not_of(" \t\f\v\n\r");
  // cleanStart == npos implies cleanEnd == npos
  if (cleanEnd != std::string::npos)
    {
    res = word.substr(cleanStart, cleanEnd - cleanStart + 1);
    }
  return res;
}

int main(int argc, char* argv[])
{
  #ifdef OTB_USE_MPI
  otb::MPIConfig::Instance()->Init(argc,argv);
  #endif

  if (argc < 2)
    {
    std::cerr << "Usage : " << argv[0] << " module_name [MODULEPATH] [arguments]" << std::endl;
    return EXIT_FAILURE;
    }

  std::vector<std::string> vexp;

  std::string exp;
  if (strcmp(argv[1], "-inxml") == 0)
    {
    //exp = PrepareExpressionFromXML(argv[2]);
    vexp = PrepareVectorExpressionFromXML(argv[2]);
    }
  else
    {
    // Construct the string expression
    for (int i = 1; i < argc; i++)
      {
      /*if (i != argc - 1)
        {
        exp.append(argv[i]);
        exp.append(" ");
        }
      else
        {
        exp.append(argv[i]);
        }*/
      std::string strarg(argv[i]);
      std::string cleanArg = CleanWord(strarg);
      if (cleanArg.empty())
        {
        // Empty argument !
        continue;
        }
      vexp.push_back(cleanArg);
      }
    }
  //  std::cerr << exp << ":\n";

  typedef otb::Wrapper::CommandLineLauncher LauncherType;
  LauncherType::Pointer launcher = LauncherType::New();

  //if (launcher->Load(exp) == true)
    if (launcher->Load(vexp) == true)
    {
    if (launcher->ExecuteAndWriteOutput() == false)
      {
      return EXIT_FAILURE;
      }
    }
  else
    {
    return EXIT_FAILURE;
    }

  return EXIT_SUCCESS;
}

const std::string GetChildNodeTextOf(TiXmlElement *parentElement, std::string key)
{
  std::string value="";

  if(parentElement)
    {
    TiXmlElement* childElement = ITK_NULLPTR;
    childElement = parentElement->FirstChildElement(key.c_str());

    //same as childElement->GetText() does but that call is failing if there is
    //no such node.
    //but the below code works and is a replacement for GetText()
    if(childElement)
      {
      const TiXmlNode* child = childElement->FirstChild();
      if ( child )
        {
        const TiXmlText* childText = child->ToText();
        if ( childText )
          {
          value = childText->Value();
          }
        }
      }
    }
  return value;
}
<|endoftext|>


<commit_before>/* -*-  mode: c++; c-default-style: "google"; indent-tabs-mode: nil -*- */

/* -------------------------------------------------------------------------
ATS

License: see $ATS_DIR/COPYRIGHT
Author: Ethan Coon

Standard base for most PKs, this combines both domains/meshes of
PKPhysicalBase and BDF methods of PKBDFBase.
------------------------------------------------------------------------- */

#include "boost/math/special_functions/fpclassify.hpp"

#include "pk_physical_bdf_base.hh"

namespace Amanzi {

// -----------------------------------------------------------------------------
// Setup
// -----------------------------------------------------------------------------
void PKPhysicalBDFBase::setup(const Teuchos::Ptr<State>& S) {

  // call the meat of the base constructurs via Setup methods
  PKPhysicalBase::setup(S);
  PKBDFBase::setup(S);

  // convergence criteria
  atol_ = plist_.get<double>("absolute error tolerance",1.0);
  rtol_ = plist_.get<double>("relative error tolerance",1.0);
  atol0_ = atol_;
  rtol0_ = rtol_;

  // adapt the tolerances to fit the timestep
  adapt_tols_to_h_ = plist_.get<bool>("adapt tolerances to timestep", "false");
  if (adapt_tols_to_h_) {
    min_tol_h_ = plist_.get<double>("cutoff timestep for adaptive tolerance", 100.0);
  }

  // continuation to steady state enables a gradually shrinking atol/rtol
  continuation_to_ss_ = plist_.get<bool>("continuation to steady state", false);

};

// -----------------------------------------------------------------------------
// initialize.  Note both BDFBase and PhysicalBase have initialize()
// methods, so we need a unique overrider.
// -----------------------------------------------------------------------------
void PKPhysicalBDFBase::initialize(const Teuchos::Ptr<State>& S) {
  // Just calls both subclass's initialize.  NOTE - order is important here --
  // PhysicalBase grabs the primary variable and stuffs it into the solution,
  // which must be done prior to BDFBase initializing the timestepper.
  PKPhysicalBase::initialize(S);
  PKBDFBase::initialize(S);
}

// -----------------------------------------------------------------------------
// Default enorm that uses an abs and rel tolerance to monitor convergence.
// -----------------------------------------------------------------------------
double PKPhysicalBDFBase::enorm(Teuchos::RCP<const TreeVector> u,
        Teuchos::RCP<const TreeVector> du) {
  // VerboseObject stuff.
  Teuchos::OSTab tab = getOSTab();
  if (out_.get() && includesVerbLevel(verbosity_, Teuchos::VERB_HIGH, true)) {
    *out_ << "ENorm (Infnorm) of: " << name_ << ": ";
  }

  // adapt tolerances if needed
  if (adapt_tols_to_h_) {
    double h = S_next_->time() - S_inter_->time();
    atol_ = atol0_ / h;
    rtol_ = rtol0_ / h;
  }

  // continue tolerances if needed
  if (continuation_to_ss_) {
    atol_ = atol0_ + 1.e5*atol0_/(1.0 + S_next_->time());
    rtol_ = rtol0_ + 1.e5*rtol0_/(1.0 + S_next_->time());
  }

  Teuchos::RCP<const CompositeVector> vec = u->data();
  Teuchos::RCP<const CompositeVector> dvec = du->data();

  double enorm_val = 0.0;
  for (CompositeVector::name_iterator comp=vec->begin();
       comp!=vec->end(); ++comp) {
    double enorm_comp = 0.0;
    double infnorm_comp = 0.0;
    for (int id=0; id!=vec->size(*comp,false); ++id) {
      if (boost::math::isnan<double>((*dvec)(*comp,id))) {
        std::cout << "Cutting time step due to NaN in correction." << std::endl;
        Errors::Message m("Cut time step");
        Exceptions::amanzi_throw(m);
      }

      double tmp = abs((*dvec)(*comp,id)) / (atol_+rtol_*abs((*vec)(*comp,id)));
      enorm_comp = std::max<double>(enorm_comp, tmp);
      infnorm_comp = std::max<double>(infnorm_comp, abs((*dvec)(*comp,id)));
    }

    if (out_.get() && includesVerbLevel(verbosity_, Teuchos::VERB_HIGH, true)) {
      *out_ << *comp << " = " << enorm_comp << " (" << infnorm_comp << ")  ";
    }
    enorm_val = std::max<double>(enorm_val, enorm_comp);
  }

  if (out_.get() && includesVerbLevel(verbosity_, Teuchos::VERB_HIGH, true)) {
    *out_ << std::endl;
  }

#ifdef HAVE_MPI
  double buf = enorm_val;
  MPI_Allreduce(&buf, &enorm_val, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);
#endif
  return enorm_val;
};

// -----------------------------------------------------------------------------
// Experimental approach -- we must pull out S_next_'s solution_evaluator_ to
// stay current for changed_solution()
// -----------------------------------------------------------------------------
void PKPhysicalBDFBase::set_states(const Teuchos::RCP<const State>& S,
        const Teuchos::RCP<State>& S_inter,
        const Teuchos::RCP<State>& S_next) {
  PKDefaultBase::set_states(S, S_inter, S_next);

  Teuchos::RCP<FieldEvaluator> fm = S_next->GetFieldEvaluator(key_);

#if ENABLE_DBC
  solution_evaluator_ = Teuchos::rcp_dynamic_cast<PrimaryVariableFieldEvaluator>(fm);
  ASSERT(solution_evaluator_ != Teuchos::null);
#else
  solution_evaluator_ = Teuchos::rcp_static_cast<PrimaryVariableFieldEvaluator>(fm);
#endif

  changed_solution();
};

// -----------------------------------------------------------------------------
// Experimental approach -- calling this indicates that the time
// integration scheme is changing the value of the solution in
// state.
// -----------------------------------------------------------------------------
void PKPhysicalBDFBase::changed_solution() {
  solution_evaluator_->SetFieldAsChanged();
};

} // namespace
<commit_msg>cleanup for reporting norms in parallel case<commit_after>/* -*-  mode: c++; c-default-style: "google"; indent-tabs-mode: nil -*- */

/* -------------------------------------------------------------------------
ATS

License: see $ATS_DIR/COPYRIGHT
Author: Ethan Coon

Standard base for most PKs, this combines both domains/meshes of
PKPhysicalBase and BDF methods of PKBDFBase.
------------------------------------------------------------------------- */

#include "boost/math/special_functions/fpclassify.hpp"

#include "pk_physical_bdf_base.hh"

namespace Amanzi {

// -----------------------------------------------------------------------------
// Setup
// -----------------------------------------------------------------------------
void PKPhysicalBDFBase::setup(const Teuchos::Ptr<State>& S) {

  // call the meat of the base constructurs via Setup methods
  PKPhysicalBase::setup(S);
  PKBDFBase::setup(S);

  // convergence criteria
  atol_ = plist_.get<double>("absolute error tolerance",1.0);
  rtol_ = plist_.get<double>("relative error tolerance",1.0);
  atol0_ = atol_;
  rtol0_ = rtol_;

  // adapt the tolerances to fit the timestep
  adapt_tols_to_h_ = plist_.get<bool>("adapt tolerances to timestep", "false");
  if (adapt_tols_to_h_) {
    min_tol_h_ = plist_.get<double>("cutoff timestep for adaptive tolerance", 100.0);
  }

  // continuation to steady state enables a gradually shrinking atol/rtol
  continuation_to_ss_ = plist_.get<bool>("continuation to steady state", false);

};

// -----------------------------------------------------------------------------
// initialize.  Note both BDFBase and PhysicalBase have initialize()
// methods, so we need a unique overrider.
// -----------------------------------------------------------------------------
void PKPhysicalBDFBase::initialize(const Teuchos::Ptr<State>& S) {
  // Just calls both subclass's initialize.  NOTE - order is important here --
  // PhysicalBase grabs the primary variable and stuffs it into the solution,
  // which must be done prior to BDFBase initializing the timestepper.
  PKPhysicalBase::initialize(S);
  PKBDFBase::initialize(S);
}

// -----------------------------------------------------------------------------
// Default enorm that uses an abs and rel tolerance to monitor convergence.
// -----------------------------------------------------------------------------
double PKPhysicalBDFBase::enorm(Teuchos::RCP<const TreeVector> u,
        Teuchos::RCP<const TreeVector> du) {
  // VerboseObject stuff.
  Teuchos::OSTab tab = getOSTab();
  if (out_.get() && includesVerbLevel(verbosity_, Teuchos::VERB_HIGH, true)) {
    *out_ << "ENorm (Infnorm) of: " << name_ << ": ";
  }

  // adapt tolerances if needed
  if (adapt_tols_to_h_) {
    double h = S_next_->time() - S_inter_->time();
    atol_ = atol0_ / h;
    rtol_ = rtol0_ / h;
  }

  // continue tolerances if needed
  if (continuation_to_ss_) {
    atol_ = atol0_ + 1.e5*atol0_/(1.0 + S_next_->time());
    rtol_ = rtol0_ + 1.e5*rtol0_/(1.0 + S_next_->time());
  }

  Teuchos::RCP<const CompositeVector> vec = u->data();
  Teuchos::RCP<const CompositeVector> dvec = du->data();

  double enorm_val = 0.0;
  for (CompositeVector::name_iterator comp=vec->begin();
       comp!=vec->end(); ++comp) {
    double enorm_comp = 0.0;
    for (int id=0; id!=vec->size(*comp,false); ++id) {
      if (boost::math::isnan<double>((*dvec)(*comp,id))) {
        std::cout << "Cutting time step due to NaN in correction." << std::endl;
        Errors::Message m("Cut time step");
        Exceptions::amanzi_throw(m);
      }

      double tmp = abs((*dvec)(*comp,id)) / (atol_+rtol_*abs((*vec)(*comp,id)));
      enorm_comp = std::max<double>(enorm_comp, tmp);
    }

    if (out_.get() && includesVerbLevel(verbosity_, Teuchos::VERB_HIGH, true)) {
      double buf(0.);
      MPI_Allreduce(&enorm_comp, &buf, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);

      double infnorm_comp;
      dvec->ViewComponent(*comp,false)->NormInf(&infnorm_comp);

      *out_ << *comp << " = " << buf << " (" << infnorm_comp << ")  ";
    }
    enorm_val = std::max<double>(enorm_val, enorm_comp);
  }

  if (out_.get() && includesVerbLevel(verbosity_, Teuchos::VERB_HIGH, true)) {
    *out_ << std::endl;
  }

#ifdef HAVE_MPI
  double buf = enorm_val;
  MPI_Allreduce(&buf, &enorm_val, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);
#endif
  return enorm_val;
};

// -----------------------------------------------------------------------------
// Experimental approach -- we must pull out S_next_'s solution_evaluator_ to
// stay current for changed_solution()
// -----------------------------------------------------------------------------
void PKPhysicalBDFBase::set_states(const Teuchos::RCP<const State>& S,
        const Teuchos::RCP<State>& S_inter,
        const Teuchos::RCP<State>& S_next) {
  PKDefaultBase::set_states(S, S_inter, S_next);

  Teuchos::RCP<FieldEvaluator> fm = S_next->GetFieldEvaluator(key_);

#if ENABLE_DBC
  solution_evaluator_ = Teuchos::rcp_dynamic_cast<PrimaryVariableFieldEvaluator>(fm);
  ASSERT(solution_evaluator_ != Teuchos::null);
#else
  solution_evaluator_ = Teuchos::rcp_static_cast<PrimaryVariableFieldEvaluator>(fm);
#endif

  changed_solution();
};

// -----------------------------------------------------------------------------
// Experimental approach -- calling this indicates that the time
// integration scheme is changing the value of the solution in
// state.
// -----------------------------------------------------------------------------
void PKPhysicalBDFBase::changed_solution() {
  solution_evaluator_->SetFieldAsChanged();
};

} // namespace
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "LocalTables.h"

using namespace std;

void LocalTables::init(std::function<int(const Motif&)> fn, double LB)
{
	fnGetNParents = fn;
	lowerBound = LB;
	candidateTables.reserve(16);
	nActLevel.reserve(16);
	nActLevelTotal.reserve(16);
}

void LocalTables::update(const Motif & m, const double newUB, const int num)
{
	int l = m.getnEdge();
	lock_guard<mutex> lg(mct);
	// add new level
	if(static_cast<int>(candidateTables.size()) <= l ) {
		size_t len = max(candidateTables.size(), nActLevel.size());
		len = max<size_t>(len, l + 1);
		candidateTables.resize(len);
		lock_guard<mutex> lga(mat);
		nActLevel.resize(len);
		nActLevelTotal.resize(len);
	}
	// update the num. left for activation
	CT_t& ct = candidateTables[l];
	auto it = ct.find(m);
	if(it == ct.end()) {
		// the max(0,...) here is for the special case where fnGetNParents(m)-num < 0
		int np = max(0, fnGetNParents(m) - num);
		it = ct.insert(make_pair(move(m), make_pair(newUB, np))).first;
	} else {
		it->second.first = min(it->second.first, newUB);
		it->second.second -= num;
	}
	// move a motif from candiate to active
	if(it->second.second == 0) {
		if(it->second.first >= lowerBound) {
			lock_guard<mutex> lga(mat);
			activatedTable.push_back(make_pair(move(it->first), it->second.first));
			++nActLevel[l];
			++nActLevelTotal[l];
		}
		// Special Case: when using estimated num. parents algorithm:
		//   #-left may be negative. If remove it the first time, it may be activated again.
		//   Therefore, instead of remove it, I set its #-left to a very large number.
		// TODO: distinguish the method for calculating num. partents, exact type & estimated type
		//ct.erase(it);
		it->second.second = numeric_limits<int>::max();
	}

}

void LocalTables::addToActivated(const Motif & m, const double newUB)
{
	int l = m.getnEdge();
	lock_guard<mutex> lga(mat);
	// add new level
	if(static_cast<int>(nActLevel.size()) <= l) {
		size_t len = max<size_t>(nActLevel.size(), l + 1);
		nActLevel.resize(len);
		nActLevelTotal.resize(len);
	}
	activatedTable.push_back(make_pair(m, newUB));
	++nActLevel[l];
	++nActLevelTotal[l];
}

void LocalTables::sortUp(const int l)
{
	lock_guard<mutex> lg(mct);
	size_t end = min(static_cast<size_t>(l + 1 + 1), candidateTables.size());
	// first +1 : clear the CT of level l+1 ; second +1 : loop in [x,x) manner
	for(size_t i = 1; i < end; ++i) {
		candidateTables[i].clear();
	}
}

int LocalTables::updateLowerBound(double newLB)
{
	if(lowerBound >= newLB)
		return 0;
	lowerBound = newLB;
	lock_guard<mutex> lg(mat);
	size_t s0 = activatedTable.size();
	auto it = activatedTable.begin();
	while(it != activatedTable.end()) {
		if(it->second < lowerBound) {
			--nActLevel[it->first.getnEdge()];
			it = activatedTable.erase(it);
		} else {
			++it;
		}
	}
	return s0 - activatedTable.size();
}

std::pair<bool, std::pair<Motif, double>> LocalTables::getOne()
{
	if(activatedTable.empty()) {
		return make_pair(false, make_pair(Motif(), 0.0));
	}
	lock_guard<mutex> lg(mat);
	if(activatedTable.empty()) {
		return make_pair(false, make_pair(Motif(), 0.0));
	}
	auto mu = move(activatedTable.front());
	--nActLevel[mu.first.getnEdge()];
	activatedTable.pop_front();
	return make_pair(true, move(mu));
}

int LocalTables::mostRecentLevel() const
{
	return candidateTables.size() - 1;
}

bool LocalTables::emptyCandidate() const
{
	for(size_t i = 0; i < candidateTables.size(); ++i) {
		if(emptyCandidate(i))
			return true;
	}
	return false;
}

bool LocalTables::emptyCandidate(const int level) const
{
	return static_cast<int>(candidateTables.size()) > level
		&& candidateTables[level].empty();
}

bool LocalTables::emptyActivated() const
{
	return activatedTable.empty();
}

bool LocalTables::emptyActivated(const int level) const
{
	return static_cast<int>(nActLevel.size()) > level
		&& nActLevel[level] == 0;
}

int LocalTables::getNumCandidate() const
{
	int res = 0;
	size_t n = candidateTables.size();
	for(size_t i = 0; i < n; ++i)
		res += candidateTables[i].size();
	return res;
}

std::vector<int> LocalTables::getNumCandidates() const
{
	size_t n = candidateTables.size();
	std::vector<int> res(n);
	for(size_t i = 0; i < n; ++i)
		res[i] = candidateTables[i].size();
	return res;
}

int LocalTables::getNumCandidate(const int level) const
{
	return static_cast<int>(candidateTables.size()) > level
		? candidateTables[level].size() : 0;
}

int LocalTables::getNumActive() const
{
	return activatedTable.size();
}

std::vector<int> LocalTables::getNumActives() const
{
	return nActLevel;
}

int LocalTables::getNumActive(const int level) const
{
	return static_cast<int>(nActLevel.size()) > level
		? nActLevel[level] : 0;
}

int LocalTables::getNumEverActive(const int level) const
{
	return static_cast<int>(nActLevelTotal.size()) > level ?
		nActLevelTotal[level] : 0;
}

bool LocalTables::empty() const
{
	unique_lock<mutex> ulc(mct, defer_lock);
	unique_lock<mutex> ula(mat, defer_lock);
	lock(ulc, ula);
	if(activatedTable.empty()) {
		for(auto& ct : candidateTables)
			if(!ct.empty())
				return false;
		return true;
	}
	return false;
}

bool LocalTables::empty(const int level) const
{
	unique_lock<mutex> ulc(mct, defer_lock);
	unique_lock<mutex> ula(mat, defer_lock);
	lock(ulc, ula);
	return candidateTables[level].empty() && nActLevel[level] == 0;
}

<commit_msg>fix an over optimization in local table<commit_after>#include "stdafx.h"
#include "LocalTables.h"

using namespace std;

void LocalTables::init(std::function<int(const Motif&)> fn, double LB)
{
	fnGetNParents = fn;
	lowerBound = LB;
	candidateTables.reserve(16);
	nActLevel.reserve(16);
	nActLevelTotal.reserve(16);
}

void LocalTables::update(const Motif & m, const double newUB, const int num)
{
	int l = m.getnEdge();
	lock_guard<mutex> lg(mct);
	// add new level
	if(static_cast<int>(candidateTables.size()) <= l ) {
		size_t len = max(candidateTables.size(), nActLevel.size());
		len = max<size_t>(len, l + 1);
		candidateTables.resize(len);
		lock_guard<mutex> lga(mat);
		nActLevel.resize(len);
		nActLevelTotal.resize(len);
	}
	// update the num. left for activation
	CT_t& ct = candidateTables[l];
	auto it = ct.find(m);
	if(it == ct.end()) {
		// the max(0,...) here is for the special case where fnGetNParents(m)-num < 0
		int np = max(0, fnGetNParents(m) - num);
		it = ct.insert(make_pair(move(m), make_pair(newUB, np))).first;
	} else {
		it->second.first = min(it->second.first, newUB);
		it->second.second -= num;
	}
	// move a motif from candiate to active
	if(it->second.second == 0) {
		if(it->second.first >= lowerBound) {
			lock_guard<mutex> lga(mat);
			activatedTable.push_back(make_pair(move(it->first), it->second.first));
			++nActLevel[l];
			++nActLevelTotal[l];
		}
		// Special Case: when using estimated num. parents algorithm:
		//   #-left may be negative. If remove it the first time, it may be activated again.
		//   Therefore, instead of remove it, I set its #-left to a very large number.
		// TODO: distinguish the method for calculating num. partents, exact type & estimated type
		//ct.erase(it);
		it->second.second = numeric_limits<int>::max();
	}

}

void LocalTables::addToActivated(const Motif & m, const double newUB)
{
	int l = m.getnEdge();
	lock_guard<mutex> lga(mat);
	// add new level
	if(static_cast<int>(nActLevel.size()) <= l) {
		size_t len = max<size_t>(nActLevel.size(), l + 1);
		nActLevel.resize(len);
		nActLevelTotal.resize(len);
	}
	activatedTable.push_back(make_pair(m, newUB));
	++nActLevel[l];
	++nActLevelTotal[l];
}

void LocalTables::sortUp(const int l)
{
	lock_guard<mutex> lg(mct);
	size_t end = min(static_cast<size_t>(l + 1), candidateTables.size());
	// l+1 : loop in [x,x) manner
	for(size_t i = 1; i < end; ++i) {
		candidateTables[i].clear();
	}
}

int LocalTables::updateLowerBound(double newLB)
{
	if(lowerBound >= newLB)
		return 0;
	lowerBound = newLB;
	lock_guard<mutex> lg(mat);
	size_t s0 = activatedTable.size();
	auto it = activatedTable.begin();
	while(it != activatedTable.end()) {
		if(it->second < lowerBound) {
			--nActLevel[it->first.getnEdge()];
			it = activatedTable.erase(it);
		} else {
			++it;
		}
	}
	return s0 - activatedTable.size();
}

std::pair<bool, std::pair<Motif, double>> LocalTables::getOne()
{
	if(activatedTable.empty()) {
		return make_pair(false, make_pair(Motif(), 0.0));
	}
	lock_guard<mutex> lg(mat);
	if(activatedTable.empty()) {
		return make_pair(false, make_pair(Motif(), 0.0));
	}
	auto mu = move(activatedTable.front());
	--nActLevel[mu.first.getnEdge()];
	activatedTable.pop_front();
	return make_pair(true, move(mu));
}

int LocalTables::mostRecentLevel() const
{
	return candidateTables.size() - 1;
}

bool LocalTables::emptyCandidate() const
{
	for(size_t i = 0; i < candidateTables.size(); ++i) {
		if(emptyCandidate(i))
			return true;
	}
	return false;
}

bool LocalTables::emptyCandidate(const int level) const
{
	return static_cast<int>(candidateTables.size()) > level
		&& candidateTables[level].empty();
}

bool LocalTables::emptyActivated() const
{
	return activatedTable.empty();
}

bool LocalTables::emptyActivated(const int level) const
{
	return static_cast<int>(nActLevel.size()) > level
		&& nActLevel[level] == 0;
}

int LocalTables::getNumCandidate() const
{
	int res = 0;
	size_t n = candidateTables.size();
	for(size_t i = 0; i < n; ++i)
		res += candidateTables[i].size();
	return res;
}

std::vector<int> LocalTables::getNumCandidates() const
{
	size_t n = candidateTables.size();
	std::vector<int> res(n);
	for(size_t i = 0; i < n; ++i)
		res[i] = candidateTables[i].size();
	return res;
}

int LocalTables::getNumCandidate(const int level) const
{
	return static_cast<int>(candidateTables.size()) > level
		? candidateTables[level].size() : 0;
}

int LocalTables::getNumActive() const
{
	return activatedTable.size();
}

std::vector<int> LocalTables::getNumActives() const
{
	return nActLevel;
}

int LocalTables::getNumActive(const int level) const
{
	return static_cast<int>(nActLevel.size()) > level
		? nActLevel[level] : 0;
}

int LocalTables::getNumEverActive(const int level) const
{
	return static_cast<int>(nActLevelTotal.size()) > level ?
		nActLevelTotal[level] : 0;
}

bool LocalTables::empty() const
{
	unique_lock<mutex> ulc(mct, defer_lock);
	unique_lock<mutex> ula(mat, defer_lock);
	lock(ulc, ula);
	if(activatedTable.empty()) {
		for(auto& ct : candidateTables)
			if(!ct.empty())
				return false;
		return true;
	}
	return false;
}

bool LocalTables::empty(const int level) const
{
	unique_lock<mutex> ulc(mct, defer_lock);
	unique_lock<mutex> ula(mat, defer_lock);
	lock(ulc, ula);
	return candidateTables[level].empty() && nActLevel[level] == 0;
}

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: syshelp.cxx,v $
 *
 *  $Revision: 1.12 $
 *
 *  last change: $Author: hr $ $Date: 2007-11-02 12:55:32 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include <syshelp.hxx>

// NOT FULLY DEFINED SERVICES
#include <string.h>
#include "sistr.hxx"
#include "list.hxx"

#ifdef WNT
#include <io.h>
#elif defined(UNX) || defined(OS2)
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#define stricmp strcasecmp
#else
#error Must run under unix or windows, please define UNX or WNT.
#endif

char C_sSpaceInName[] = "   ";

void
WriteName( std::ostream &       o_rFile,
           const Simstr &   i_rIdlDocuBaseDir,
           const Simstr &   i_rName,
           E_LinkType       i_eLinkType )
{
    if (i_rName.l() == 0)
        return;

    const char * pNameEnd = strstr( i_rName.str(), " in " );

    // No link:
    if ( i_eLinkType == lt_nolink )
    {
        if ( pNameEnd != 0 )
        {
            const char * pStart = i_rName.str();
            o_rFile.write( pStart, pNameEnd - pStart );
            WriteStr( o_rFile, C_sSpaceInName );
            WriteStr( o_rFile, pNameEnd );
        }
        else
        {
            WriteStr( o_rFile, i_rName );
        }
        return;
    }

    if ( i_eLinkType == lt_idl )
    {
        Simstr sPath(i_rName);
        sPath.replace_all('.','/');
        int nNameEnd = sPath.pos_first(' ');
        int nPathStart = sPath.pos_last(' ');
        WriteStr( o_rFile, " -1 )
        {
            WriteStr( o_rFile, "file:///" );
            WriteStr( o_rFile, i_rIdlDocuBaseDir );
            WriteStr( o_rFile, "/" );
            WriteStr( o_rFile, sPath.str() + 1 + nPathStart );
            WriteStr( o_rFile, "/" );
            o_rFile.write( sPath.str(), nNameEnd );
            WriteStr( o_rFile, ".html\">" );
        }
        else
        {   // Should not be reached:
            WriteStr(o_rFile, i_rName);
            return;
        }
    }
    else if ( i_eLinkType == lt_html )
    {
        int nKomma = i_rName.pos_first(',');
        int nEnd = i_rName.pos_first(' ');
        if ( nKomma > -1 )
        {
            o_rFile.write( i_rName.str(), nKomma );
            WriteStr( o_rFile, ": " );

            WriteStr( o_rFile, " -1 )
                o_rFile.write( i_rName.str() + nKomma + 1, nEnd - nKomma );
            else
                WriteStr( o_rFile, i_rName.str() + nKomma + 1 );
            WriteStr( o_rFile, "\">" );

            o_rFile.write( i_rName.str() + nKomma + 1, nEnd - nKomma );
        }
        else
        {
            WriteStr( o_rFile, "" );

            WriteStr( o_rFile, i_rName );
        }
        WriteStr( o_rFile, "" );
        return;
    }

    if ( pNameEnd != 0 )
    {
        const char * pStart = i_rName.str();
        if ( pNameEnd > pStart )
            o_rFile.write( pStart, pNameEnd - pStart );
        WriteStr( o_rFile, "" );

        WriteStr( o_rFile, C_sSpaceInName );
        WriteStr( o_rFile, pNameEnd );
    }
    else
    {
        WriteStr( o_rFile, i_rName );
        WriteStr( o_rFile, "" );
    }
}

void
WriteStr( std::ostream &    o_rFile,
          const char *      i_sStr )
{
    o_rFile.write( i_sStr, (int) strlen(i_sStr) );
}

void
WriteStr( std::ostream &      o_rFile,
          const Simstr &      i_sStr )
{
    o_rFile.write( i_sStr.str(), i_sStr.l() );
}

const char C_sXML_END[] = "\\*.xml";

void
GatherFileNames( List<Simstr> &     o_sFiles,
                 const char *       i_sSrcDirectory )
{
    static int   nAliveCounter = 0;

    char *       sNextDir = 0;
    Simstr       sNew = 0;

#ifdef WNT
    struct _finddata_t aEntry;
    long hFile = 0;
    int bFindMore = 0;
    char * sFilter = new char[ strlen(i_sSrcDirectory) + sizeof C_sXML_END ];

    // Stayingalive sign
    if (++nAliveCounter % 100 == 1)
        std::cout << "." << std::flush;

    strcpy(sFilter, i_sSrcDirectory);       // STRCPY SAFE HERE
    strcat(sFilter,C_sXML_END);             // STRCAT SAFE HERE

    hFile = _findfirst( sFilter, &aEntry );
    for ( bFindMore = hFile == -1;
          bFindMore == 0;
          bFindMore = _findnext( hFile, &aEntry ) )
    {
        sNew = i_sSrcDirectory;
        sNew += "\\";
        sNew += aEntry.name;
        o_sFiles.push_back(sNew);
    }   // end for

    _findclose(hFile);
    delete [] sFilter;
#elif defined(UNX) || defined(OS2)
    DIR * pDir = opendir( i_sSrcDirectory );
    dirent * pEntry = 0;
    char * sEnding;

    // Stayingalive sign
    if (++nAliveCounter % 100 == 1)
        std::cout << "." << std::flush;

    while ( (pEntry = readdir(pDir)) != 0 )
    {
        sEnding = strrchr(pEntry->d_name,'.');
        if (sEnding != 0 ? stricmp(sEnding,".xml") == 0 : 0 )
        {
            sNew = i_sSrcDirectory;
            sNew += "/";
            sNew += pEntry->d_name;
            o_sFiles.push_back(sNew);
        }
    }   // end while

    closedir( pDir );
#else
#error Must run on unix or windows, please define UNX or WNT.
#endif

    //  gathering from subdirectories:
    List<Simstr> aSubDirectories;
    GatherSubDirectories( aSubDirectories, i_sSrcDirectory );

    unsigned d_max = aSubDirectories.size();
    for ( unsigned d = 0; d < d_max; ++d )
    {
        sNextDir = new char[ strlen(i_sSrcDirectory) + 2 + aSubDirectories[d].l() ];

        strcpy(sNextDir, i_sSrcDirectory);
        strcat(sNextDir, C_sSLASH);
        strcat(sNextDir, aSubDirectories[d].str());
        GatherFileNames(o_sFiles, sNextDir);

        delete [] sNextDir;
    }
}

const char * C_sANYDIR = "\\*.*";

void
GatherSubDirectories( List<Simstr> &    o_sSubDirectories,
                      const char *      i_sParentdDirectory )
{
    Simstr sNew;

#ifdef WNT
    struct _finddata_t aEntry;
    long hFile = 0;
    int bFindMore = 0;
    char * sFilter = new char[strlen(i_sParentdDirectory) + sizeof C_sANYDIR];

    strcpy(sFilter, i_sParentdDirectory);
    strcat(sFilter,C_sANYDIR);

    hFile = _findfirst( sFilter, &aEntry );
    for ( bFindMore = hFile == -1;
          bFindMore == 0;
          bFindMore = _findnext( hFile, &aEntry ) )
    {
        if (aEntry.attrib == _A_SUBDIR)
        {
            // Do not gather . .. and outputtree directories
            if ( strchr(aEntry.name,'.') == 0
                 && strncmp(aEntry.name, "wnt", 3) != 0
                 && strncmp(aEntry.name, "unx", 3) != 0 )
            {
                sNew = aEntry.name;
                o_sSubDirectories.push_back(sNew);
            }
        }   // endif (aEntry.attrib == _A_SUBDIR)
    }   // end for
    _findclose(hFile);
    delete [] sFilter;

#elif defined(UNX) || defined(OS2)
    DIR * pDir = opendir( i_sParentdDirectory );
    dirent * pEntry = 0;
    struct stat     aEntryStatus;

    while ( ( pEntry = readdir(pDir) ) != 0 )
    {
        stat(pEntry->d_name, &aEntryStatus);
        if ( ( aEntryStatus.st_mode & S_IFDIR ) == S_IFDIR )
        {
            // Do not gather . .. and outputtree directories
            if ( strchr(pEntry->d_name,'.') == 0
                 && strncmp(pEntry->d_name, "wnt", 3) != 0
                 && strncmp(pEntry->d_name, "unx", 3) != 0 )
            {
                sNew = pEntry->d_name;
                o_sSubDirectories.push_back(sNew);
            }
        }   // endif (aEntry.attrib == _A_SUBDIR)
    }   // end while
    closedir( pDir );
#else
#error Must run on unix or windows, please define UNX or WNT.
#endif
}

<commit_msg>INTEGRATION: CWS changefileheader (1.12.12); FILE MERGED 2008/03/31 13:06:36 rt 1.12.12.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: syshelp.cxx,v $
 * $Revision: 1.13 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#include <syshelp.hxx>

// NOT FULLY DEFINED SERVICES
#include <string.h>
#include "sistr.hxx"
#include "list.hxx"

#ifdef WNT
#include <io.h>
#elif defined(UNX) || defined(OS2)
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#define stricmp strcasecmp
#else
#error Must run under unix or windows, please define UNX or WNT.
#endif

char C_sSpaceInName[] = "   ";

void
WriteName( std::ostream &       o_rFile,
           const Simstr &   i_rIdlDocuBaseDir,
           const Simstr &   i_rName,
           E_LinkType       i_eLinkType )
{
    if (i_rName.l() == 0)
        return;

    const char * pNameEnd = strstr( i_rName.str(), " in " );

    // No link:
    if ( i_eLinkType == lt_nolink )
    {
        if ( pNameEnd != 0 )
        {
            const char * pStart = i_rName.str();
            o_rFile.write( pStart, pNameEnd - pStart );
            WriteStr( o_rFile, C_sSpaceInName );
            WriteStr( o_rFile, pNameEnd );
        }
        else
        {
            WriteStr( o_rFile, i_rName );
        }
        return;
    }

    if ( i_eLinkType == lt_idl )
    {
        Simstr sPath(i_rName);
        sPath.replace_all('.','/');
        int nNameEnd = sPath.pos_first(' ');
        int nPathStart = sPath.pos_last(' ');
        WriteStr( o_rFile, " -1 )
        {
            WriteStr( o_rFile, "file:///" );
            WriteStr( o_rFile, i_rIdlDocuBaseDir );
            WriteStr( o_rFile, "/" );
            WriteStr( o_rFile, sPath.str() + 1 + nPathStart );
            WriteStr( o_rFile, "/" );
            o_rFile.write( sPath.str(), nNameEnd );
            WriteStr( o_rFile, ".html\">" );
        }
        else
        {   // Should not be reached:
            WriteStr(o_rFile, i_rName);
            return;
        }
    }
    else if ( i_eLinkType == lt_html )
    {
        int nKomma = i_rName.pos_first(',');
        int nEnd = i_rName.pos_first(' ');
        if ( nKomma > -1 )
        {
            o_rFile.write( i_rName.str(), nKomma );
            WriteStr( o_rFile, ": " );

            WriteStr( o_rFile, " -1 )
                o_rFile.write( i_rName.str() + nKomma + 1, nEnd - nKomma );
            else
                WriteStr( o_rFile, i_rName.str() + nKomma + 1 );
            WriteStr( o_rFile, "\">" );

            o_rFile.write( i_rName.str() + nKomma + 1, nEnd - nKomma );
        }
        else
        {
            WriteStr( o_rFile, "" );

            WriteStr( o_rFile, i_rName );
        }
        WriteStr( o_rFile, "" );
        return;
    }

    if ( pNameEnd != 0 )
    {
        const char * pStart = i_rName.str();
        if ( pNameEnd > pStart )
            o_rFile.write( pStart, pNameEnd - pStart );
        WriteStr( o_rFile, "" );

        WriteStr( o_rFile, C_sSpaceInName );
        WriteStr( o_rFile, pNameEnd );
    }
    else
    {
        WriteStr( o_rFile, i_rName );
        WriteStr( o_rFile, "" );
    }
}

void
WriteStr( std::ostream &    o_rFile,
          const char *      i_sStr )
{
    o_rFile.write( i_sStr, (int) strlen(i_sStr) );
}

void
WriteStr( std::ostream &      o_rFile,
          const Simstr &      i_sStr )
{
    o_rFile.write( i_sStr.str(), i_sStr.l() );
}

const char C_sXML_END[] = "\\*.xml";

void
GatherFileNames( List<Simstr> &     o_sFiles,
                 const char *       i_sSrcDirectory )
{
    static int   nAliveCounter = 0;

    char *       sNextDir = 0;
    Simstr       sNew = 0;

#ifdef WNT
    struct _finddata_t aEntry;
    long hFile = 0;
    int bFindMore = 0;
    char * sFilter = new char[ strlen(i_sSrcDirectory) + sizeof C_sXML_END ];

    // Stayingalive sign
    if (++nAliveCounter % 100 == 1)
        std::cout << "." << std::flush;

    strcpy(sFilter, i_sSrcDirectory);       // STRCPY SAFE HERE
    strcat(sFilter,C_sXML_END);             // STRCAT SAFE HERE

    hFile = _findfirst( sFilter, &aEntry );
    for ( bFindMore = hFile == -1;
          bFindMore == 0;
          bFindMore = _findnext( hFile, &aEntry ) )
    {
        sNew = i_sSrcDirectory;
        sNew += "\\";
        sNew += aEntry.name;
        o_sFiles.push_back(sNew);
    }   // end for

    _findclose(hFile);
    delete [] sFilter;
#elif defined(UNX) || defined(OS2)
    DIR * pDir = opendir( i_sSrcDirectory );
    dirent * pEntry = 0;
    char * sEnding;

    // Stayingalive sign
    if (++nAliveCounter % 100 == 1)
        std::cout << "." << std::flush;

    while ( (pEntry = readdir(pDir)) != 0 )
    {
        sEnding = strrchr(pEntry->d_name,'.');
        if (sEnding != 0 ? stricmp(sEnding,".xml") == 0 : 0 )
        {
            sNew = i_sSrcDirectory;
            sNew += "/";
            sNew += pEntry->d_name;
            o_sFiles.push_back(sNew);
        }
    }   // end while

    closedir( pDir );
#else
#error Must run on unix or windows, please define UNX or WNT.
#endif

    //  gathering from subdirectories:
    List<Simstr> aSubDirectories;
    GatherSubDirectories( aSubDirectories, i_sSrcDirectory );

    unsigned d_max = aSubDirectories.size();
    for ( unsigned d = 0; d < d_max; ++d )
    {
        sNextDir = new char[ strlen(i_sSrcDirectory) + 2 + aSubDirectories[d].l() ];

        strcpy(sNextDir, i_sSrcDirectory);
        strcat(sNextDir, C_sSLASH);
        strcat(sNextDir, aSubDirectories[d].str());
        GatherFileNames(o_sFiles, sNextDir);

        delete [] sNextDir;
    }
}

const char * C_sANYDIR = "\\*.*";

void
GatherSubDirectories( List<Simstr> &    o_sSubDirectories,
                      const char *      i_sParentdDirectory )
{
    Simstr sNew;

#ifdef WNT
    struct _finddata_t aEntry;
    long hFile = 0;
    int bFindMore = 0;
    char * sFilter = new char[strlen(i_sParentdDirectory) + sizeof C_sANYDIR];

    strcpy(sFilter, i_sParentdDirectory);
    strcat(sFilter,C_sANYDIR);

    hFile = _findfirst( sFilter, &aEntry );
    for ( bFindMore = hFile == -1;
          bFindMore == 0;
          bFindMore = _findnext( hFile, &aEntry ) )
    {
        if (aEntry.attrib == _A_SUBDIR)
        {
            // Do not gather . .. and outputtree directories
            if ( strchr(aEntry.name,'.') == 0
                 && strncmp(aEntry.name, "wnt", 3) != 0
                 && strncmp(aEntry.name, "unx", 3) != 0 )
            {
                sNew = aEntry.name;
                o_sSubDirectories.push_back(sNew);
            }
        }   // endif (aEntry.attrib == _A_SUBDIR)
    }   // end for
    _findclose(hFile);
    delete [] sFilter;

#elif defined(UNX) || defined(OS2)
    DIR * pDir = opendir( i_sParentdDirectory );
    dirent * pEntry = 0;
    struct stat     aEntryStatus;

    while ( ( pEntry = readdir(pDir) ) != 0 )
    {
        stat(pEntry->d_name, &aEntryStatus);
        if ( ( aEntryStatus.st_mode & S_IFDIR ) == S_IFDIR )
        {
            // Do not gather . .. and outputtree directories
            if ( strchr(pEntry->d_name,'.') == 0
                 && strncmp(pEntry->d_name, "wnt", 3) != 0
                 && strncmp(pEntry->d_name, "unx", 3) != 0 )
            {
                sNew = pEntry->d_name;
                o_sSubDirectories.push_back(sNew);
            }
        }   // endif (aEntry.attrib == _A_SUBDIR)
    }   // end while
    closedir( pDir );
#else
#error Must run on unix or windows, please define UNX or WNT.
#endif
}

<|endoftext|>


<commit_before>/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.

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.
==============================================================================*/

#include "tensorflow/lite/delegates/gpu/cl/kernels/work_group_picking.h"

#include <algorithm>
#include <limits>
#include <set>
#include <vector>

#include "tensorflow/lite/delegates/gpu/common/util.h"

namespace tflite {
namespace gpu {
namespace cl {

namespace {

std::vector<int2> Get2DWorkgroupsEqualTo128() {
  return {{128, 1}, {64, 2}, {32, 4}, {16, 8},
          {8, 16},  {4, 32}, {2, 64}, {1, 128}};
}

std::vector<int3> GenerateWorkGroupSizesXY128(
    int3 grid, int max_work_group_size, WorkGroupSizeAlignment z_alignment) {
  std::vector<int3> work_groups;
  work_groups.reserve(32);

  std::vector<int> possible_z_sizes = GetPossibleSizes(grid.z, z_alignment);

  for (int x = 1; x <= max_work_group_size; x *= 2) {
    for (int y = 1; y <= max_work_group_size; y *= 2) {
      int work_group_size_xy = x * y;
      if (work_group_size_xy % 128 != 0 ||
          work_group_size_xy > max_work_group_size) {
        continue;
      }
      for (auto z : possible_z_sizes) {
        if (work_group_size_xy * z > max_work_group_size) {
          continue;
        }
        work_groups.push_back({x, y, z});
      }
    }
  }
  return work_groups;
}

std::vector<int3> GenerateWorkGroupSizesXY128Linear(
    int3 grid, int max_work_group_size, WorkGroupSizeAlignment z_alignment) {
  std::vector<int3> work_groups;
  work_groups.reserve(32);

  std::vector<int> possible_z_sizes = GetPossibleSizes(grid.z, z_alignment);

  for (int x = 128; x <= max_work_group_size && x < grid.x + 128; x += 128) {
    for (auto z : possible_z_sizes) {
      if (x * z <= max_work_group_size) {
        work_groups.push_back({x, 1, z});
      }
    }
  }
  return work_groups;
}

Status GetBestWorkGroupAlignedToGrid(const TuningParameters& params,
                                     const CLKernel& kernel, const int3& grid,
                                     int3* best_work_group) {
  std::vector<int3> work_groups;
  RETURN_IF_ERROR(GenerateWorkGroupSizesAlignedToGrid(
      grid, params.info->max_work_group_sizes, kernel.GetMaxWorkGroupSize(),
      &work_groups));
  int best_work_group_index;
  RETURN_IF_ERROR(params.queue->GetBestWorkGroupIndex(
      kernel, *params.info, grid, work_groups, &best_work_group_index));
  *best_work_group = work_groups[best_work_group_index];
  return OkStatus();
}

int GetPenalty(int grid_size, int group_size) {
  const int reminder = grid_size % group_size;
  return reminder == 0 ? 0 : group_size - reminder;
}

int GetPenalty(int2 grid_size, int2 group_size) {
  const int p_x = GetPenalty(grid_size.x, group_size.x);
  const int p_y = GetPenalty(grid_size.y, group_size.y);
  return p_x * grid_size.y + p_y * grid_size.x + p_x * p_y;
}

int GetMaxSizeWithMinPenalty(int size, int max_size) {
  int best_size = 128;
  int min_penalty = GetPenalty(size, best_size);
  for (int i = 2; i * 128 <= max_size; ++i) {
    if (GetPenalty(size, i * 128) == min_penalty) {
      best_size = i * 128;
    }
  }
  return best_size;
}

int2 GetMaxSizeWithMinPenalty(int2 size, int max_size) {
  std::vector<int2> base_groups = Get2DWorkgroupsEqualTo128();
  int min_penalty = std::numeric_limits<int>::max();
  for (auto group : base_groups) {
    min_penalty = std::min(GetPenalty(size, group), min_penalty);
  }
  for (auto group : base_groups) {
    for (int y = 1; y * group.y <= max_size; ++y) {
      int new_group_y = y * group.y;
      for (int x = 1; x * group.x <= max_size; ++x) {
        int new_group_x = x * group.x;
        if (new_group_x * new_group_y > max_size) {
          break;
        }
        if (GetPenalty(size, int2(new_group_x, new_group_y)) == min_penalty) {
          return int2(new_group_x, new_group_y);
        }
      }
    }
  }
  return int2(0, 0);
}

int GetBiggestDividerWithPriority(int number, int max_divider) {
  if (number % 8 == 0 && 8 <= max_divider) {
    return 8;
  }
  if (number % 4 == 0 && 4 <= max_divider) {
    return 4;
  }
  if (number % 2 == 0 && 2 <= max_divider) {
    return 2;
  }
  for (int i = max_divider; i != 0; i--) {
    if (number % i == 0) {
      return i;
    }
  }
  return 1;
}

int GetBiggestDivider(int number, int max_divider) {
  for (int i = max_divider; i != 0; i--) {
    if (number % i == 0) {
      return i;
    }
  }
  return 1;
}

}  // namespace

int3 GetWorkGroupXY128ConvLinear(const int3& grid) {
  int grid_z = GetBiggestDividerWithPriority(grid.z, 4);
  if (grid.x <= 128) {
    return int3(128, 1, grid_z);
  }
  int grid_x = GetMaxSizeWithMinPenalty(grid.x, 512 / grid_z);
  return {grid_x, 1, grid_z};
}

int3 GetWorkGroupXY128Conv(const int3& grid) {
  int grid_z = GetBiggestDividerWithPriority(grid.z, 4);
  if (grid.x <= 16 && grid.y <= 8) {
    return int3(16, 8, grid_z);
  }
  int2 grid_xy = GetMaxSizeWithMinPenalty(int2(grid.x, grid.y), 512 / grid_z);
  return int3(grid_xy.x, grid_xy.y, grid_z);
}

int3 GetWorkGroupXY128Simple(const int3& grid) { return int3(16, 8, 1); }

int3 GetWorkGroup(const int3& grid, int max_size) {
  int wg_z = GetBiggestDividerWithPriority(grid.z, 8);
  int wg_xy_size = max_size / wg_z;
  int wg_x = std::min(IntegralDivideRoundUp(grid.x, 2), wg_xy_size);
  int wg_y = std::min(wg_xy_size / wg_x, grid.y);
  return int3(wg_x, wg_y, wg_z);
}

int3 GetWorkGroupConv(const int3& grid, int max_size, int max_z_size) {
  int wg_z = GetBiggestDivider(grid.z, max_z_size);
  int wg_xy_size = std::min(256, max_size) / wg_z;
  int wg_x = std::min(grid.x, wg_xy_size);
  int wg_y = std::min(wg_xy_size / wg_x, grid.y);
  if (wg_y == grid.y && grid.y % 2 == 0) {
    wg_y = grid.y / 2;
  }
  return int3(wg_x, wg_y, wg_z);
}

Status GetBestWorkGroupXY128(const TuningParameters& params,
                             const CLKernel& kernel, const int3& grid,
                             WorkGroupSizeAlignment z_alignment,
                             int3* best_work_group) {
  std::vector<int3> work_groups = GenerateWorkGroupSizesXY128(
      grid, kernel.GetMaxWorkGroupSize(), z_alignment);
  int best_work_group_index;
  RETURN_IF_ERROR(params.queue->GetBestWorkGroupIndex(
      kernel, *params.info, grid, work_groups, &best_work_group_index));
  *best_work_group = work_groups[best_work_group_index];
  return OkStatus();
}

Status GetBestWorkGroupXY128Linear(const TuningParameters& params,
                                   const CLKernel& kernel, const int3& grid,
                                   WorkGroupSizeAlignment z_alignment,
                                   int3* best_work_group) {
  std::vector<int3> work_groups = GenerateWorkGroupSizesXY128Linear(
      grid, kernel.GetMaxWorkGroupSize(), z_alignment);
  int best_work_group_index;
  RETURN_IF_ERROR(params.queue->GetBestWorkGroupIndex(
      kernel, *params.info, grid, work_groups, &best_work_group_index));
  *best_work_group = work_groups[best_work_group_index];
  return OkStatus();
}

bool XY128RequiresMoreWorkGroupsThenXY128Linear(int width, int height) {
  int planar_work_groups = IntegralDivideRoundUp(width * height, 128);
  auto base_work_groups = Get2DWorkgroupsEqualTo128();
  bool have_equal_work_groups = false;
  for (auto& work_group : base_work_groups) {
    int x_groups = IntegralDivideRoundUp(width, work_group.x);
    int y_groups = IntegralDivideRoundUp(height, work_group.y);
    int xy_groups = x_groups * y_groups;
    if (xy_groups == planar_work_groups) {
      have_equal_work_groups = true;
      break;
    }
  }
  return !have_equal_work_groups;
}

Status GetBestWorkGroup(const TuningParameters& params, const CLKernel& kernel,
                        const int3& grid, int3* best_work_group) {
  switch (params.tuning_type) {
    case TuningType::FAST:
      if (params.info->vendor != Vendor::QUALCOMM) {
        *best_work_group = int3(8, 4, 1);
        return OkStatus();
      } else {
        *best_work_group = GetWorkGroup(grid, kernel.GetMaxWorkGroupSize());
        return OkStatus();
      }
    case TuningType::EXHAUSTIVE:
      return GetBestWorkGroupAlignedToGrid(params, kernel, grid,
                                           best_work_group);
    default:
      *best_work_group = {8, 4, 1};
      return OkStatus();
  }
}

Status GetBestWorkGroupConv(const TuningParameters& params,
                            const CLKernel& kernel, const int3& grid,
                            int3* best_work_group) {
  switch (params.tuning_type) {
    case TuningType::FAST:
      if (params.info->vendor != Vendor::QUALCOMM) {
        *best_work_group = int3(8, 4, 1);
        return OkStatus();
      } else {
        int max_z_size = params.info->adreno_info.gpu_version < 400 ? 16 : 64;
        *best_work_group =
            GetWorkGroupConv(grid, kernel.GetMaxWorkGroupSize(), max_z_size);
        return OkStatus();
      }
    case TuningType::EXHAUSTIVE:
      return GetBestWorkGroupAlignedToGrid(params, kernel, grid,
                                           best_work_group);
    default:
      *best_work_group = {8, 4, 1};
      return OkStatus();
  }
}

}  // namespace cl
}  // namespace gpu
}  // namespace tflite
<commit_msg>Enabling non trivial fast tuning for all vendors.<commit_after>/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.

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.
==============================================================================*/

#include "tensorflow/lite/delegates/gpu/cl/kernels/work_group_picking.h"

#include <algorithm>
#include <limits>
#include <set>
#include <vector>

#include "tensorflow/lite/delegates/gpu/common/util.h"

namespace tflite {
namespace gpu {
namespace cl {

namespace {

std::vector<int2> Get2DWorkgroupsEqualTo128() {
  return {{128, 1}, {64, 2}, {32, 4}, {16, 8},
          {8, 16},  {4, 32}, {2, 64}, {1, 128}};
}

std::vector<int3> GenerateWorkGroupSizesXY128(
    int3 grid, int max_work_group_size, WorkGroupSizeAlignment z_alignment) {
  std::vector<int3> work_groups;
  work_groups.reserve(32);

  std::vector<int> possible_z_sizes = GetPossibleSizes(grid.z, z_alignment);

  for (int x = 1; x <= max_work_group_size; x *= 2) {
    for (int y = 1; y <= max_work_group_size; y *= 2) {
      int work_group_size_xy = x * y;
      if (work_group_size_xy % 128 != 0 ||
          work_group_size_xy > max_work_group_size) {
        continue;
      }
      for (auto z : possible_z_sizes) {
        if (work_group_size_xy * z > max_work_group_size) {
          continue;
        }
        work_groups.push_back({x, y, z});
      }
    }
  }
  return work_groups;
}

std::vector<int3> GenerateWorkGroupSizesXY128Linear(
    int3 grid, int max_work_group_size, WorkGroupSizeAlignment z_alignment) {
  std::vector<int3> work_groups;
  work_groups.reserve(32);

  std::vector<int> possible_z_sizes = GetPossibleSizes(grid.z, z_alignment);

  for (int x = 128; x <= max_work_group_size && x < grid.x + 128; x += 128) {
    for (auto z : possible_z_sizes) {
      if (x * z <= max_work_group_size) {
        work_groups.push_back({x, 1, z});
      }
    }
  }
  return work_groups;
}

Status GetBestWorkGroupAlignedToGrid(const TuningParameters& params,
                                     const CLKernel& kernel, const int3& grid,
                                     int3* best_work_group) {
  std::vector<int3> work_groups;
  RETURN_IF_ERROR(GenerateWorkGroupSizesAlignedToGrid(
      grid, params.info->max_work_group_sizes, kernel.GetMaxWorkGroupSize(),
      &work_groups));
  int best_work_group_index;
  RETURN_IF_ERROR(params.queue->GetBestWorkGroupIndex(
      kernel, *params.info, grid, work_groups, &best_work_group_index));
  *best_work_group = work_groups[best_work_group_index];
  return OkStatus();
}

int GetPenalty(int grid_size, int group_size) {
  const int reminder = grid_size % group_size;
  return reminder == 0 ? 0 : group_size - reminder;
}

int GetPenalty(int2 grid_size, int2 group_size) {
  const int p_x = GetPenalty(grid_size.x, group_size.x);
  const int p_y = GetPenalty(grid_size.y, group_size.y);
  return p_x * grid_size.y + p_y * grid_size.x + p_x * p_y;
}

int GetMaxSizeWithMinPenalty(int size, int max_size) {
  int best_size = 128;
  int min_penalty = GetPenalty(size, best_size);
  for (int i = 2; i * 128 <= max_size; ++i) {
    if (GetPenalty(size, i * 128) == min_penalty) {
      best_size = i * 128;
    }
  }
  return best_size;
}

int2 GetMaxSizeWithMinPenalty(int2 size, int max_size) {
  std::vector<int2> base_groups = Get2DWorkgroupsEqualTo128();
  int min_penalty = std::numeric_limits<int>::max();
  for (auto group : base_groups) {
    min_penalty = std::min(GetPenalty(size, group), min_penalty);
  }
  for (auto group : base_groups) {
    for (int y = 1; y * group.y <= max_size; ++y) {
      int new_group_y = y * group.y;
      for (int x = 1; x * group.x <= max_size; ++x) {
        int new_group_x = x * group.x;
        if (new_group_x * new_group_y > max_size) {
          break;
        }
        if (GetPenalty(size, int2(new_group_x, new_group_y)) == min_penalty) {
          return int2(new_group_x, new_group_y);
        }
      }
    }
  }
  return int2(0, 0);
}

int GetBiggestDividerWithPriority(int number, int max_divider) {
  if (number % 8 == 0 && 8 <= max_divider) {
    return 8;
  }
  if (number % 4 == 0 && 4 <= max_divider) {
    return 4;
  }
  if (number % 2 == 0 && 2 <= max_divider) {
    return 2;
  }
  for (int i = max_divider; i != 0; i--) {
    if (number % i == 0) {
      return i;
    }
  }
  return 1;
}

int GetBiggestDivider(int number, int max_divider) {
  for (int i = max_divider; i != 0; i--) {
    if (number % i == 0) {
      return i;
    }
  }
  return 1;
}

}  // namespace

int3 GetWorkGroupXY128ConvLinear(const int3& grid) {
  int grid_z = GetBiggestDividerWithPriority(grid.z, 4);
  if (grid.x <= 128) {
    return int3(128, 1, grid_z);
  }
  int grid_x = GetMaxSizeWithMinPenalty(grid.x, 512 / grid_z);
  return {grid_x, 1, grid_z};
}

int3 GetWorkGroupXY128Conv(const int3& grid) {
  int grid_z = GetBiggestDividerWithPriority(grid.z, 4);
  if (grid.x <= 16 && grid.y <= 8) {
    return int3(16, 8, grid_z);
  }
  int2 grid_xy = GetMaxSizeWithMinPenalty(int2(grid.x, grid.y), 512 / grid_z);
  return int3(grid_xy.x, grid_xy.y, grid_z);
}

int3 GetWorkGroupXY128Simple(const int3& grid) { return int3(16, 8, 1); }

int3 GetWorkGroup(const int3& grid, int max_size) {
  int wg_z = GetBiggestDividerWithPriority(grid.z, 8);
  int wg_xy_size = max_size / wg_z;
  int wg_x = std::min(IntegralDivideRoundUp(grid.x, 2), wg_xy_size);
  int wg_y = std::min(wg_xy_size / wg_x, grid.y);
  return int3(wg_x, wg_y, wg_z);
}

int3 GetWorkGroupConv(const int3& grid, int max_size, int max_z_size) {
  int wg_z = GetBiggestDivider(grid.z, max_z_size);
  int wg_xy_size = std::min(256, max_size) / wg_z;
  int wg_x = std::min(grid.x, wg_xy_size);
  int wg_y = std::min(wg_xy_size / wg_x, grid.y);
  if (wg_y == grid.y && grid.y % 2 == 0) {
    wg_y = grid.y / 2;
  }
  return int3(wg_x, wg_y, wg_z);
}

Status GetBestWorkGroupXY128(const TuningParameters& params,
                             const CLKernel& kernel, const int3& grid,
                             WorkGroupSizeAlignment z_alignment,
                             int3* best_work_group) {
  std::vector<int3> work_groups = GenerateWorkGroupSizesXY128(
      grid, kernel.GetMaxWorkGroupSize(), z_alignment);
  int best_work_group_index;
  RETURN_IF_ERROR(params.queue->GetBestWorkGroupIndex(
      kernel, *params.info, grid, work_groups, &best_work_group_index));
  *best_work_group = work_groups[best_work_group_index];
  return OkStatus();
}

Status GetBestWorkGroupXY128Linear(const TuningParameters& params,
                                   const CLKernel& kernel, const int3& grid,
                                   WorkGroupSizeAlignment z_alignment,
                                   int3* best_work_group) {
  std::vector<int3> work_groups = GenerateWorkGroupSizesXY128Linear(
      grid, kernel.GetMaxWorkGroupSize(), z_alignment);
  int best_work_group_index;
  RETURN_IF_ERROR(params.queue->GetBestWorkGroupIndex(
      kernel, *params.info, grid, work_groups, &best_work_group_index));
  *best_work_group = work_groups[best_work_group_index];
  return OkStatus();
}

bool XY128RequiresMoreWorkGroupsThenXY128Linear(int width, int height) {
  int planar_work_groups = IntegralDivideRoundUp(width * height, 128);
  auto base_work_groups = Get2DWorkgroupsEqualTo128();
  bool have_equal_work_groups = false;
  for (auto& work_group : base_work_groups) {
    int x_groups = IntegralDivideRoundUp(width, work_group.x);
    int y_groups = IntegralDivideRoundUp(height, work_group.y);
    int xy_groups = x_groups * y_groups;
    if (xy_groups == planar_work_groups) {
      have_equal_work_groups = true;
      break;
    }
  }
  return !have_equal_work_groups;
}

Status GetBestWorkGroup(const TuningParameters& params, const CLKernel& kernel,
                        const int3& grid, int3* best_work_group) {
  switch (params.tuning_type) {
    case TuningType::FAST:
      *best_work_group = GetWorkGroup(grid, kernel.GetMaxWorkGroupSize());
      return OkStatus();
    case TuningType::EXHAUSTIVE:
      return GetBestWorkGroupAlignedToGrid(params, kernel, grid,
                                           best_work_group);
    default:
      *best_work_group = {8, 4, 1};
      return OkStatus();
  }
}

Status GetBestWorkGroupConv(const TuningParameters& params,
                            const CLKernel& kernel, const int3& grid,
                            int3* best_work_group) {
  switch (params.tuning_type) {
    case TuningType::FAST: {
      int max_z_size = 16;
      if (params.info->vendor == Vendor::QUALCOMM) {
        max_z_size = params.info->adreno_info.gpu_version < 400 ? 16 : 64;
      }
      max_z_size = std::min(max_z_size, params.info->max_work_group_sizes.z);
      *best_work_group =
          GetWorkGroupConv(grid, kernel.GetMaxWorkGroupSize(), max_z_size);
      return OkStatus();
    }
    case TuningType::EXHAUSTIVE:
      return GetBestWorkGroupAlignedToGrid(params, kernel, grid,
                                           best_work_group);
    default:
      *best_work_group = {8, 4, 1};
      return OkStatus();
  }
}

}  // namespace cl
}  // namespace gpu
}  // namespace tflite
<|endoftext|>


<commit_before>#include <vector>
#include <algorithm> /* heap operations, std::sort */
#include <iostream>

#include <shogun/converter/LocallyLinearEmbedding.h>
#include <shogun/distance/EuclideanDistance.h>
#include <shogun/features/DenseFeatures.h>
#include <shogun/features/DataGenerator.h>
#include <gtest/gtest.h>

using namespace shogun;

#ifdef HAVE_EIGEN3

struct index_and_distance_struct
{
	float64_t distance;
	index_t neighbor_index;
} ;

struct heap_comparator
{
	bool operator() (const index_and_distance_struct& first, const index_and_distance_struct& second)
	{
		return first.distance > second.distance;
	}
} comparator;

std::vector<index_t> get_neighbors_indices(CDistance* distance_object, index_t feature_vector_index, index_t n_neighbors);

TEST(LocallyLinearEmbeddingTest,neighbors_preserving)
{
	const index_t n_samples = 100;
	const index_t n_gaussians = 1;
	const index_t n_dimensions = 4;
	const index_t n_target_dimensions = 3;
	const index_t n_neighbors = 30;
	CDenseFeatures<float64_t>* high_dimensional_features =
		new CDenseFeatures<float64_t>(CDataGenerator::generate_gaussians(n_samples, n_gaussians, n_dimensions));

	CDistance* high_dimensional_dist =
		new CEuclideanDistance(high_dimensional_features, high_dimensional_features);

	std::vector<std::vector<index_t> > neighbors_for_vectors;
	/* Find n_neighbors nearest eighbours for each vector */
	for (index_t i=0; i<n_samples; ++i)
	{
		neighbors_for_vectors.push_back(get_neighbors_indices(high_dimensional_dist, i, n_neighbors));
	}

	CLocallyLinearEmbedding* lleEmbedder =
		new CLocallyLinearEmbedding();
	lleEmbedder->set_k(n_neighbors);

	lleEmbedder->set_target_dim(n_target_dimensions);
	EXPECT_EQ(n_target_dimensions, lleEmbedder->get_target_dim());

	CDenseFeatures<float64_t>* low_dimensional_features =
		lleEmbedder->embed(high_dimensional_features);

	EXPECT_EQ(n_target_dimensions,low_dimensional_features->get_dim_feature_space());
	EXPECT_EQ(high_dimensional_features->get_num_vectors(),low_dimensional_features->get_num_vectors());

	CDistance* low_dimensional_dist =
		new CEuclideanDistance(low_dimensional_features, low_dimensional_features);

	for (index_t i=0; i<n_samples; ++i)
	{
		ASSERT_EQ(neighbors_for_vectors[i], get_neighbors_indices(low_dimensional_dist, i, n_neighbors));
	}

	SG_UNREF(lleEmbedder);
	SG_UNREF(high_dimensional_dist);
	SG_UNREF(low_dimensional_dist);
}

std::vector<index_t> get_neighbors_indices(CDistance* distance_object, index_t feature_vector_index, index_t n_neighbors)
{
	index_t n_vectors = distance_object->get_num_vec_lhs();
	EXPECT_EQ(n_vectors, distance_object->get_num_vec_rhs());
	EXPECT_LE(n_neighbors, n_vectors - 1) << "Number of neigbors can not be greater than total number of vectors minus 1";
	EXPECT_LE(feature_vector_index, n_vectors - 1);

	std::vector<index_and_distance_struct> distances_and_indices;

	for (index_t j = 0; j<n_vectors; ++j)
	{
		if (j == feature_vector_index)
			/* To avoid adding itself to the neighbors list */
			continue;
		index_and_distance_struct current;
		current.distance = distance_object->distance(feature_vector_index, j);
		current.neighbor_index = j;
		distances_and_indices.push_back(current);
	}

	/* Heapify, and then extract n_neighbors nearest neighbors*/
	std::make_heap(distances_and_indices.begin(), distances_and_indices.end(), comparator);
	std::vector<index_t> neighbors_for_current_vector;
	for (index_t j = 0; j < n_neighbors; ++j)
	{
		neighbors_for_current_vector.push_back(distances_and_indices[0].neighbor_index);
		std::pop_heap(distances_and_indices.begin(), distances_and_indices.end(), comparator);
		distances_and_indices.pop_back();
	}
	std::sort(neighbors_for_current_vector.begin(), neighbors_for_current_vector.end());
	return neighbors_for_current_vector;
}

#endif
<commit_msg>Modified unit test for Locally Linear Embedding, so that it allows 'misses' of neighbors before and after the dimensionality reduction.<commit_after>#include <vector>
#include <set>
#include <algorithm> /* heap operations, std::sort */
#include <iostream>

#include <shogun/converter/LocallyLinearEmbedding.h>
#include <shogun/distance/EuclideanDistance.h>
#include <shogun/features/DenseFeatures.h>
#include <shogun/features/DataGenerator.h>
#include <gtest/gtest.h>

using namespace shogun;

#ifdef HAVE_EIGEN3

struct index_and_distance_struct
{
	float64_t distance;
	index_t neighbor_index;
} ;

struct heap_comparator
{
	bool operator() (const index_and_distance_struct& first, const index_and_distance_struct& second)
	{
		return first.distance > second.distance;
	}
} comparator;

std::set<index_t> get_neighbors_indices(CDistance* distance_object, index_t feature_vector_index, index_t n_neighbors);

void check_similarity_of_sets(const std::set<index_t>& first_set,const std::set<index_t>& second_set, float min_similarity_level);

TEST(LocallyLinearEmbeddingTest,neighbors_preserving)
{
	const index_t n_samples = 100;
	const index_t n_gaussians = 1;
	const index_t n_dimensions = 4;
	const index_t n_target_dimensions = 3;
	const index_t n_neighbors = 40;
	const float required_similarity_level = 0.5; /*hope we will get rid of this*/
	CDenseFeatures<float64_t>* high_dimensional_features =
		new CDenseFeatures<float64_t>(CDataGenerator::generate_gaussians(n_samples, n_gaussians, n_dimensions));

	CDistance* high_dimensional_dist =
		new CEuclideanDistance(high_dimensional_features, high_dimensional_features);

	std::vector<std::set<index_t> > high_dimensional_neighbors_for_vectors;
	/* Find n_neighbors nearest eighbours for each vector */
	for (index_t i=0; i<n_samples; ++i)
	{
		high_dimensional_neighbors_for_vectors.push_back(get_neighbors_indices(high_dimensional_dist, i, n_neighbors));
	}

	CLocallyLinearEmbedding* lleEmbedder =
		new CLocallyLinearEmbedding();
	lleEmbedder->set_k(n_neighbors);

	lleEmbedder->set_target_dim(n_target_dimensions);
	EXPECT_EQ(n_target_dimensions, lleEmbedder->get_target_dim());

	CDenseFeatures<float64_t>* low_dimensional_features =
		lleEmbedder->embed(high_dimensional_features);

	EXPECT_EQ(n_target_dimensions,low_dimensional_features->get_dim_feature_space());
	EXPECT_EQ(high_dimensional_features->get_num_vectors(),low_dimensional_features->get_num_vectors());

	CDistance* low_dimensional_dist =
		new CEuclideanDistance(low_dimensional_features, low_dimensional_features);

	for (index_t i=0; i<n_samples; ++i)
	{
		std::set<index_t> low_dimensional_neighbors = get_neighbors_indices(low_dimensional_dist, i, n_neighbors);
		check_similarity_of_sets(high_dimensional_neighbors_for_vectors[i], low_dimensional_neighbors, required_similarity_level);
	}

	SG_UNREF(lleEmbedder);
	SG_UNREF(high_dimensional_dist);
	SG_UNREF(low_dimensional_dist);
}

std::set<index_t> get_neighbors_indices(CDistance* distance_object, index_t feature_vector_index, index_t n_neighbors)
{
	index_t n_vectors = distance_object->get_num_vec_lhs();
	EXPECT_EQ(n_vectors, distance_object->get_num_vec_rhs());
	EXPECT_LE(n_neighbors, n_vectors - 1) << "Number of neigbors can not be greater than total number of vectors minus 1";
	EXPECT_LE(feature_vector_index, n_vectors - 1);

	std::vector<index_and_distance_struct> distances_and_indices;

	for (index_t j = 0; j<n_vectors; ++j)
	{
		if (j == feature_vector_index)
			/* To avoid adding itself to the neighbors list */
			continue;
		index_and_distance_struct current;
		current.distance = distance_object->distance(feature_vector_index, j);
		current.neighbor_index = j;
		distances_and_indices.push_back(current);
	}

	/* Heapify, and then extract n_neighbors nearest neighbors*/
	std::make_heap(distances_and_indices.begin(), distances_and_indices.end(), comparator);
	std::set<index_t> neighbors_for_current_vector;
	for (index_t j = 0; j < n_neighbors; ++j)
	{
		neighbors_for_current_vector.insert(distances_and_indices[0].neighbor_index);
		std::pop_heap(distances_and_indices.begin(), distances_and_indices.end(), comparator);
		distances_and_indices.pop_back();
	}
	return neighbors_for_current_vector;
}

void check_similarity_of_sets(const std::set<index_t>& first_set,const std::set<index_t>& second_set, float min_similarity_level)
{
	index_t total_elements_count = first_set.size();
	ASSERT_EQ(total_elements_count, second_set.size()) << "Can not compare sets of different size.";
	ASSERT_LE(min_similarity_level, 1.0) << "Similarity level can not be greater than 1.";
	ASSERT_GE(min_similarity_level, 0) << "Similarity level can not be less than 0.";
	if (min_similarity_level == 0)
		/*Nothing to do*/
		return;
	index_t similar_elements_count = 0;
	std::set<index_t>::iterator first_iter = first_set.begin(), second_iter = second_set.begin();
	while (first_iter != first_set.end() && second_iter != second_set.end())
	{
		if (*first_iter < *second_iter)
			++first_iter;
		else if (*second_iter < *first_iter)
			++second_iter;
		else
		{
			++similar_elements_count; ++first_iter; ++second_iter;
		}
	}
	EXPECT_GE((float) similar_elements_count /(float) total_elements_count, min_similarity_level)<<"#similarElements/#total < minimal similarity level.";
}
#endif
<|endoftext|>