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

  Program:   Visualization Toolkit
  Module:    vtkMapServerSource.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm 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 notice for more information.

=========================================================================*/
#include "vtkMapServerSource.h"

#include "vtkPolyData.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkStreamingDemandDrivenPipeline.h"
#include "vtkSmartPointer.h"
#include "vtkTransform.h"
#include "vtkTransformPolyDataFilter.h"
#include "vtkNew.h"

#include <vtkIdList.h>
#include <vtkCellArray.h>
#include <vtkPoints.h>
#include <vtkDoubleArray.h>
#include <vtkFloatArray.h>
#include <vtkPointData.h>

#include <Eigen/Dense>
#include <boost/shared_ptr.hpp>
#include <boost/thread/thread.hpp>

#include <lcm/lcm-cpp.hpp>

//#include <lcmtypes/drc_lcmtypes.hpp>
#include <lcmtypes/drc/map_image_t.hpp>
#include <lcmtypes/drc/map_cloud_t.hpp>

#include <maps/LcmTranslator.hpp>
#include <maps/DepthImageView.hpp>
#include <maps/PointCloudView.hpp>

#include <sys/select.h>
#include <deque>

namespace
{

//----------------------------------------------------------------------------
vtkSmartPointer<vtkCellArray> NewVertexCells(vtkIdType numberOfVerts)
{
  vtkNew<vtkIdTypeArray> cells;
  cells->SetNumberOfValues(numberOfVerts*2);
  vtkIdType* ids = cells->GetPointer(0);
  for (vtkIdType i = 0; i < numberOfVerts; ++i)
    {
    ids[i*2] = 1;
    ids[i*2+1] = i;
    }

  vtkSmartPointer<vtkCellArray> cellArray = vtkSmartPointer<vtkCellArray>::New();
  cellArray->SetCells(numberOfVerts, cells.GetPointer());
  return cellArray;
}

//----------------------------------------------------------------------------
vtkSmartPointer<vtkPolyData> PolyDataFromPointCloud(pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr cloud)
{
  vtkIdType nr_points = cloud->points.size();

  vtkNew<vtkPoints> points;
  points->SetDataTypeToFloat();
  points->SetNumberOfPoints(nr_points);

  vtkNew<vtkUnsignedCharArray> rgbArray;
  rgbArray->SetName("rgb_colors");
  rgbArray->SetNumberOfComponents(3);
  rgbArray->SetNumberOfTuples(nr_points);

  if (cloud->is_dense)
  {
    for (vtkIdType i = 0; i < nr_points; ++i) {
      float point[3] = {cloud->points[i].x, cloud->points[i].y, cloud->points[i].z};
      unsigned char color[3] = {cloud->points[i].r, cloud->points[i].g, cloud->points[i].b};
      points->SetPoint(i, point);
      rgbArray->SetTupleValue(i, color);
    }
  }
  else
  {
    vtkIdType j = 0;    // true point index
    for (vtkIdType i = 0; i < nr_points; ++i)
    {
      // Check if the point is invalid
      if (!pcl_isfinite (cloud->points[i].x) ||
          !pcl_isfinite (cloud->points[i].y) ||
          !pcl_isfinite (cloud->points[i].z))
        continue;

      float point[3] = {cloud->points[i].x, cloud->points[i].y, cloud->points[i].z};
      unsigned char color[3] = {cloud->points[i].r, cloud->points[i].g, cloud->points[i].b};
      points->SetPoint(j, point);
      rgbArray->SetTupleValue(j, color);
      j++;
    }
    nr_points = j;
    points->SetNumberOfPoints(nr_points);
    rgbArray->SetNumberOfTuples(nr_points);
  }

  vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New();
  polyData->SetPoints(points.GetPointer());
  polyData->GetPointData()->AddArray(rgbArray.GetPointer());
  polyData->SetVerts(NewVertexCells(nr_points));
  return polyData;
}

//----------------------------------------------------------------------------
class MapData
{
public:
  uint64_t Id;
  vtkSmartPointer<vtkPolyData> Data;
};

//----------------------------------------------------------------------------
class LCMListener
{
public:

  LCMListener()
  {
    this->ShouldStop = true;
    this->NewData = false;
    this->MaxNumberOfDatasets = 100;
    this->CurrentMapId = -1;

    this->LCMHandle = boost::shared_ptr<lcm::LCM>(new lcm::LCM);
    if(!this->LCMHandle->good())
    {
      std::cerr <<"ERROR: lcm is not good()" <<std::endl;
    }

    this->LCMHandle->subscribe( "MAP_DEPTH", &LCMListener::depthHandler, this);
    this->LCMHandle->subscribe( "MAP_CLOUD", &LCMListener::cloudHandler, this);
  }

  void cloudHandler(const lcm::ReceiveBuffer* rbuf, const std::string& channel, const drc::map_cloud_t* msg)
  {
    this->HandleNewData(msg);
  }

  void depthHandler(const lcm::ReceiveBuffer* rbuf, const std::string& channel, const drc::map_image_t* msg)
  {
    this->HandleNewData(msg);
  }

  bool CheckForNewData()
  {
    boost::lock_guard<boost::mutex> lock(this->Mutex);
    bool newData = this->NewData;
    this->NewData = false;
    return newData;
  }

  bool WaitForLCM(double timeout)
  {
    int lcmFd = this->LCMHandle->getFileno();

    timeval tv;
    tv.tv_sec = 0;
    tv.tv_usec = timeout * 1e6;

    fd_set fds;
    FD_ZERO(&fds);
    FD_SET(lcmFd, &fds);

    int status = select(lcmFd + 1, &fds, 0, 0, &tv);
    return (status != 0 && FD_ISSET(lcmFd, &fds));
  }

  void ThreadLoopWithSelect()
  {
    while (!this->ShouldStop)
    {
      const double timeoutInSeconds = 0.3;
      bool lcmReady = this->WaitForLCM(timeoutInSeconds);

      if (this->ShouldStop)
      {
        break;
      }

      if (lcmReady)
      {
        if (this->LCMHandle->handle() != 0)
        {
          printf("lcm->handle() returned non-zero\n");
          break;
        }
      }
    }

  }

  void ThreadLoop()
  {
    while (!this->ShouldStop)
    {
      if (this->LCMHandle->handle() != 0)
      {
        printf("lcm->handle() returned non-zero\n");
        break;
      }
    }
  }

  void Start()
  {
    if (this->Thread)
      {
      return;
      }

    printf("starting\n");

    this->ShouldStop = false;
    this->Thread = boost::shared_ptr<boost::thread>(
      new boost::thread(boost::bind(&LCMListener::ThreadLoopWithSelect, this)));
  }

  void Stop()
  {
    if (this->Thread)
      {
      printf("stopping thread...\n");
      this->ShouldStop = true;
      this->Thread->interrupt();
      this->Thread->join();
      this->Thread.reset();
      printf("done.\n");
      }
  }

  std::vector<vtkSmartPointer<vtkPolyData> > GetDatasets()
  {
    std::vector<vtkSmartPointer<vtkPolyData> > datasets;

    boost::lock_guard<boost::mutex> lock(this->Mutex);
    for (size_t i = 0; i < this->Datasets.size(); ++i)
      {
      datasets.push_back(this->Datasets[i].Data);
      }

    return datasets;
  }

  std::vector<double> GetTimesteps()
  {
    boost::lock_guard<boost::mutex> lock(this->Mutex);

    std::vector<double> timesteps;
    for (int i = 0; i < this->Datasets.size(); ++i)
      {
      timesteps.push_back(i);
      }
    return timesteps;
  }

  vtkSmartPointer<vtkPolyData> GetDatasetForTime(int timestep)
  {
    boost::lock_guard<boost::mutex> lock(this->Mutex);
    if (timestep >= 0 && timestep < this->Datasets.size())
      {
      return this->Datasets[timestep].Data;
      }
    else
      {
      return 0;
      }
  }

  vtkIdType GetCurrentMapId()
  {
    return this->CurrentMapId;
  }

  void GetDataForMapId(vtkIdType mapId, vtkPolyData* polyData)
  {
    if (!polyData)
      {
      return;
      }

    boost::lock_guard<boost::mutex> lock(this->Mutex);
    for (size_t i = 0; i < this->Datasets.size(); ++i)
      {
      if (this->Datasets[i].Id == mapId)
        {
        polyData->DeepCopy(this->Datasets[i].Data);
        }
      }
  }

protected:

  void UpdateDequeSize()
  {
    if (this->MaxNumberOfDatasets <= 0)
      {
      return;
      }
    while (this->Datasets.size() >= this->MaxNumberOfDatasets)
      {
      this->Datasets.pop_front();
      }
  }

  void HandleNewData(const drc::map_image_t* msg)
  {
    maps::DepthImageView depthImage;
    maps::LcmTranslator::fromLcm(*msg, depthImage);

    maps::PointCloud::Ptr pointCloud = depthImage.getAsPointCloud();

    MapData mapData;
    mapData.Id = ++this->CurrentMapId;
    mapData.Data = PolyDataFromPointCloud(pointCloud);

    printf("storing depth map id: %d.  %d points\n", mapData.Id, mapData.Data->GetNumberOfPoints());

    // store data
    boost::lock_guard<boost::mutex> lock(this->Mutex);
    this->Datasets.push_back(mapData);
    this->UpdateDequeSize();
    this->NewData = true;
  }

  void HandleNewData(const drc::map_cloud_t* msg)
  {
    maps::PointCloudView cloudView;
    maps::LcmTranslator::fromLcm(*msg, cloudView);

    maps::PointCloud::Ptr pointCloud = cloudView.getAsPointCloud();

    MapData mapData;
    mapData.Id = ++this->CurrentMapId;
    mapData.Data = PolyDataFromPointCloud(pointCloud);

    printf("storing cloud map id: %d.  %d points\n", mapData.Id, mapData.Data->GetNumberOfPoints());

    // store data
    boost::lock_guard<boost::mutex> lock(this->Mutex);
    this->Datasets.push_back(mapData);
    this->UpdateDequeSize();
    this->NewData = true;
  }

  bool NewData;
  bool ShouldStop;
  int MaxNumberOfDatasets;
  vtkIdType CurrentMapId;

  boost::mutex Mutex;

  std::deque<MapData> Datasets;

  boost::shared_ptr<lcm::LCM> LCMHandle;

  boost::shared_ptr<boost::thread> Thread;

};

} // end namespace

//----------------------------------------------------------------------------
class vtkMapServerSource::vtkInternal
{
public:

  vtkInternal()
  {
    this->Listener = boost::shared_ptr<LCMListener>(new LCMListener);
  }

  ~vtkInternal()
  {
  }

  boost::shared_ptr<LCMListener> Listener;
};

//----------------------------------------------------------------------------
vtkStandardNewMacro(vtkMapServerSource);

//----------------------------------------------------------------------------
vtkMapServerSource::vtkMapServerSource()
{
  this->Internal = new vtkInternal;
  this->SetNumberOfInputPorts(0);
  this->SetNumberOfOutputPorts(1);
}

//----------------------------------------------------------------------------
vtkMapServerSource::~vtkMapServerSource()
{
  this->Stop();
  delete this->Internal;
}

//----------------------------------------------------------------------------
void vtkMapServerSource::Start()
{
  this->Internal->Listener->Start();
}

//----------------------------------------------------------------------------
void vtkMapServerSource::Stop()
{
  this->Internal->Listener->Stop();
}

//----------------------------------------------------------------------------
void vtkMapServerSource::Poll()
{
  if (this->Internal->Listener->CheckForNewData())
    {
    this->Modified();
    }
}

//-----------------------------------------------------------------------------
int vtkMapServerSource::GetNumberOfDatasets()
{
  return this->Internal->Listener->GetDatasets().size();
}

//-----------------------------------------------------------------------------
vtkIdType vtkMapServerSource::GetCurrentMapId()
{
  return this->Internal->Listener->GetCurrentMapId();
}

//-----------------------------------------------------------------------------
void vtkMapServerSource::GetDataForMapId(vtkIdType mapId, vtkPolyData* polyData)
{
  return this->Internal->Listener->GetDataForMapId(mapId, polyData);
}

//-----------------------------------------------------------------------------
vtkPolyData* vtkMapServerSource::GetDataset(int i)
{
  return this->Internal->Listener->GetDatasetForTime(i);
}

//-----------------------------------------------------------------------------
int vtkMapServerSource::RequestInformation(vtkInformation *request,
                                     vtkInformationVector **inputVector,
                                     vtkInformationVector *outputVector)
{
  vtkInformation *info = outputVector->GetInformationObject(0);

  printf("requst info\n");

  std::vector<double> timesteps = this->Internal->Listener->GetTimesteps();
  if (timesteps.size())
    {
    double timeRange[2] = {timesteps.front(), timesteps.back()};

    printf("time range: [%f, %f]\n", timeRange[0], timeRange[1]);

    info->Set(vtkStreamingDemandDrivenPipeline::TIME_STEPS(), &timesteps.front(), timesteps.size());
    info->Set(vtkStreamingDemandDrivenPipeline::TIME_RANGE(), timeRange, 2);
    }
  else
    {
    printf("no timesteps available\n");
    info->Remove(vtkStreamingDemandDrivenPipeline::TIME_STEPS());
    info->Remove(vtkStreamingDemandDrivenPipeline::TIME_RANGE());
    }

  return 1;
}

//----------------------------------------------------------------------------
int vtkMapServerSource::RequestData(
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **inputVector,
  vtkInformationVector *outputVector)
{
  printf("request data\n");

  vtkInformation *info = outputVector->GetInformationObject(0);
  vtkDataSet *output = vtkDataSet::SafeDownCast(info->Get(vtkDataObject::DATA_OBJECT()));

  int timestep = 0;
  if (info->Has(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEPS()))
    {
    double timeRequest = info->Get(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEPS())[0];
    timestep = static_cast<int>(floor(timeRequest+0.5));
    }

  vtkSmartPointer<vtkPolyData> polyData = this->Internal->Listener->GetDatasetForTime(timestep);
  if (polyData)
    {
    output->ShallowCopy(polyData);
    }
  else
    {
    printf("no data\n");
    }

  return 1;
}

//----------------------------------------------------------------------------
void vtkMapServerSource::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
}
<commit_msg>fix lcm select in vtkMapServerSource.cxx<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkMapServerSource.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm 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 notice for more information.

=========================================================================*/
#include "vtkMapServerSource.h"

#include "vtkPolyData.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkStreamingDemandDrivenPipeline.h"
#include "vtkSmartPointer.h"
#include "vtkTransform.h"
#include "vtkTransformPolyDataFilter.h"
#include "vtkNew.h"

#include <vtkIdList.h>
#include <vtkCellArray.h>
#include <vtkPoints.h>
#include <vtkDoubleArray.h>
#include <vtkFloatArray.h>
#include <vtkPointData.h>

#include <Eigen/Dense>
#include <boost/shared_ptr.hpp>
#include <boost/thread/thread.hpp>

#include <lcm/lcm-cpp.hpp>

//#include <lcmtypes/drc_lcmtypes.hpp>
#include <lcmtypes/drc/map_image_t.hpp>
#include <lcmtypes/drc/map_cloud_t.hpp>

#include <maps/LcmTranslator.hpp>
#include <maps/DepthImageView.hpp>
#include <maps/PointCloudView.hpp>

#include <sys/select.h>
#include <deque>

namespace
{

//----------------------------------------------------------------------------
vtkSmartPointer<vtkCellArray> NewVertexCells(vtkIdType numberOfVerts)
{
  vtkNew<vtkIdTypeArray> cells;
  cells->SetNumberOfValues(numberOfVerts*2);
  vtkIdType* ids = cells->GetPointer(0);
  for (vtkIdType i = 0; i < numberOfVerts; ++i)
    {
    ids[i*2] = 1;
    ids[i*2+1] = i;
    }

  vtkSmartPointer<vtkCellArray> cellArray = vtkSmartPointer<vtkCellArray>::New();
  cellArray->SetCells(numberOfVerts, cells.GetPointer());
  return cellArray;
}

//----------------------------------------------------------------------------
vtkSmartPointer<vtkPolyData> PolyDataFromPointCloud(pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr cloud)
{
  vtkIdType nr_points = cloud->points.size();

  vtkNew<vtkPoints> points;
  points->SetDataTypeToFloat();
  points->SetNumberOfPoints(nr_points);

  vtkNew<vtkUnsignedCharArray> rgbArray;
  rgbArray->SetName("rgb_colors");
  rgbArray->SetNumberOfComponents(3);
  rgbArray->SetNumberOfTuples(nr_points);

  if (cloud->is_dense)
  {
    for (vtkIdType i = 0; i < nr_points; ++i) {
      float point[3] = {cloud->points[i].x, cloud->points[i].y, cloud->points[i].z};
      unsigned char color[3] = {cloud->points[i].r, cloud->points[i].g, cloud->points[i].b};
      points->SetPoint(i, point);
      rgbArray->SetTupleValue(i, color);
    }
  }
  else
  {
    vtkIdType j = 0;    // true point index
    for (vtkIdType i = 0; i < nr_points; ++i)
    {
      // Check if the point is invalid
      if (!pcl_isfinite (cloud->points[i].x) ||
          !pcl_isfinite (cloud->points[i].y) ||
          !pcl_isfinite (cloud->points[i].z))
        continue;

      float point[3] = {cloud->points[i].x, cloud->points[i].y, cloud->points[i].z};
      unsigned char color[3] = {cloud->points[i].r, cloud->points[i].g, cloud->points[i].b};
      points->SetPoint(j, point);
      rgbArray->SetTupleValue(j, color);
      j++;
    }
    nr_points = j;
    points->SetNumberOfPoints(nr_points);
    rgbArray->SetNumberOfTuples(nr_points);
  }

  vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New();
  polyData->SetPoints(points.GetPointer());
  polyData->GetPointData()->AddArray(rgbArray.GetPointer());
  polyData->SetVerts(NewVertexCells(nr_points));
  return polyData;
}

//----------------------------------------------------------------------------
class MapData
{
public:
  uint64_t Id;
  vtkSmartPointer<vtkPolyData> Data;
};

//----------------------------------------------------------------------------
class LCMListener
{
public:

  LCMListener()
  {
    this->ShouldStop = true;
    this->NewData = false;
    this->MaxNumberOfDatasets = 100;
    this->CurrentMapId = -1;

    this->LCMHandle = boost::shared_ptr<lcm::LCM>(new lcm::LCM);
    if(!this->LCMHandle->good())
    {
      std::cerr <<"ERROR: lcm is not good()" <<std::endl;
    }

    this->LCMHandle->subscribe( "MAP_DEPTH", &LCMListener::depthHandler, this);
    this->LCMHandle->subscribe( "MAP_CLOUD", &LCMListener::cloudHandler, this);
  }

  void cloudHandler(const lcm::ReceiveBuffer* rbuf, const std::string& channel, const drc::map_cloud_t* msg)
  {
    this->HandleNewData(msg);
  }

  void depthHandler(const lcm::ReceiveBuffer* rbuf, const std::string& channel, const drc::map_image_t* msg)
  {
    this->HandleNewData(msg);
  }

  bool CheckForNewData()
  {
    boost::lock_guard<boost::mutex> lock(this->Mutex);
    bool newData = this->NewData;
    this->NewData = false;
    return newData;
  }

  bool WaitForLCM(double timeout)
  {
    int lcmFd = this->LCMHandle->getFileno();

    timeval tv;
    tv.tv_sec = 0;
    tv.tv_usec = timeout * 1e6;

    fd_set fds;
    FD_ZERO(&fds);
    FD_SET(lcmFd, &fds);

    int status = select(lcmFd + 1, &fds, 0, 0, &tv);
    if (status == -1 && errno != EINTR)
    {
      printf("select() returned error: %d\n", errno);
    }
    else if (status == -1 && errno == EINTR)
    {
      printf("select() interrupted\n");
    }
    return (status > 0 && FD_ISSET(lcmFd, &fds));
  }

  void ThreadLoopWithSelect()
  {
    while (!this->ShouldStop)
    {
      const double timeoutInSeconds = 0.3;
      bool lcmReady = this->WaitForLCM(timeoutInSeconds);

      if (this->ShouldStop)
      {
        break;
      }

      if (lcmReady)
      {
        if (this->LCMHandle->handle() != 0)
        {
          printf("lcm->handle() returned non-zero\n");
          break;
        }
      }
    }

  }

  void ThreadLoop()
  {
    while (!this->ShouldStop)
    {
      if (this->LCMHandle->handle() != 0)
      {
        printf("lcm->handle() returned non-zero\n");
        break;
      }
    }
  }

  void Start()
  {
    if (this->Thread)
      {
      return;
      }

    printf("starting\n");

    this->ShouldStop = false;
    this->Thread = boost::shared_ptr<boost::thread>(
      new boost::thread(boost::bind(&LCMListener::ThreadLoopWithSelect, this)));
  }

  void Stop()
  {
    if (this->Thread)
      {
      printf("stopping thread...\n");
      this->ShouldStop = true;
      this->Thread->interrupt();
      this->Thread->join();
      this->Thread.reset();
      printf("done.\n");
      }
  }

  std::vector<vtkSmartPointer<vtkPolyData> > GetDatasets()
  {
    std::vector<vtkSmartPointer<vtkPolyData> > datasets;

    boost::lock_guard<boost::mutex> lock(this->Mutex);
    for (size_t i = 0; i < this->Datasets.size(); ++i)
      {
      datasets.push_back(this->Datasets[i].Data);
      }

    return datasets;
  }

  std::vector<double> GetTimesteps()
  {
    boost::lock_guard<boost::mutex> lock(this->Mutex);

    std::vector<double> timesteps;
    for (int i = 0; i < this->Datasets.size(); ++i)
      {
      timesteps.push_back(i);
      }
    return timesteps;
  }

  vtkSmartPointer<vtkPolyData> GetDatasetForTime(int timestep)
  {
    boost::lock_guard<boost::mutex> lock(this->Mutex);
    if (timestep >= 0 && timestep < this->Datasets.size())
      {
      return this->Datasets[timestep].Data;
      }
    else
      {
      return 0;
      }
  }

  vtkIdType GetCurrentMapId()
  {
    return this->CurrentMapId;
  }

  void GetDataForMapId(vtkIdType mapId, vtkPolyData* polyData)
  {
    if (!polyData)
      {
      return;
      }

    boost::lock_guard<boost::mutex> lock(this->Mutex);
    for (size_t i = 0; i < this->Datasets.size(); ++i)
      {
      if (this->Datasets[i].Id == mapId)
        {
        polyData->DeepCopy(this->Datasets[i].Data);
        }
      }
  }

protected:

  void UpdateDequeSize()
  {
    if (this->MaxNumberOfDatasets <= 0)
      {
      return;
      }
    while (this->Datasets.size() >= this->MaxNumberOfDatasets)
      {
      this->Datasets.pop_front();
      }
  }

  void HandleNewData(const drc::map_image_t* msg)
  {
    maps::DepthImageView depthImage;
    maps::LcmTranslator::fromLcm(*msg, depthImage);

    maps::PointCloud::Ptr pointCloud = depthImage.getAsPointCloud();

    MapData mapData;
    mapData.Id = ++this->CurrentMapId;
    mapData.Data = PolyDataFromPointCloud(pointCloud);

    printf("storing depth map id: %d.  %d points\n", mapData.Id, mapData.Data->GetNumberOfPoints());

    // store data
    boost::lock_guard<boost::mutex> lock(this->Mutex);
    this->Datasets.push_back(mapData);
    this->UpdateDequeSize();
    this->NewData = true;
  }

  void HandleNewData(const drc::map_cloud_t* msg)
  {
    maps::PointCloudView cloudView;
    maps::LcmTranslator::fromLcm(*msg, cloudView);

    maps::PointCloud::Ptr pointCloud = cloudView.getAsPointCloud();

    MapData mapData;
    mapData.Id = ++this->CurrentMapId;
    mapData.Data = PolyDataFromPointCloud(pointCloud);

    printf("storing cloud map id: %d.  %d points\n", mapData.Id, mapData.Data->GetNumberOfPoints());

    // store data
    boost::lock_guard<boost::mutex> lock(this->Mutex);
    this->Datasets.push_back(mapData);
    this->UpdateDequeSize();
    this->NewData = true;
  }

  bool NewData;
  bool ShouldStop;
  int MaxNumberOfDatasets;
  vtkIdType CurrentMapId;

  boost::mutex Mutex;

  std::deque<MapData> Datasets;

  boost::shared_ptr<lcm::LCM> LCMHandle;

  boost::shared_ptr<boost::thread> Thread;

};

} // end namespace

//----------------------------------------------------------------------------
class vtkMapServerSource::vtkInternal
{
public:

  vtkInternal()
  {
    this->Listener = boost::shared_ptr<LCMListener>(new LCMListener);
  }

  ~vtkInternal()
  {
  }

  boost::shared_ptr<LCMListener> Listener;
};

//----------------------------------------------------------------------------
vtkStandardNewMacro(vtkMapServerSource);

//----------------------------------------------------------------------------
vtkMapServerSource::vtkMapServerSource()
{
  this->Internal = new vtkInternal;
  this->SetNumberOfInputPorts(0);
  this->SetNumberOfOutputPorts(1);
}

//----------------------------------------------------------------------------
vtkMapServerSource::~vtkMapServerSource()
{
  this->Stop();
  delete this->Internal;
}

//----------------------------------------------------------------------------
void vtkMapServerSource::Start()
{
  this->Internal->Listener->Start();
}

//----------------------------------------------------------------------------
void vtkMapServerSource::Stop()
{
  this->Internal->Listener->Stop();
}

//----------------------------------------------------------------------------
void vtkMapServerSource::Poll()
{
  if (this->Internal->Listener->CheckForNewData())
    {
    this->Modified();
    }
}

//-----------------------------------------------------------------------------
int vtkMapServerSource::GetNumberOfDatasets()
{
  return this->Internal->Listener->GetDatasets().size();
}

//-----------------------------------------------------------------------------
vtkIdType vtkMapServerSource::GetCurrentMapId()
{
  return this->Internal->Listener->GetCurrentMapId();
}

//-----------------------------------------------------------------------------
void vtkMapServerSource::GetDataForMapId(vtkIdType mapId, vtkPolyData* polyData)
{
  return this->Internal->Listener->GetDataForMapId(mapId, polyData);
}

//-----------------------------------------------------------------------------
vtkPolyData* vtkMapServerSource::GetDataset(int i)
{
  return this->Internal->Listener->GetDatasetForTime(i);
}

//-----------------------------------------------------------------------------
int vtkMapServerSource::RequestInformation(vtkInformation *request,
                                     vtkInformationVector **inputVector,
                                     vtkInformationVector *outputVector)
{
  vtkInformation *info = outputVector->GetInformationObject(0);

  printf("requst info\n");

  std::vector<double> timesteps = this->Internal->Listener->GetTimesteps();
  if (timesteps.size())
    {
    double timeRange[2] = {timesteps.front(), timesteps.back()};

    printf("time range: [%f, %f]\n", timeRange[0], timeRange[1]);

    info->Set(vtkStreamingDemandDrivenPipeline::TIME_STEPS(), &timesteps.front(), timesteps.size());
    info->Set(vtkStreamingDemandDrivenPipeline::TIME_RANGE(), timeRange, 2);
    }
  else
    {
    printf("no timesteps available\n");
    info->Remove(vtkStreamingDemandDrivenPipeline::TIME_STEPS());
    info->Remove(vtkStreamingDemandDrivenPipeline::TIME_RANGE());
    }

  return 1;
}

//----------------------------------------------------------------------------
int vtkMapServerSource::RequestData(
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **inputVector,
  vtkInformationVector *outputVector)
{
  printf("request data\n");

  vtkInformation *info = outputVector->GetInformationObject(0);
  vtkDataSet *output = vtkDataSet::SafeDownCast(info->Get(vtkDataObject::DATA_OBJECT()));

  int timestep = 0;
  if (info->Has(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEPS()))
    {
    double timeRequest = info->Get(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEPS())[0];
    timestep = static_cast<int>(floor(timeRequest+0.5));
    }

  vtkSmartPointer<vtkPolyData> polyData = this->Internal->Listener->GetDatasetForTime(timestep);
  if (polyData)
    {
    output->ShallowCopy(polyData);
    }
  else
    {
    printf("no data\n");
    }

  return 1;
}

//----------------------------------------------------------------------------
void vtkMapServerSource::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
}
<|endoftext|>


<commit_before>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of libdui.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** 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
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include "duilabelview.h"
#include "duilabelview_p.h"
#include "duilabelmodel.h"
#include "duilabel.h"
#include "duiviewcreator.h"

#include <QPainter>
#include <QTextDocument>
#include <QTextCursor>
#include <QFontMetrics>
#include <QPixmapCache>
#include <QAbstractTextDocumentLayout>
#include <QGraphicsSceneMouseEvent>
#include <QGraphicsSceneResizeEvent>

DuiLabelViewSimple::DuiLabelViewSimple(DuiLabelViewPrivate *viewPrivate) :
    viewPrivate(viewPrivate), preferredSize(-1, -1), dirty(true)
{
}

DuiLabelViewSimple::~DuiLabelViewSimple()
{
}

#ifdef __arm__
void DuiLabelViewSimple::drawContents(QPainter *painter, const QSizeF &size)
{
    Q_UNUSED(size);

    const DuiLabelModel *model = viewPrivate->model();
    const DuiLabelStyle *style = viewPrivate->style();
    QRectF paintingRect(viewPrivate->boundingRect().adjusted(style->paddingLeft(), style->paddingTop(), -style->paddingRight(), -style->paddingBottom()));
    QString textToRender = model->text();
    if (model->textElide() && textToRender.size() > 4) {
        QFontMetrics fm(viewPrivate->controller->font());
        textToRender = fm.elidedText(model->text(), Qt::ElideRight, paintingRect.width());
    }

    if (textToRender.isEmpty()) {
        return;
    }

    painter->setFont(viewPrivate->controller->font());
    painter->setPen(model->color().isValid() ? model->color() : style->color());
    painter->setLayoutDirection(model->textDirection());
    painter->drawText(paintingRect, viewPrivate->textOptions.alignment() | Qt::TextSingleLine, textToRender);
}

#else

void DuiLabelViewSimple::drawContents(QPainter *painter, const QSizeF &size)
{
    Q_UNUSED(size);

    painter->drawImage(textOffset, generateImage());
}

#endif

QPixmap DuiLabelViewSimple::generatePixmap()
{
    return QPixmap();
}

QImage DuiLabelViewSimple::generateImage()
{
    if(!dirty)
        return cachedImage;

    dirty = false;
    const DuiLabelModel *model = viewPrivate->model();
    const DuiLabelStyle *style = viewPrivate->style();
    QRectF paintingRect(viewPrivate->boundingRect().adjusted(style->paddingLeft(), style->paddingTop(), -style->paddingRight(), -style->paddingBottom()));
    QSizeF paintingRectSize = paintingRect.size();
    textOffset = paintingRect.topLeft().toPoint();
    QString textToRender = model->text();
    if (model->textElide() && textToRender.size() > 4) {
        QFontMetrics fm(viewPrivate->controller->font());
        textToRender = fm.elidedText(model->text(), Qt::ElideRight, paintingRect.width());
    }

    if (textToRender.isEmpty()) {
        return QImage();
    }

    if(cachedImage.size() != paintingRect.size().toSize())
    {
        cachedImage = QImage(paintingRect.size().toSize(), QImage::Format_ARGB32_Premultiplied);
    }

    QImage &image = cachedImage;

    if (!image.isNull()) {
        image.fill(0);
        QPainter painter(&image);
        painter.setRenderHint(QPainter::TextAntialiasing);
        painter.setFont(viewPrivate->controller->font());
        painter.setPen(model->color().isValid() ? model->color() : style->color());
        painter.setLayoutDirection(model->textDirection());

        painter.drawText(0, 0, paintingRectSize.width(), paintingRectSize.height(), viewPrivate->textOptions.alignment() | Qt::TextSingleLine, textToRender);
    }

    return image;
}

bool DuiLabelViewSimple::resizeEvent(QGraphicsSceneResizeEvent *event)
{
    // There is no way to specify sizeHint for a text without knowing possible width.
    // 1st phase, when Qt calls sizeHint, view will return approximate values for
    // minimum and preferred size. When resizeEvent comes, layout already knows
    // sizes of components, and here comes
    // 2nd phase, when we identify widget's height, based on width. Our height will
    // change and we don't want to occupy more space then need, so we have to call
    // updateGeometry, to tell layout to update sizeHint cache. This function
    // return true if such update is needed.

    QFontMetricsF fm(viewPrivate->controller->font());
    QRectF bR = fm.boundingRect(QRectF(QPoint(0, 0), event->newSize()), viewPrivate->textOptions.alignment(), viewPrivate->model()->text());
    if (bR.height() > fm.height()) {
        preferredSize = QSizeF(bR.width(), bR.height());
        return true;
    } else
        return false;
}

QSizeF DuiLabelViewSimple::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
{
    switch (which) {
    case Qt::MinimumSize: {
        QFontMetricsF fm(viewPrivate->controller->font());
        QRectF r(0, 0, constraint.width(), constraint.height());

        if (r.width() < 0) {
            r.setWidth(QWIDGETSIZE_MAX);
        }
        if (r.height() < 0) {
            r.setHeight(QWIDGETSIZE_MAX);
        }

        QRectF bR(fm.boundingRect(r, viewPrivate->textOptions.alignment() | Qt::TextSingleLine,
                                  viewPrivate->model()->text()));

        return QSizeF(fm.width(""), bR.height());
    }
    case Qt::PreferredSize: {
        qreal w = constraint.width();
        qreal h = constraint.height();
        if (w < 0) {
            w = QWIDGETSIZE_MAX;
        }
        if (h < 0) {
            h = QWIDGETSIZE_MAX;
        }
        if (preferredSize.width() >= 0 && preferredSize.width() < w)
            w = preferredSize.width();
        if (preferredSize.height() >= 0 && preferredSize.height() < h)
            h = preferredSize.height();

        QFontMetricsF fm(viewPrivate->controller->font());
        QRectF bR(fm.boundingRect(QRectF(0, 0, w, h), viewPrivate->textOptions.alignment() | Qt::TextSingleLine,
                                  viewPrivate->model()->text()));
        return bR.size().boundedTo(QSizeF(w, h));
    }
    case Qt::MaximumSize: {
        return QSizeF(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
    }
    default:
        qWarning("DuiLabel::sizeHint() don't know how to handle the value of 'which' ");
    }

    return QSizeF(0, 0);
}

void DuiLabelViewSimple::setupModel()
{
    viewPrivate->textOptions.setTextDirection(viewPrivate->model()->textDirection());
    viewPrivate->textOptions.setAlignment(viewPrivate->model()->alignment());
}

bool DuiLabelViewSimple::updateData(const QList<const char *>& modifications)
{
    const char *member = NULL;
    bool needUpdate = false;

    foreach(member, modifications) {
        if (member == DuiLabelModel::Text) {
            preferredSize = QSizeF(-1, -1);
            needUpdate = true;
        } else if (member == DuiLabelModel::WordWrap) {
            if (viewPrivate->model()->wordWrap()) {
                viewPrivate->textOptions.setWrapMode(QTextOption::WordWrap);
            } else {
                viewPrivate->textOptions.setWrapMode(QTextOption::ManualWrap);
            }
        } else if (member == DuiLabelModel::TextDirection) {
            viewPrivate->textOptions.setTextDirection(viewPrivate->model()->textDirection());
        } else if (member == DuiLabelModel::Alignment) {
            viewPrivate->textOptions.setAlignment(viewPrivate->model()->alignment());
        } else if (member == DuiLabelModel::UseModelFont || member == DuiLabelModel::Font) {
            needUpdate = true;
        }
    }
    return needUpdate;
}

bool DuiLabelViewSimple::isRich()
{
    return false;
}

void DuiLabelViewSimple::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    event->ignore(); //propagate link up to owner of label
}

void DuiLabelViewSimple::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
    Q_UNUSED(event);
}

void DuiLabelViewSimple::cancelEvent(DuiCancelEvent *event)
{
    Q_UNUSED(event);
}

void DuiLabelViewSimple::longPressEvent(QGraphicsSceneContextMenuEvent *event)
{
    Q_UNUSED(event);
}

void DuiLabelViewSimple::applyStyle()
{
}
<commit_msg>Fixes: NB#160550 DuiLabel::setText() does not work when using "" as a parameter.<commit_after>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of libdui.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** 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
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include "duilabelview.h"
#include "duilabelview_p.h"
#include "duilabelmodel.h"
#include "duilabel.h"
#include "duiviewcreator.h"

#include <QPainter>
#include <QTextDocument>
#include <QTextCursor>
#include <QFontMetrics>
#include <QPixmapCache>
#include <QAbstractTextDocumentLayout>
#include <QGraphicsSceneMouseEvent>
#include <QGraphicsSceneResizeEvent>

DuiLabelViewSimple::DuiLabelViewSimple(DuiLabelViewPrivate *viewPrivate) :
    viewPrivate(viewPrivate), preferredSize(-1, -1), dirty(true)
{
}

DuiLabelViewSimple::~DuiLabelViewSimple()
{
}

#ifdef __arm__
void DuiLabelViewSimple::drawContents(QPainter *painter, const QSizeF &size)
{
    Q_UNUSED(size);

    const DuiLabelModel *model = viewPrivate->model();
    const DuiLabelStyle *style = viewPrivate->style();
    QRectF paintingRect(viewPrivate->boundingRect().adjusted(style->paddingLeft(), style->paddingTop(), -style->paddingRight(), -style->paddingBottom()));
    QString textToRender = model->text();
    if (model->textElide() && textToRender.size() > 4) {
        QFontMetrics fm(viewPrivate->controller->font());
        textToRender = fm.elidedText(model->text(), Qt::ElideRight, paintingRect.width());
    }

    if (textToRender.isEmpty()) {
        return;
    }

    painter->setFont(viewPrivate->controller->font());
    painter->setPen(model->color().isValid() ? model->color() : style->color());
    painter->setLayoutDirection(model->textDirection());
    painter->drawText(paintingRect, viewPrivate->textOptions.alignment() | Qt::TextSingleLine, textToRender);
}

#else

void DuiLabelViewSimple::drawContents(QPainter *painter, const QSizeF &size)
{
    Q_UNUSED(size);

    painter->drawImage(textOffset, generateImage());
}

#endif

QPixmap DuiLabelViewSimple::generatePixmap()
{
    return QPixmap();
}

QImage DuiLabelViewSimple::generateImage()
{
    if(!dirty)
        return cachedImage;

    dirty = false;
    const DuiLabelModel *model = viewPrivate->model();
    const DuiLabelStyle *style = viewPrivate->style();
    QRectF paintingRect(viewPrivate->boundingRect().adjusted(style->paddingLeft(), style->paddingTop(), -style->paddingRight(), -style->paddingBottom()));
    QSizeF paintingRectSize = paintingRect.size();
    textOffset = paintingRect.topLeft().toPoint();
    QString textToRender = model->text();
    if (model->textElide() && textToRender.size() > 4) {
        QFontMetrics fm(viewPrivate->controller->font());
        textToRender = fm.elidedText(model->text(), Qt::ElideRight, paintingRect.width());
    }

    if (textToRender.isEmpty()) {
        cachedImage = QImage();
        return cachedImage;
    }

    if(cachedImage.size() != paintingRect.size().toSize())
    {
        cachedImage = QImage(paintingRect.size().toSize(), QImage::Format_ARGB32_Premultiplied);
    }

    QImage &image = cachedImage;

    if (!image.isNull()) {
        image.fill(0);
        QPainter painter(&image);
        painter.setRenderHint(QPainter::TextAntialiasing);
        painter.setFont(viewPrivate->controller->font());
        painter.setPen(model->color().isValid() ? model->color() : style->color());
        painter.setLayoutDirection(model->textDirection());

        painter.drawText(0, 0, paintingRectSize.width(), paintingRectSize.height(), viewPrivate->textOptions.alignment() | Qt::TextSingleLine, textToRender);
    }

    return image;
}

bool DuiLabelViewSimple::resizeEvent(QGraphicsSceneResizeEvent *event)
{
    // There is no way to specify sizeHint for a text without knowing possible width.
    // 1st phase, when Qt calls sizeHint, view will return approximate values for
    // minimum and preferred size. When resizeEvent comes, layout already knows
    // sizes of components, and here comes
    // 2nd phase, when we identify widget's height, based on width. Our height will
    // change and we don't want to occupy more space then need, so we have to call
    // updateGeometry, to tell layout to update sizeHint cache. This function
    // return true if such update is needed.

    QFontMetricsF fm(viewPrivate->controller->font());
    QRectF bR = fm.boundingRect(QRectF(QPoint(0, 0), event->newSize()), viewPrivate->textOptions.alignment(), viewPrivate->model()->text());
    if (bR.height() > fm.height()) {
        preferredSize = QSizeF(bR.width(), bR.height());
        return true;
    } else
        return false;
}

QSizeF DuiLabelViewSimple::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
{
    switch (which) {
    case Qt::MinimumSize: {
        QFontMetricsF fm(viewPrivate->controller->font());
        QRectF r(0, 0, constraint.width(), constraint.height());

        if (r.width() < 0) {
            r.setWidth(QWIDGETSIZE_MAX);
        }
        if (r.height() < 0) {
            r.setHeight(QWIDGETSIZE_MAX);
        }

        QRectF bR(fm.boundingRect(r, viewPrivate->textOptions.alignment() | Qt::TextSingleLine,
                                  viewPrivate->model()->text()));

        return QSizeF(fm.width(""), bR.height());
    }
    case Qt::PreferredSize: {
        qreal w = constraint.width();
        qreal h = constraint.height();
        if (w < 0) {
            w = QWIDGETSIZE_MAX;
        }
        if (h < 0) {
            h = QWIDGETSIZE_MAX;
        }
        if (preferredSize.width() >= 0 && preferredSize.width() < w)
            w = preferredSize.width();
        if (preferredSize.height() >= 0 && preferredSize.height() < h)
            h = preferredSize.height();

        QFontMetricsF fm(viewPrivate->controller->font());
        QRectF bR(fm.boundingRect(QRectF(0, 0, w, h), viewPrivate->textOptions.alignment() | Qt::TextSingleLine,
                                  viewPrivate->model()->text()));
        return bR.size().boundedTo(QSizeF(w, h));
    }
    case Qt::MaximumSize: {
        return QSizeF(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
    }
    default:
        qWarning("DuiLabel::sizeHint() don't know how to handle the value of 'which' ");
    }

    return QSizeF(0, 0);
}

void DuiLabelViewSimple::setupModel()
{
    viewPrivate->textOptions.setTextDirection(viewPrivate->model()->textDirection());
    viewPrivate->textOptions.setAlignment(viewPrivate->model()->alignment());
}

bool DuiLabelViewSimple::updateData(const QList<const char *>& modifications)
{
    const char *member = NULL;
    bool needUpdate = false;

    foreach(member, modifications) {
        if (member == DuiLabelModel::Text) {
            preferredSize = QSizeF(-1, -1);
            needUpdate = true;
        } else if (member == DuiLabelModel::WordWrap) {
            if (viewPrivate->model()->wordWrap()) {
                viewPrivate->textOptions.setWrapMode(QTextOption::WordWrap);
            } else {
                viewPrivate->textOptions.setWrapMode(QTextOption::ManualWrap);
            }
        } else if (member == DuiLabelModel::TextDirection) {
            viewPrivate->textOptions.setTextDirection(viewPrivate->model()->textDirection());
        } else if (member == DuiLabelModel::Alignment) {
            viewPrivate->textOptions.setAlignment(viewPrivate->model()->alignment());
        } else if (member == DuiLabelModel::UseModelFont || member == DuiLabelModel::Font) {
            needUpdate = true;
        }
    }
    return needUpdate;
}

bool DuiLabelViewSimple::isRich()
{
    return false;
}

void DuiLabelViewSimple::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    event->ignore(); //propagate link up to owner of label
}

void DuiLabelViewSimple::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
    Q_UNUSED(event);
}

void DuiLabelViewSimple::cancelEvent(DuiCancelEvent *event)
{
    Q_UNUSED(event);
}

void DuiLabelViewSimple::longPressEvent(QGraphicsSceneContextMenuEvent *event)
{
    Q_UNUSED(event);
}

void DuiLabelViewSimple::applyStyle()
{
}
<|endoftext|>


<commit_before>#include <cmdstan/stansummary_helper.hpp>
#include <stan/mcmc/chains.hpp>
#include <stan/io/ends_with.hpp>
#include <algorithm>
#include <fstream>
#include <iomanip>
#include <ios>
#include <iostream>
#include <vector>
#include <boost/algorithm/string.hpp>
#include <CLI11/CLI11.hpp>

/**
 * Compute summary statistics over HMC sampler output
 * read in from stan_csv files.
 * Command line options handled by CLI11 lib.
 *
 * @param argc Number of arguments
 * @param argv Arguments
 *
 * @return 0 for success,
 *         non-zero otherwise
 */
int main(int argc, const char *argv[]) {
  std::string usage = R"(Usage: stansummary [OPTIONS] stan_csv_file(s)
Report statistics for one or more Stan csv files from a HMC sampler run.
Example:  stansummary model_chain_1.csv model_chain_2.csv
Options:
  -a, --autocorr [n]          Display the chain autocorrelation for the n-th
                              input file, in addition to statistics.
  -c, --csv_filename [file]   Write statistics to a csv file.
  -h, --help                  Produce help message, then exit.
  -p, --percentiles [values]  Percentiles to report as ordered set of
                              comma-separated integers from (1,99), inclusive.
                              Default is 5,50,95.
  -s, --sig_figs [n]          Significant figures reported. Default is 2.
                              Must be an integer from (1, 18), inclusive.
)";
  if (argc < 2) {
    std::cout << usage << std::endl;
    return -1;
  }

  // Command-line arguments
  int sig_figs = 2;
  int autocorr_idx;
  std::string csv_filename;
  std::string percentiles_spec = "5,50,95";
  std::vector<std::string> filenames;

  CLI::App app{"Allowed options"};
  app.add_option("--sig_figs,-s", sig_figs, "Significant figures, default 2.",
                 true)
      ->check(CLI::Range(1, 18));
  app.add_option("--autocorr,-a", autocorr_idx,
                 "Display the chain autocorrelation.", true)
      ->check(CLI::PositiveNumber);
  app.add_option("--csv_filename,-c", csv_filename,
                 "Write statistics to a csv.", true)
      ->check(CLI::NonexistentPath);
  app.add_option("--percentiles,-p", percentiles_spec, "Percentiles to report.",
                 true);
  app.add_option("input_files", filenames, "Sampler csv files.", true)
      ->required()
      ->check(CLI::ExistingFile);

  try {
    CLI11_PARSE(app, argc, argv);
  } catch (const CLI::ParseError &e) {
    std::cout << e.get_exit_code();
    return app.exit(e);
  }

  // Check options semantic consistency
  if (app.count("--autocorr") && autocorr_idx > filenames.size()) {
    std::cout << "Option --autocorr: " << autocorr_idx
              << " not a valid chain id." << std::endl;
    return -1;
  }
  std::vector<std::string> percentiles;
  boost::algorithm::trim(percentiles_spec);
  boost::algorithm::split(percentiles, percentiles_spec, boost::is_any_of(", "),
                          boost::token_compress_on);
  Eigen::VectorXd probs;
  try {
    probs = percentiles_to_probs(percentiles);
  } catch (const std::invalid_argument &e) {
    std::cout << "Option --percentiles " << percentiles_spec << ": " << e.what()
              << std::endl;
    return -1;
  }
  if (app.count("--csv_filename")) {
    if (FILE *file = fopen(csv_filename.c_str(), "w")) {
      fclose(file);
    } else {
      std::cout << "Cannot save to csv_filename: " << csv_filename << "."
                << std::endl;
      return -1;
    }
  }
  for (int i = 0; i < filenames.size(); ++i) {
    std::ifstream infile;
    infile.open(filenames[i].c_str());
    if (infile.good()) {
      infile.close();
    } else {
      std::cout << "Cannot read input csv file: " << filenames[i] << "."
                << std::endl;
      return -1;
    }
  }

  try {
    // Parse csv files into sample, metadata
    stan::io::stan_csv_metadata metadata;
    Eigen::VectorXd warmup_times(filenames.size());
    Eigen::VectorXd sampling_times(filenames.size());
    Eigen::VectorXi thin(filenames.size());

    // check for stan csv file parse errors written to output stream
    std::stringstream cout_ss;
    cout_ss.str("");
    stan::mcmc::chains<> chains = parse_csv_files(
        filenames, metadata, warmup_times, sampling_times, thin, &cout_ss);
    if (cout_ss.str() != "")
      throw std::invalid_argument(cout_ss.str());

    // Get column headers for sampler, model params
    size_t max_name_length = 0;
    size_t num_sampler_params = -1;  // don't count name 'lp__'
    for (int i = 0; i < chains.num_params(); ++i) {
      if (chains.param_name(i).length() > max_name_length)
        max_name_length = chains.param_name(i).length();
      if (stan::io::ends_with("__", chains.param_name(i)))
        num_sampler_params++;
    }
    size_t model_params_offset = num_sampler_params + 1;
    size_t num_model_params = chains.num_params() - model_params_offset;

    std::vector<std::string> header = get_header(percentiles);

    // Compute statistics for sampler and model params
    Eigen::MatrixXd lp_param(1, header.size());
    Eigen::MatrixXd sampler_params(num_sampler_params, header.size());
    Eigen::MatrixXd model_params(num_model_params, header.size());

    get_stats(chains, warmup_times, sampling_times, probs, 0, lp_param);
    get_stats(chains, warmup_times, sampling_times, probs, 1, sampler_params);
    get_stats(chains, warmup_times, sampling_times, probs, model_params_offset,
              model_params);

    // Console output formatting
    Eigen::VectorXi column_sig_figs(header.size());
    Eigen::Matrix<std::ios_base::fmtflags, Eigen::Dynamic, 1> sampler_formats(
        header.size());
    Eigen::VectorXi sampler_widths(header.size());
    sampler_widths = calculate_column_widths(sampler_params, header, sig_figs,
                                             sampler_formats);

    Eigen::Matrix<std::ios_base::fmtflags, Eigen::Dynamic, 1> model_formats(
        header.size());
    Eigen::VectorXi model_widths(header.size());
    model_widths = calculate_column_widths(model_params, header, sig_figs,
                                           model_formats);

    Eigen::VectorXi column_widths(header.size());
    for (size_t i = 0; i < header.size(); ++i)
      column_widths[i] = sampler_widths[i] > model_widths[i] ? sampler_widths[i]
                                                             : model_widths[i];

    // Print to console
    write_timing(chains, metadata, warmup_times, sampling_times, thin, "",
                 &std::cout);
    std::cout << std::endl;

    write_header(header, column_widths, max_name_length, false, &std::cout);
    std::cout << std::endl;
    write_params(chains, lp_param, column_widths, model_formats,
                 max_name_length, sig_figs, 0, false, &std::cout);
    write_params(chains, sampler_params, column_widths, sampler_formats,
                 max_name_length, sig_figs, 1, false, &std::cout);
    std::cout << std::endl;
    write_params(chains, model_params, column_widths, model_formats,
                 max_name_length, sig_figs, model_params_offset, false,
                 &std::cout);
    std::cout << std::endl;
    write_sampler_info(metadata, "", &std::cout);

    if (app.count("--autocorr")) {
      autocorrelation(chains, metadata, autocorr_idx, max_name_length);
      std::cout << std::endl;
    }

    // Write to csv file (optional)
    if (app.count("--csv_filename")) {
      std::ofstream csv_file(csv_filename.c_str(), std::ios_base::app);
      csv_file << std::setprecision(app.count("--sig_figs") ? sig_figs : 6);

      write_header(header, column_widths, max_name_length, true, &csv_file);
      write_params(chains, lp_param, column_widths, model_formats,
                   max_name_length, sig_figs, 0, true, &csv_file);
      write_params(chains, sampler_params, column_widths, sampler_formats,
                   max_name_length, sig_figs, 1, true, &csv_file);
      write_params(chains, model_params, column_widths, model_formats,
                   max_name_length, sig_figs, model_params_offset, true,
                   &csv_file);

      write_timing(chains, metadata, warmup_times, sampling_times, thin, "# ",
                   &csv_file);
      write_sampler_info(metadata, "# ", &csv_file);
      csv_file.close();
    }
  } catch (const std::invalid_argument &e) {
    std::cout << "Error during processing. " << e.what() << std::endl;
    return -1;
  }

  return 0;
}
<commit_msg>Updated stansummary to not quit on non-fatal error (#971)<commit_after>#include <cmdstan/stansummary_helper.hpp>
#include <stan/mcmc/chains.hpp>
#include <stan/io/ends_with.hpp>
#include <algorithm>
#include <fstream>
#include <iomanip>
#include <ios>
#include <iostream>
#include <vector>
#include <boost/algorithm/string.hpp>
#include <CLI11/CLI11.hpp>

/**
 * Compute summary statistics over HMC sampler output
 * read in from stan_csv files.
 * Command line options handled by CLI11 lib.
 *
 * @param argc Number of arguments
 * @param argv Arguments
 *
 * @return 0 for success,
 *         non-zero otherwise
 */
int main(int argc, const char *argv[]) {
  std::string usage = R"(Usage: stansummary [OPTIONS] stan_csv_file(s)
Report statistics for one or more Stan csv files from a HMC sampler run.
Example:  stansummary model_chain_1.csv model_chain_2.csv
Options:
  -a, --autocorr [n]          Display the chain autocorrelation for the n-th
                              input file, in addition to statistics.
  -c, --csv_filename [file]   Write statistics to a csv file.
  -h, --help                  Produce help message, then exit.
  -p, --percentiles [values]  Percentiles to report as ordered set of
                              comma-separated integers from (1,99), inclusive.
                              Default is 5,50,95.
  -s, --sig_figs [n]          Significant figures reported. Default is 2.
                              Must be an integer from (1, 18), inclusive.
)";
  if (argc < 2) {
    std::cout << usage << std::endl;
    return -1;
  }

  // Command-line arguments
  int sig_figs = 2;
  int autocorr_idx;
  std::string csv_filename;
  std::string percentiles_spec = "5,50,95";
  std::vector<std::string> filenames;

  CLI::App app{"Allowed options"};
  app.add_option("--sig_figs,-s", sig_figs, "Significant figures, default 2.",
                 true)
      ->check(CLI::Range(1, 18));
  app.add_option("--autocorr,-a", autocorr_idx,
                 "Display the chain autocorrelation.", true)
      ->check(CLI::PositiveNumber);
  app.add_option("--csv_filename,-c", csv_filename,
                 "Write statistics to a csv.", true)
      ->check(CLI::NonexistentPath);
  app.add_option("--percentiles,-p", percentiles_spec, "Percentiles to report.",
                 true);
  app.add_option("input_files", filenames, "Sampler csv files.", true)
      ->required()
      ->check(CLI::ExistingFile);

  try {
    CLI11_PARSE(app, argc, argv);
  } catch (const CLI::ParseError &e) {
    std::cout << e.get_exit_code();
    return app.exit(e);
  }

  // Check options semantic consistency
  if (app.count("--autocorr") && autocorr_idx > filenames.size()) {
    std::cout << "Option --autocorr: " << autocorr_idx
              << " not a valid chain id." << std::endl;
    return -1;
  }
  std::vector<std::string> percentiles;
  boost::algorithm::trim(percentiles_spec);
  boost::algorithm::split(percentiles, percentiles_spec, boost::is_any_of(", "),
                          boost::token_compress_on);
  Eigen::VectorXd probs;
  try {
    probs = percentiles_to_probs(percentiles);
  } catch (const std::invalid_argument &e) {
    std::cout << "Option --percentiles " << percentiles_spec << ": " << e.what()
              << std::endl;
    return -1;
  }
  if (app.count("--csv_filename")) {
    if (FILE *file = fopen(csv_filename.c_str(), "w")) {
      fclose(file);
    } else {
      std::cout << "Cannot save to csv_filename: " << csv_filename << "."
                << std::endl;
      return -1;
    }
  }
  for (int i = 0; i < filenames.size(); ++i) {
    std::ifstream infile;
    infile.open(filenames[i].c_str());
    if (infile.good()) {
      infile.close();
    } else {
      std::cout << "Cannot read input csv file: " << filenames[i] << "."
                << std::endl;
      return -1;
    }
  }

  try {
    // Parse csv files into sample, metadata
    stan::io::stan_csv_metadata metadata;
    Eigen::VectorXd warmup_times(filenames.size());
    Eigen::VectorXd sampling_times(filenames.size());
    Eigen::VectorXi thin(filenames.size());

    // check for stan csv file parse errors written to output stream
    std::stringstream cout_ss;
    stan::mcmc::chains<> chains = parse_csv_files
      (filenames, metadata, warmup_times, sampling_times, thin, &std::cout);

    // Get column headers for sampler, model params
    size_t max_name_length = 0;
    size_t num_sampler_params = -1;  // don't count name 'lp__'
    for (int i = 0; i < chains.num_params(); ++i) {
      if (chains.param_name(i).length() > max_name_length)
        max_name_length = chains.param_name(i).length();
      if (stan::io::ends_with("__", chains.param_name(i)))
        num_sampler_params++;
    }
    size_t model_params_offset = num_sampler_params + 1;
    size_t num_model_params = chains.num_params() - model_params_offset;

    std::vector<std::string> header = get_header(percentiles);

    // Compute statistics for sampler and model params
    Eigen::MatrixXd lp_param(1, header.size());
    Eigen::MatrixXd sampler_params(num_sampler_params, header.size());
    Eigen::MatrixXd model_params(num_model_params, header.size());

    get_stats(chains, warmup_times, sampling_times, probs, 0, lp_param);
    get_stats(chains, warmup_times, sampling_times, probs, 1, sampler_params);
    get_stats(chains, warmup_times, sampling_times, probs, model_params_offset,
              model_params);

    // Console output formatting
    Eigen::VectorXi column_sig_figs(header.size());
    Eigen::Matrix<std::ios_base::fmtflags, Eigen::Dynamic, 1> sampler_formats(
        header.size());
    Eigen::VectorXi sampler_widths(header.size());
    sampler_widths = calculate_column_widths(sampler_params, header, sig_figs,
                                             sampler_formats);

    Eigen::Matrix<std::ios_base::fmtflags, Eigen::Dynamic, 1> model_formats(
        header.size());
    Eigen::VectorXi model_widths(header.size());
    model_widths = calculate_column_widths(model_params, header, sig_figs,
                                           model_formats);

    Eigen::VectorXi column_widths(header.size());
    for (size_t i = 0; i < header.size(); ++i)
      column_widths[i] = sampler_widths[i] > model_widths[i] ? sampler_widths[i]
                                                             : model_widths[i];

    // Print to console
    write_timing(chains, metadata, warmup_times, sampling_times, thin, "",
                 &std::cout);
    std::cout << std::endl;

    write_header(header, column_widths, max_name_length, false, &std::cout);
    std::cout << std::endl;
    write_params(chains, lp_param, column_widths, model_formats,
                 max_name_length, sig_figs, 0, false, &std::cout);
    write_params(chains, sampler_params, column_widths, sampler_formats,
                 max_name_length, sig_figs, 1, false, &std::cout);
    std::cout << std::endl;
    write_params(chains, model_params, column_widths, model_formats,
                 max_name_length, sig_figs, model_params_offset, false,
                 &std::cout);
    std::cout << std::endl;
    write_sampler_info(metadata, "", &std::cout);

    if (app.count("--autocorr")) {
      autocorrelation(chains, metadata, autocorr_idx, max_name_length);
      std::cout << std::endl;
    }

    // Write to csv file (optional)
    if (app.count("--csv_filename")) {
      std::ofstream csv_file(csv_filename.c_str(), std::ios_base::app);
      csv_file << std::setprecision(app.count("--sig_figs") ? sig_figs : 6);

      write_header(header, column_widths, max_name_length, true, &csv_file);
      write_params(chains, lp_param, column_widths, model_formats,
                   max_name_length, sig_figs, 0, true, &csv_file);
      write_params(chains, sampler_params, column_widths, sampler_formats,
                   max_name_length, sig_figs, 1, true, &csv_file);
      write_params(chains, model_params, column_widths, model_formats,
                   max_name_length, sig_figs, model_params_offset, true,
                   &csv_file);

      write_timing(chains, metadata, warmup_times, sampling_times, thin, "# ",
                   &csv_file);
      write_sampler_info(metadata, "# ", &csv_file);
      csv_file.close();
    }
  } catch (const std::invalid_argument &e) {
    std::cout << "Error during processing. " << e.what() << std::endl;
    return -1;
  }

  return 0;
}
<|endoftext|>


<commit_before>//===----------------------------------------------------------------------===//
//
//                         Peloton
//
// aggregation.cpp
//
// Identification: src/codegen/aggregation.cpp
//
// Copyright (c) 2015-17, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include "codegen/aggregation.h"

namespace peloton {
namespace codegen {

//===----------------------------------------------------------------------===//
// Setup the aggregation storage format given the aggregates the caller wants to
// store.
//===----------------------------------------------------------------------===//
void Aggregation::Setup(
    CodeGen &codegen,
    const std::vector<planner::AggregatePlan::AggTerm> &aggregates) {
  // Collect the types so we can configure the updateable storage's format
  bool needs_group_count = false;
  bool tracks_group_count = false;
  for (uint32_t i = 0; i < aggregates.size(); i++) {
    const auto agg_term = aggregates[i];
    // Defense > Offense ?
    PL_ASSERT(agg_term.agg_ai.type != type::Type::TypeId::INVALID);

    needs_group_count |= agg_term.aggtype == ExpressionType::AGGREGATE_AVG;
    tracks_group_count |=
        agg_term.aggtype == ExpressionType::AGGREGATE_COUNT_STAR;
  }

  // Add the count(*) aggregate first, if we need to
  if (tracks_group_count || needs_group_count) {
    uint32_t storage_pos = storage_.AddType(type::Type::TypeId::BIGINT);
    AggregateInfo count_agg{
        ExpressionType::AGGREGATE_COUNT_STAR, type::Type::TypeId::BIGINT,
        std::numeric_limits<uint32_t>::max(), storage_pos, true};
    aggregate_infos_.push_back(count_agg);
  }

  // Add the rest
  for (uint32_t source_index = 0; source_index < aggregates.size();
       source_index++) {
    const auto agg_term = aggregates[source_index];
    switch (agg_term.aggtype) {
      case ExpressionType::AGGREGATE_COUNT: {
        // We're counting instances ... use BIGINT for the count
        auto count_type = type::Type::TypeId::BIGINT;
        uint32_t storage_pos = storage_.AddType(count_type);
        AggregateInfo aggregate_info{agg_term.aggtype, count_type, source_index,
                                     storage_pos, false};
        aggregate_infos_.push_back(aggregate_info);
        break;
      }
      case ExpressionType::AGGREGATE_SUM:
      case ExpressionType::AGGREGATE_MIN:
      case ExpressionType::AGGREGATE_MAX: {
        // Regular
        type::Type::TypeId value_type = agg_term.expression->GetValueType();
        uint32_t storage_pos = storage_.AddType(value_type);
        AggregateInfo aggregate_info{agg_term.aggtype, value_type, source_index,
                                     storage_pos, false};
        aggregate_infos_.push_back(aggregate_info);
        break;
      }
      case ExpressionType::AGGREGATE_AVG: {
        // We decompose averages (i.e., AVG(c)) into COUNT(c) and SUM(c)

        // SUM() - the type must match the type of the expression
        PL_ASSERT(agg_term.expression != nullptr);
        type::Type::TypeId sum_type = agg_term.expression->GetValueType();
        uint32_t sum_storage_pos = storage_.AddType(sum_type);
        AggregateInfo sum_agg{ExpressionType::AGGREGATE_SUM, sum_type,
                              source_index, sum_storage_pos, true};
        aggregate_infos_.push_back(sum_agg);

        // COUNT() - can use big integer since we're counting instances
        uint32_t count_storage_pos =
            storage_.AddType(type::Type::TypeId::BIGINT);
        AggregateInfo count_agg{ExpressionType::AGGREGATE_COUNT,
                                type::Type::TypeId::BIGINT, source_index,
                                count_storage_pos, true};
        aggregate_infos_.push_back(count_agg);

        // AVG()
        // TODO: Is this always double?
        AggregateInfo avg_agg{agg_term.aggtype, type::Type::TypeId::DECIMAL,
                              source_index,
                              std::numeric_limits<uint32_t>::max(), false};
        aggregate_infos_.push_back(avg_agg);
        break;
      }
      case ExpressionType::AGGREGATE_COUNT_STAR: {
        // count(*)'s are always stored in the first slot, reference that here
        // NOTE: We've already added the count(*) to the storage format above,
        //       don't do it here
        PL_ASSERT(tracks_group_count);
        AggregateInfo count_agg{agg_term.aggtype, type::Type::TypeId::BIGINT,
                                source_index, 0, false};
        aggregate_infos_.push_back(count_agg);
        break;
      }
      default: {
        std::string message = "Ran into unexpected aggregate type [" +
                              ExpressionTypeToString(agg_term.aggtype) +
                              "] when setting up aggregation";
        LOG_ERROR("%s", message.c_str());
        throw Exception{message};
      }
    }
  }

  // Finalize the storage format
  storage_.Finalize(codegen);
}

// Create the initial values of all aggregates based on the the provided values
void Aggregation::CreateInitialValues(
    CodeGen &codegen, llvm::Value *storage_space,
    const std::vector<codegen::Value> &initial) const {
  // TODO: Handle null
  for (size_t i = 0; i < aggregate_infos_.size(); i++) {
    const auto &aggregate_info = aggregate_infos_[i];
    switch (aggregate_info.aggregate_type) {
      case ExpressionType::AGGREGATE_SUM:
      case ExpressionType::AGGREGATE_MIN:
      case ExpressionType::AGGREGATE_MAX: {
        // For the above aggregations, the initial value is the attribute value
        uint32_t val_source = aggregate_info.source_index;
        storage_.SetValueAt(codegen, storage_space,
                            aggregate_info.storage_index, initial[val_source]);
        break;
      }
      case ExpressionType::AGGREGATE_COUNT:
      case ExpressionType::AGGREGATE_COUNT_STAR: {
        // TODO: Count(col) needs to check for null values
        // This aggregate should be moved to the front of the storage area
        storage_.SetValueAt(
            codegen, storage_space, aggregate_info.storage_index,
            codegen::Value{type::Type::TypeId::BIGINT, codegen.Const64(1)});
        break;
      }
      case ExpressionType::AGGREGATE_AVG: {
        // AVG() aggregates aren't physically stored
        break;
      }
      default: {
        std::string message =
            "Ran into unexpected aggregate type [" +
            ExpressionTypeToString(aggregate_info.aggregate_type) +
            "] when creating initial aggregate values";
        LOG_ERROR("%s", message.c_str());
        throw Exception{message};
      }
    }
  }
}

//===----------------------------------------------------------------------===//
// Advance each of the aggregates stored in the provided storage space. We
// use the storage format class to determine the location of each of the
// aggregates. Then, depending on the type of aggregation, we advance of their
// values, populating the provided next_vals vector with their new values.
//===----------------------------------------------------------------------===//
void Aggregation::AdvanceValues(
    CodeGen &codegen, llvm::Value *storage_space,
    const std::vector<codegen::Value> &next_vals) const {
  // TODO: Handle null
  for (const auto &aggregate_info : aggregate_infos_) {
    // Loop over all aggregates, advancing each
    uint32_t source = aggregate_info.source_index;
    codegen::Value next;
    switch (aggregate_info.aggregate_type) {
      case ExpressionType::AGGREGATE_SUM: {
        PL_ASSERT(source < std::numeric_limits<uint32_t>::max());
        auto curr = storage_.GetValueAt(codegen, storage_space,
                                        aggregate_info.storage_index);
        next = curr.Add(codegen, next_vals[source]);
        break;
      }
      case ExpressionType::AGGREGATE_MIN: {
        PL_ASSERT(source < std::numeric_limits<uint32_t>::max());
        auto curr = storage_.GetValueAt(codegen, storage_space,
                                        aggregate_info.storage_index);
        next = curr.Min(codegen, next_vals[source]);
        break;
      }
      case ExpressionType::AGGREGATE_MAX: {
        PL_ASSERT(source < std::numeric_limits<uint32_t>::max());
        auto curr = storage_.GetValueAt(codegen, storage_space,
                                        aggregate_info.storage_index);
        next = curr.Max(codegen, next_vals[source]);
        break;
      }
      case ExpressionType::AGGREGATE_COUNT: {
        auto curr = storage_.GetValueAt(codegen, storage_space,
                                        aggregate_info.storage_index);
        next = curr.Add(codegen, codegen::Value{type::Type::TypeId::BIGINT,
                                                codegen.Const64(1)});
        break;
      }
      case ExpressionType::AGGREGATE_COUNT_STAR: {
        // COUNT(*) is always stored first with a source equal to INT_MAX. All
        // other COUNT(*)'s refer to that one.
        if (source != std::numeric_limits<uint32_t>::max()) {
          continue;
        }
        auto curr = storage_.GetValueAt(codegen, storage_space,
                                        aggregate_info.storage_index);
        next = curr.Add(codegen, codegen::Value{type::Type::TypeId::BIGINT,
                                                codegen.Const64(1)});
        break;
      }
      case ExpressionType::AGGREGATE_AVG: {
        // AVG() aggregates aren't physically stored
        continue;
      }
      default: {
        std::string message =
            "Ran into unexpected aggregate type [" +
            ExpressionTypeToString(aggregate_info.aggregate_type) +
            "] when advancing aggregates";
        LOG_ERROR("%s", message.c_str());
        throw Exception{message};
      }
    }

    // StoreValue the next value in the appropriate slot
    PL_ASSERT(next.GetType() != type::Type::TypeId::INVALID);
    storage_.SetValueAt(codegen, storage_space, aggregate_info.storage_index,
                        next);
  }
}

//===----------------------------------------------------------------------===//
// This function will finalize the aggregates stored in the provided storage
// space.  Finalization essentially means computing the final values of the
// aggregates. This is only really necessary for averages. Either way, we
// populate the final_vals vector with the final values of all the aggregates.
//===----------------------------------------------------------------------===//
void Aggregation::FinalizeValues(
    CodeGen &codegen, llvm::Value *storage_space,
    std::vector<codegen::Value> &final_vals) const {
  // Collect all final values into this map. We need this because some
  // aggregates are derived from other component aggregates.
  std::map<std::pair<uint32_t, ExpressionType>, codegen::Value> vals;

  for (const auto &aggregate_info : aggregate_infos_) {
    uint32_t source = aggregate_info.source_index;
    ExpressionType agg_type = aggregate_info.aggregate_type;
    switch (agg_type) {
      case ExpressionType::AGGREGATE_COUNT:
      case ExpressionType::AGGREGATE_SUM:
      case ExpressionType::AGGREGATE_MIN:
      case ExpressionType::AGGREGATE_MAX: {
        codegen::Value final_val = storage_.GetValueAt(
            codegen, storage_space, aggregate_info.storage_index);
        vals[std::make_pair(source, agg_type)] = final_val;
        if (!aggregate_info.is_internal) {
          final_vals.push_back(final_val);
        }
        break;
      }
      case ExpressionType::AGGREGATE_AVG: {
        // Find the sum and count for this aggregate
        codegen::Value sum =
            vals[std::make_pair(source, ExpressionType::AGGREGATE_SUM)];
        codegen::Value count =
            vals[std::make_pair(source, ExpressionType::AGGREGATE_COUNT)];
        // TODO: Check if count is zero
        codegen::Value final_val = sum.Div(codegen, count);
        vals[std::make_pair(source, agg_type)] = final_val;
        final_vals.push_back(final_val);
        break;
      }
      case ExpressionType::AGGREGATE_COUNT_STAR: {
        if (source != std::numeric_limits<uint32_t>::max()) {
          PL_ASSERT(!aggregate_info.is_internal);
          uint32_t count_source = std::numeric_limits<uint32_t>::max();
          final_vals.push_back(vals[std::make_pair(count_source, agg_type)]);
        } else {
          PL_ASSERT(aggregate_info.is_internal);
          codegen::Value final_val = storage_.GetValueAt(
              codegen, storage_space, aggregate_info.storage_index);
          vals[std::make_pair(source, agg_type)] = final_val;
        }
        break;
      }
      default: {
        std::string message = "Ran into unexpected aggregate type [" +
                              ExpressionTypeToString(agg_type) +
                              "] when finalizing aggregation";
        LOG_ERROR("%s", message.c_str());
        throw Exception{message};
      }
    }
  }
}

}  // namespace codegen
}  // namespace peloton
<commit_msg>Cleaned up<commit_after>//===----------------------------------------------------------------------===//
//
//                         Peloton
//
// aggregation.cpp
//
// Identification: src/codegen/aggregation.cpp
//
// Copyright (c) 2015-17, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include "codegen/aggregation.h"

namespace peloton {
namespace codegen {

//===----------------------------------------------------------------------===//
// Setup the aggregation storage format given the aggregates the caller wants to
// store.
//===----------------------------------------------------------------------===//
void Aggregation::Setup(
    CodeGen &codegen,
    const std::vector<planner::AggregatePlan::AggTerm> &aggregates) {
  // Collect the types so we can configure the updateable storage's format
  bool needs_group_count = false;
  bool tracks_group_count = false;
  for (uint32_t i = 0; i < aggregates.size(); i++) {
    const auto agg_term = aggregates[i];
    // Defense > Offense ?
    PL_ASSERT(agg_term.agg_ai.type != type::Type::TypeId::INVALID);

    needs_group_count |= agg_term.aggtype == ExpressionType::AGGREGATE_AVG;
    tracks_group_count |=
        agg_term.aggtype == ExpressionType::AGGREGATE_COUNT_STAR;
  }

  // Add the count(*) aggregate first, if we need to
  if (tracks_group_count || needs_group_count) {
    uint32_t storage_pos = storage_.AddType(type::Type::TypeId::BIGINT);
    AggregateInfo count_agg{
        ExpressionType::AGGREGATE_COUNT_STAR, type::Type::TypeId::BIGINT,
        std::numeric_limits<uint32_t>::max(), storage_pos, true};
    aggregate_infos_.push_back(count_agg);
  }

  // Add the rest
  for (uint32_t source_idx = 0; source_idx < aggregates.size(); source_idx++) {
    const auto agg_term = aggregates[source_idx];
    switch (agg_term.aggtype) {
      case ExpressionType::AGGREGATE_COUNT: {
        // We're counting instances ... use BIGINT for the count
        const auto count_type = type::Type::TypeId::BIGINT;
        uint32_t storage_pos = storage_.AddType(count_type);
        AggregateInfo aggregate_info{agg_term.aggtype, count_type, source_idx,
                                     storage_pos, false};
        aggregate_infos_.push_back(aggregate_info);
        break;
      }
      case ExpressionType::AGGREGATE_SUM:
      case ExpressionType::AGGREGATE_MIN:
      case ExpressionType::AGGREGATE_MAX: {
        // Regular
        const auto value_type = agg_term.expression->GetValueType();
        uint32_t storage_pos = storage_.AddType(value_type);
        AggregateInfo aggregate_info{agg_term.aggtype, value_type, source_idx,
                                     storage_pos, false};
        aggregate_infos_.push_back(aggregate_info);
        break;
      }
      case ExpressionType::AGGREGATE_AVG: {
        // We decompose averages (i.e., AVG(c)) into COUNT(c) and SUM(c)

        // SUM() - the type must match the type of the expression
        PL_ASSERT(agg_term.expression != nullptr);
        const auto sum_type = agg_term.expression->GetValueType();
        uint32_t sum_storage_pos = storage_.AddType(sum_type);
        AggregateInfo sum_agg{ExpressionType::AGGREGATE_SUM, sum_type,
                              source_idx, sum_storage_pos, true};
        aggregate_infos_.push_back(sum_agg);

        // COUNT() - can use big integer since we're counting instances
        uint32_t count_storage_pos =
            storage_.AddType(type::Type::TypeId::BIGINT);
        AggregateInfo count_agg{ExpressionType::AGGREGATE_COUNT,
                                type::Type::TypeId::BIGINT, source_idx,
                                count_storage_pos, true};
        aggregate_infos_.push_back(count_agg);

        // AVG()
        // TODO: Is this always double?
        AggregateInfo avg_agg{agg_term.aggtype, type::Type::TypeId::DECIMAL,
                              source_idx, std::numeric_limits<uint32_t>::max(),
                              false};
        aggregate_infos_.push_back(avg_agg);
        break;
      }
      case ExpressionType::AGGREGATE_COUNT_STAR: {
        // count(*)'s are always stored in the first slot, reference that here
        // NOTE: We've already added the count(*) to the storage format above,
        //       don't do it here
        PL_ASSERT(tracks_group_count);
        AggregateInfo count_agg{agg_term.aggtype, type::Type::TypeId::BIGINT,
                                source_idx, 0, false};
        aggregate_infos_.push_back(count_agg);
        break;
      }
      default: {
        std::string message = StringUtil::Format(
            "Unexpected aggregate type [%s] when preparing aggregator",
            ExpressionTypeToString(agg_term.aggtype));
        LOG_ERROR("%s", message.c_str());
        throw Exception{EXCEPTION_TYPE_UNKNOWN_TYPE, message};
      }
    }
  }

  // Finalize the storage format
  storage_.Finalize(codegen);
}

// Create the initial values of all aggregates based on the the provided values
void Aggregation::CreateInitialValues(
    CodeGen &codegen, llvm::Value *storage_space,
    const std::vector<codegen::Value> &initial) const {
  // TODO: Handle null
  for (size_t i = 0; i < aggregate_infos_.size(); i++) {
    const auto &aggregate_info = aggregate_infos_[i];
    switch (aggregate_info.aggregate_type) {
      case ExpressionType::AGGREGATE_SUM:
      case ExpressionType::AGGREGATE_MIN:
      case ExpressionType::AGGREGATE_MAX: {
        // For the above aggregations, the initial value is the attribute value
        uint32_t val_source = aggregate_info.source_index;
        storage_.SetValueAt(codegen, storage_space,
                            aggregate_info.storage_index, initial[val_source]);
        break;
      }
      case ExpressionType::AGGREGATE_COUNT:
      case ExpressionType::AGGREGATE_COUNT_STAR: {
        // TODO: Count(col) needs to check for null values
        // This aggregate should be moved to the front of the storage area
        storage_.SetValueAt(
            codegen, storage_space, aggregate_info.storage_index,
            codegen::Value{type::Type::TypeId::BIGINT, codegen.Const64(1)});
        break;
      }
      case ExpressionType::AGGREGATE_AVG: {
        // AVG() aggregates aren't physically stored
        break;
      }
      default: {
        std::string message = StringUtil::Format(
            "Unexpected aggregate type [%s] when creating initial values",
            ExpressionTypeToString(aggregate_info.aggregate_type));
        LOG_ERROR("%s", message.c_str());
        throw Exception{EXCEPTION_TYPE_UNKNOWN_TYPE, message};
      }
    }
  }
}

//===----------------------------------------------------------------------===//
// Advance each of the aggregates stored in the provided storage space. We
// use the storage format class to determine the location of each of the
// aggregates. Then, depending on the type of aggregation, we advance of their
// values, populating the provided next_vals vector with their new values.
//===----------------------------------------------------------------------===//
void Aggregation::AdvanceValues(
    CodeGen &codegen, llvm::Value *storage_space,
    const std::vector<codegen::Value> &next_vals) const {
  // TODO: Handle null
  for (const auto &aggregate_info : aggregate_infos_) {
    // Loop over all aggregates, advancing each
    uint32_t source = aggregate_info.source_index;
    codegen::Value next;
    switch (aggregate_info.aggregate_type) {
      case ExpressionType::AGGREGATE_SUM: {
        PL_ASSERT(source < std::numeric_limits<uint32_t>::max());
        auto curr = storage_.GetValueAt(codegen, storage_space,
                                        aggregate_info.storage_index);
        next = curr.Add(codegen, next_vals[source]);
        break;
      }
      case ExpressionType::AGGREGATE_MIN: {
        PL_ASSERT(source < std::numeric_limits<uint32_t>::max());
        auto curr = storage_.GetValueAt(codegen, storage_space,
                                        aggregate_info.storage_index);
        next = curr.Min(codegen, next_vals[source]);
        break;
      }
      case ExpressionType::AGGREGATE_MAX: {
        PL_ASSERT(source < std::numeric_limits<uint32_t>::max());
        auto curr = storage_.GetValueAt(codegen, storage_space,
                                        aggregate_info.storage_index);
        next = curr.Max(codegen, next_vals[source]);
        break;
      }
      case ExpressionType::AGGREGATE_COUNT: {
        auto curr = storage_.GetValueAt(codegen, storage_space,
                                        aggregate_info.storage_index);
        next = curr.Add(codegen, codegen::Value{type::Type::TypeId::BIGINT,
                                                codegen.Const64(1)});
        break;
      }
      case ExpressionType::AGGREGATE_COUNT_STAR: {
        // COUNT(*) is always stored first with a source equal to INT_MAX. All
        // other COUNT(*)'s refer to that one.
        if (source != std::numeric_limits<uint32_t>::max()) {
          continue;
        }
        auto curr = storage_.GetValueAt(codegen, storage_space,
                                        aggregate_info.storage_index);
        next = curr.Add(codegen, codegen::Value{type::Type::TypeId::BIGINT,
                                                codegen.Const64(1)});
        break;
      }
      case ExpressionType::AGGREGATE_AVG: {
        // AVG() aggregates aren't physically stored
        continue;
      }
      default: {
        std::string message = StringUtil::Format(
            "Unexpected aggregate type [%s] when advancing aggregator",
            ExpressionTypeToString(aggregate_info.aggregate_type));
        LOG_ERROR("%s", message.c_str());
        throw Exception{EXCEPTION_TYPE_UNKNOWN_TYPE, message};
      }
    }

    // StoreValue the next value in the appropriate slot
    PL_ASSERT(next.GetType() != type::Type::TypeId::INVALID);
    storage_.SetValueAt(codegen, storage_space, aggregate_info.storage_index,
                        next);
  }
}

//===----------------------------------------------------------------------===//
// This function will finalize the aggregates stored in the provided storage
// space.  Finalization essentially means computing the final values of the
// aggregates. This is only really necessary for averages. Either way, we
// populate the final_vals vector with the final values of all the aggregates.
//===----------------------------------------------------------------------===//
void Aggregation::FinalizeValues(
    CodeGen &codegen, llvm::Value *storage_space,
    std::vector<codegen::Value> &final_vals) const {
  // Collect all final values into this map. We need this because some
  // aggregates are derived from other component aggregates.
  std::map<std::pair<uint32_t, ExpressionType>, codegen::Value> vals;

  for (const auto &aggregate_info : aggregate_infos_) {
    uint32_t source = aggregate_info.source_index;
    ExpressionType agg_type = aggregate_info.aggregate_type;
    switch (agg_type) {
      case ExpressionType::AGGREGATE_COUNT:
      case ExpressionType::AGGREGATE_SUM:
      case ExpressionType::AGGREGATE_MIN:
      case ExpressionType::AGGREGATE_MAX: {
        codegen::Value final_val = storage_.GetValueAt(
            codegen, storage_space, aggregate_info.storage_index);
        vals[std::make_pair(source, agg_type)] = final_val;
        if (!aggregate_info.is_internal) {
          final_vals.push_back(final_val);
        }
        break;
      }
      case ExpressionType::AGGREGATE_AVG: {
        // Find the sum and count for this aggregate
        codegen::Value sum =
            vals[std::make_pair(source, ExpressionType::AGGREGATE_SUM)];
        codegen::Value count =
            vals[std::make_pair(source, ExpressionType::AGGREGATE_COUNT)];
        // TODO: Check if count is zero
        codegen::Value final_val = sum.Div(codegen, count);
        vals[std::make_pair(source, agg_type)] = final_val;
        final_vals.push_back(final_val);
        break;
      }
      case ExpressionType::AGGREGATE_COUNT_STAR: {
        if (source != std::numeric_limits<uint32_t>::max()) {
          PL_ASSERT(!aggregate_info.is_internal);
          uint32_t count_source = std::numeric_limits<uint32_t>::max();
          final_vals.push_back(vals[std::make_pair(count_source, agg_type)]);
        } else {
          PL_ASSERT(aggregate_info.is_internal);
          codegen::Value final_val = storage_.GetValueAt(
              codegen, storage_space, aggregate_info.storage_index);
          vals[std::make_pair(source, agg_type)] = final_val;
        }
        break;
      }
      default: {
        std::string message = StringUtil::Format(
            "Unexpected aggregate type [%s] when finalizing aggregator",
            ExpressionTypeToString(agg_type));
        LOG_ERROR("%s", message.c_str());
        throw Exception{EXCEPTION_TYPE_UNKNOWN_TYPE, message};
      }
    }
  }
}

}  // namespace codegen
}  // namespace peloton
<|endoftext|>