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

  Program:   Visualization Toolkit
  Module:    vtkDistanceRepresentation3D.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 "vtkDistanceRepresentation3D.h"
#include "vtkPointHandleRepresentation3D.h"
#include "vtkPolyDataMapper.h"
#include "vtkPoints.h"
#include "vtkCellArray.h"
#include "vtkPolyData.h"
#include "vtkPolyDataMapper.h"
#include "vtkActor.h"
#include "vtkVectorText.h"
#include "vtkFollower.h"
#include "vtkCamera.h"
#include "vtkProperty.h"
#include "vtkCoordinate.h"
#include "vtkRenderer.h"
#include "vtkObjectFactory.h"
#include "vtkInteractorObserver.h"
#include "vtkMath.h"
#include "vtkWindow.h"
#include "vtkSmartPointer.h"
#include "vtkBox.h"
#include "vtkGlyph3D.h"
#include "vtkCylinderSource.h"
#include "vtkDoubleArray.h"
#include "vtkPointData.h"
#include "vtkTransformPolyDataFilter.h"
#include "vtkTransform.h"
#include "vtkSmartPointer.h"

vtkStandardNewMacro(vtkDistanceRepresentation3D);

//----------------------------------------------------------------------
vtkDistanceRepresentation3D::vtkDistanceRepresentation3D()
{
  // By default, use one of these handles
  this->HandleRepresentation  = vtkPointHandleRepresentation3D::New();

  // The line
  this->LinePoints = vtkPoints::New();
  this->LinePoints->SetDataTypeToDouble();
  this->LinePoints->SetNumberOfPoints(2);
  this->LinePolyData = vtkPolyData::New();
  this->LinePolyData->SetPoints(this->LinePoints);
  vtkSmartPointer<vtkCellArray> line = vtkSmartPointer<vtkCellArray>::New();
  line->InsertNextCell(2);
  line->InsertCellPoint(0);
  line->InsertCellPoint(1);
  this->LinePolyData->SetLines(line);
  this->LineMapper = vtkPolyDataMapper::New();
  this->LineMapper->SetInput(this->LinePolyData);
  this->LineActor = vtkActor::New();
  this->LineActor->SetMapper(this->LineMapper);

  // The label
  this->LabelText = vtkVectorText::New();
  this->LabelMapper = vtkPolyDataMapper::New();
  this->LabelMapper->SetInputConnection(this->LabelText->GetOutputPort());
  this->LabelActor = vtkFollower::New();
  this->LabelActor->SetMapper(this->LabelMapper);

  // The tick marks
  this->GlyphPoints = vtkPoints::New();
  this->GlyphPoints->SetDataTypeToDouble();
  this->GlyphVectors = vtkDoubleArray::New();
  this->GlyphVectors->SetNumberOfComponents(3);
  this->GlyphPolyData = vtkPolyData::New();
  this->GlyphPolyData->SetPoints(this->GlyphPoints);
  this->GlyphPolyData->GetPointData()->SetVectors(this->GlyphVectors);
  this->GlyphCylinder = vtkCylinderSource::New();
  this->GlyphCylinder->SetRadius(0.5);
  this->GlyphCylinder->SetHeight(0.1);
  this->GlyphCylinder->SetResolution(12);
  vtkSmartPointer<vtkTransform> xform = vtkSmartPointer<vtkTransform>::New();
  this->GlyphXForm = vtkTransformPolyDataFilter::New();
  this->GlyphXForm->SetInputConnection(this->GlyphCylinder->GetOutputPort());
  this->GlyphXForm->SetTransform(xform);
  xform->RotateZ(90);
  this->Glyph3D = vtkGlyph3D::New();
  this->Glyph3D->SetInput(this->GlyphPolyData);
  this->Glyph3D->SetSourceConnection(this->GlyphXForm->GetOutputPort());
  this->Glyph3D->SetScaleModeToDataScalingOff();
  this->GlyphMapper = vtkPolyDataMapper::New();
  this->GlyphMapper->SetInputConnection(this->Glyph3D->GetOutputPort());
  this->GlyphActor = vtkActor::New();
  this->GlyphActor->SetMapper(this->GlyphMapper);

  this->Distance = 0.0;

  // The bounding box
  this->BoundingBox = vtkBox::New();

  // Scaling the label
  this->LabelScaleSpecified = false;
}

//----------------------------------------------------------------------
vtkDistanceRepresentation3D::~vtkDistanceRepresentation3D()
{
  this->LinePoints->Delete();
  this->LinePolyData->Delete();
  this->LineMapper->Delete();
  this->LineActor->Delete();

  this->LabelText->Delete();
  this->LabelMapper->Delete();
  this->LabelActor->Delete();

  this->GlyphPoints->Delete();
  this->GlyphVectors->Delete();
  this->GlyphPolyData->Delete();
  this->GlyphCylinder->Delete();
  this->GlyphXForm->Delete();
  this->Glyph3D->Delete();
  this->GlyphMapper->Delete();
  this->GlyphActor->Delete();

  this->BoundingBox->Delete();
}

//----------------------------------------------------------------------
void vtkDistanceRepresentation3D::GetPoint1WorldPosition(double pos[3])
{
  this->Point1Representation->GetWorldPosition(pos);
}

//----------------------------------------------------------------------
void vtkDistanceRepresentation3D::GetPoint2WorldPosition(double pos[3])
{
  this->Point2Representation->GetWorldPosition(pos);
}

//----------------------------------------------------------------------
double* vtkDistanceRepresentation3D::GetPoint1WorldPosition()
{
  if (!this->Point1Representation)
    {
    static double temp[3]=  {0, 0, 0};
    return temp;
    }
  return this->Point1Representation->GetWorldPosition();
}

//----------------------------------------------------------------------
double* vtkDistanceRepresentation3D::GetPoint2WorldPosition()
{
  if (!this->Point2Representation)
    {
    static double temp[3]=  {0, 0, 0};
    return temp;
    }
  return this->Point2Representation->GetWorldPosition();
}

//----------------------------------------------------------------------
void vtkDistanceRepresentation3D::SetPoint1DisplayPosition(double x[3])
{
  this->Point1Representation->SetDisplayPosition(x);
  double p[3];
  this->Point1Representation->GetWorldPosition(p);
  this->Point1Representation->SetWorldPosition(p);
}

//----------------------------------------------------------------------
void vtkDistanceRepresentation3D::SetPoint2DisplayPosition(double x[3])
{
  this->Point2Representation->SetDisplayPosition(x);
  double p[3];
  this->Point2Representation->GetWorldPosition(p);
  this->Point2Representation->SetWorldPosition(p);
}

//----------------------------------------------------------------------
void vtkDistanceRepresentation3D::SetPoint1WorldPosition(double x[3])
{
  if (this->Point1Representation)
    {
    this->Point1Representation->SetWorldPosition(x);
    }
}

//----------------------------------------------------------------------
void vtkDistanceRepresentation3D::SetPoint2WorldPosition(double x[3])
{
  if (this->Point2Representation)
    {
    this->Point2Representation->SetWorldPosition(x);
    }
}

//----------------------------------------------------------------------
void vtkDistanceRepresentation3D::GetPoint1DisplayPosition(double pos[3])
{
  this->Point1Representation->GetDisplayPosition(pos);
  pos[2] = 0.0;
}

//----------------------------------------------------------------------
void vtkDistanceRepresentation3D::GetPoint2DisplayPosition(double pos[3])
{
  this->Point2Representation->GetDisplayPosition(pos);
  pos[2] = 0.0;
}

//----------------------------------------------------------------------
double *vtkDistanceRepresentation3D::GetBounds()
{
  if(this->Point1Representation && this->Point2Representation)
    {
    this->BuildRepresentation();
    this->BoundingBox->SetBounds(this->Point1Representation->GetBounds());
    this->BoundingBox->AddBounds(this->Point2Representation->GetBounds());
    }
  this->BoundingBox->AddBounds(this->LineActor->GetBounds());

  return this->BoundingBox->GetBounds();
}

//----------------------------------------------------------------------
void vtkDistanceRepresentation3D::BuildRepresentation()
{
  if ( this->GetMTime() > this->BuildTime ||
       this->Point1Representation->GetMTime() > this->BuildTime ||
       this->Point2Representation->GetMTime() > this->BuildTime ||
       (this->Renderer && this->Renderer->GetVTKWindow() &&
        this->Renderer->GetVTKWindow()->GetMTime() > this->BuildTime) )
    {
    this->Superclass::BuildRepresentation();

    // Okay, compute the distance and set the label
    double p1[3], p2[3];
    this->Point1Representation->GetWorldPosition(p1);
    this->Point2Representation->GetWorldPosition(p2);
    this->Distance = sqrt(vtkMath::Distance2BetweenPoints(p1,p2));

    // Line
    this->LinePoints->SetPoint(0,p1);
    this->LinePoints->SetPoint(1,p2);
    this->LinePoints->Modified();

    // Label
    char string[512];
    double pos[3];
    sprintf(string, this->LabelFormat, this->Distance);
    this->LabelText->SetText(string);
    pos[0] = (p1[0]+p2[0])/2.0; pos[1] = (p1[1]+p2[1])/2.0; pos[2] = (p1[2]+p2[2])/2.0;
    this->LabelActor->SetPosition(pos);
    if (this->Renderer) //make the label face the camera
      {
      this->LabelActor->SetCamera( this->Renderer->GetActiveCamera() );
      }

    if (!this->LabelScaleSpecified)
      {
      // If a font size hasn't been specified by the user, scale the text
      // (font size) according to the length of the line widget.
      this->LabelActor->SetScale(
          this->Distance/20.0, this->Distance/20.0, this->Distance/20.0 );
      }

    // Ticks - generate points that are glyphed
    int i, numTicks;
    double v21[3], x[3];
    v21[0] =  p2[0] - p1[0]; v21[1] =  p2[1] - p1[1]; v21[2] =  p2[2] - p1[2];
    vtkMath::Normalize(v21);
    this->GlyphPoints->Reset();
    this->GlyphPoints->Modified();
    this->GlyphVectors->Reset();
    this->Glyph3D->SetScaleFactor(this->Distance/40);
    double distance;
    if ( this->RulerMode ) // specified tick separation
      {
      numTicks = (this->RulerDistance <= 0.0 ? 1 : (this->Distance / this->RulerDistance));
      numTicks = (numTicks > 99 ? 99 : numTicks);
      distance = this->RulerDistance;
      }
    else //evenly spaced
      {
      numTicks = this->NumberOfRulerTicks;
      distance = this->Distance / (numTicks + 1);
      }
    for (i=1; i <= numTicks; ++i)
      {
      x[0] = p1[0] + i*v21[0]*distance;
      x[1] = p1[1] + i*v21[1]*distance;
      x[2] = p1[2] + i*v21[2]*distance;
      this->GlyphPoints->InsertNextPoint(x);
      this->GlyphVectors->InsertNextTuple(v21);
      }

    this->BuildTime.Modified();
    }
}

//----------------------------------------------------------------------
void vtkDistanceRepresentation3D::
ReleaseGraphicsResources(vtkWindow *w)
{
  this->LineActor->ReleaseGraphicsResources(w);
  this->LabelActor->ReleaseGraphicsResources(w);
  this->GlyphActor->ReleaseGraphicsResources(w);
}

//----------------------------------------------------------------------
int vtkDistanceRepresentation3D::
RenderOpaqueGeometry(vtkViewport *v)
{
  this->BuildRepresentation();

  this->LineActor->RenderOpaqueGeometry(v);
  this->LabelActor->RenderOpaqueGeometry(v);
  this->GlyphActor->RenderOpaqueGeometry(v);

  return 3;
}

//----------------------------------------------------------------------
int vtkDistanceRepresentation3D::
RenderTranslucentPolygonalGeometry(vtkViewport *v)
{
  this->BuildRepresentation();

  this->LineActor->RenderTranslucentPolygonalGeometry(v);
  this->LabelActor->RenderTranslucentPolygonalGeometry(v);
  this->GlyphActor->RenderTranslucentPolygonalGeometry(v);

  return 3;
}

//----------------------------------------------------------------------
void vtkDistanceRepresentation3D::SetLabelScale( double scale[3] )
{
  this->LabelActor->SetScale( scale );
  this->LabelScaleSpecified = true;
}

//----------------------------------------------------------------------
double * vtkDistanceRepresentation3D::GetLabelScale()
{
  return this->LabelActor->GetScale();
}

//----------------------------------------------------------------------------
vtkProperty * vtkDistanceRepresentation3D::GetLabelProperty()
{
  return this->LabelActor->GetProperty();
}

//----------------------------------------------------------------------
void vtkDistanceRepresentation3D::PrintSelf(ostream& os, vtkIndent indent)
{
  //Superclass typedef defined in vtkTypeMacro() found in vtkSetGet.h
  this->Superclass::PrintSelf(os,indent);
}
<commit_msg>Fix casting warning.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkDistanceRepresentation3D.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 "vtkDistanceRepresentation3D.h"
#include "vtkPointHandleRepresentation3D.h"
#include "vtkPolyDataMapper.h"
#include "vtkPoints.h"
#include "vtkCellArray.h"
#include "vtkPolyData.h"
#include "vtkPolyDataMapper.h"
#include "vtkActor.h"
#include "vtkVectorText.h"
#include "vtkFollower.h"
#include "vtkCamera.h"
#include "vtkProperty.h"
#include "vtkCoordinate.h"
#include "vtkRenderer.h"
#include "vtkObjectFactory.h"
#include "vtkInteractorObserver.h"
#include "vtkMath.h"
#include "vtkWindow.h"
#include "vtkSmartPointer.h"
#include "vtkBox.h"
#include "vtkGlyph3D.h"
#include "vtkCylinderSource.h"
#include "vtkDoubleArray.h"
#include "vtkPointData.h"
#include "vtkTransformPolyDataFilter.h"
#include "vtkTransform.h"
#include "vtkSmartPointer.h"

vtkStandardNewMacro(vtkDistanceRepresentation3D);

//----------------------------------------------------------------------
vtkDistanceRepresentation3D::vtkDistanceRepresentation3D()
{
  // By default, use one of these handles
  this->HandleRepresentation  = vtkPointHandleRepresentation3D::New();

  // The line
  this->LinePoints = vtkPoints::New();
  this->LinePoints->SetDataTypeToDouble();
  this->LinePoints->SetNumberOfPoints(2);
  this->LinePolyData = vtkPolyData::New();
  this->LinePolyData->SetPoints(this->LinePoints);
  vtkSmartPointer<vtkCellArray> line = vtkSmartPointer<vtkCellArray>::New();
  line->InsertNextCell(2);
  line->InsertCellPoint(0);
  line->InsertCellPoint(1);
  this->LinePolyData->SetLines(line);
  this->LineMapper = vtkPolyDataMapper::New();
  this->LineMapper->SetInput(this->LinePolyData);
  this->LineActor = vtkActor::New();
  this->LineActor->SetMapper(this->LineMapper);

  // The label
  this->LabelText = vtkVectorText::New();
  this->LabelMapper = vtkPolyDataMapper::New();
  this->LabelMapper->SetInputConnection(this->LabelText->GetOutputPort());
  this->LabelActor = vtkFollower::New();
  this->LabelActor->SetMapper(this->LabelMapper);

  // The tick marks
  this->GlyphPoints = vtkPoints::New();
  this->GlyphPoints->SetDataTypeToDouble();
  this->GlyphVectors = vtkDoubleArray::New();
  this->GlyphVectors->SetNumberOfComponents(3);
  this->GlyphPolyData = vtkPolyData::New();
  this->GlyphPolyData->SetPoints(this->GlyphPoints);
  this->GlyphPolyData->GetPointData()->SetVectors(this->GlyphVectors);
  this->GlyphCylinder = vtkCylinderSource::New();
  this->GlyphCylinder->SetRadius(0.5);
  this->GlyphCylinder->SetHeight(0.1);
  this->GlyphCylinder->SetResolution(12);
  vtkSmartPointer<vtkTransform> xform = vtkSmartPointer<vtkTransform>::New();
  this->GlyphXForm = vtkTransformPolyDataFilter::New();
  this->GlyphXForm->SetInputConnection(this->GlyphCylinder->GetOutputPort());
  this->GlyphXForm->SetTransform(xform);
  xform->RotateZ(90);
  this->Glyph3D = vtkGlyph3D::New();
  this->Glyph3D->SetInput(this->GlyphPolyData);
  this->Glyph3D->SetSourceConnection(this->GlyphXForm->GetOutputPort());
  this->Glyph3D->SetScaleModeToDataScalingOff();
  this->GlyphMapper = vtkPolyDataMapper::New();
  this->GlyphMapper->SetInputConnection(this->Glyph3D->GetOutputPort());
  this->GlyphActor = vtkActor::New();
  this->GlyphActor->SetMapper(this->GlyphMapper);

  this->Distance = 0.0;

  // The bounding box
  this->BoundingBox = vtkBox::New();

  // Scaling the label
  this->LabelScaleSpecified = false;
}

//----------------------------------------------------------------------
vtkDistanceRepresentation3D::~vtkDistanceRepresentation3D()
{
  this->LinePoints->Delete();
  this->LinePolyData->Delete();
  this->LineMapper->Delete();
  this->LineActor->Delete();

  this->LabelText->Delete();
  this->LabelMapper->Delete();
  this->LabelActor->Delete();

  this->GlyphPoints->Delete();
  this->GlyphVectors->Delete();
  this->GlyphPolyData->Delete();
  this->GlyphCylinder->Delete();
  this->GlyphXForm->Delete();
  this->Glyph3D->Delete();
  this->GlyphMapper->Delete();
  this->GlyphActor->Delete();

  this->BoundingBox->Delete();
}

//----------------------------------------------------------------------
void vtkDistanceRepresentation3D::GetPoint1WorldPosition(double pos[3])
{
  this->Point1Representation->GetWorldPosition(pos);
}

//----------------------------------------------------------------------
void vtkDistanceRepresentation3D::GetPoint2WorldPosition(double pos[3])
{
  this->Point2Representation->GetWorldPosition(pos);
}

//----------------------------------------------------------------------
double* vtkDistanceRepresentation3D::GetPoint1WorldPosition()
{
  if (!this->Point1Representation)
    {
    static double temp[3]=  {0, 0, 0};
    return temp;
    }
  return this->Point1Representation->GetWorldPosition();
}

//----------------------------------------------------------------------
double* vtkDistanceRepresentation3D::GetPoint2WorldPosition()
{
  if (!this->Point2Representation)
    {
    static double temp[3]=  {0, 0, 0};
    return temp;
    }
  return this->Point2Representation->GetWorldPosition();
}

//----------------------------------------------------------------------
void vtkDistanceRepresentation3D::SetPoint1DisplayPosition(double x[3])
{
  this->Point1Representation->SetDisplayPosition(x);
  double p[3];
  this->Point1Representation->GetWorldPosition(p);
  this->Point1Representation->SetWorldPosition(p);
}

//----------------------------------------------------------------------
void vtkDistanceRepresentation3D::SetPoint2DisplayPosition(double x[3])
{
  this->Point2Representation->SetDisplayPosition(x);
  double p[3];
  this->Point2Representation->GetWorldPosition(p);
  this->Point2Representation->SetWorldPosition(p);
}

//----------------------------------------------------------------------
void vtkDistanceRepresentation3D::SetPoint1WorldPosition(double x[3])
{
  if (this->Point1Representation)
    {
    this->Point1Representation->SetWorldPosition(x);
    }
}

//----------------------------------------------------------------------
void vtkDistanceRepresentation3D::SetPoint2WorldPosition(double x[3])
{
  if (this->Point2Representation)
    {
    this->Point2Representation->SetWorldPosition(x);
    }
}

//----------------------------------------------------------------------
void vtkDistanceRepresentation3D::GetPoint1DisplayPosition(double pos[3])
{
  this->Point1Representation->GetDisplayPosition(pos);
  pos[2] = 0.0;
}

//----------------------------------------------------------------------
void vtkDistanceRepresentation3D::GetPoint2DisplayPosition(double pos[3])
{
  this->Point2Representation->GetDisplayPosition(pos);
  pos[2] = 0.0;
}

//----------------------------------------------------------------------
double *vtkDistanceRepresentation3D::GetBounds()
{
  if(this->Point1Representation && this->Point2Representation)
    {
    this->BuildRepresentation();
    this->BoundingBox->SetBounds(this->Point1Representation->GetBounds());
    this->BoundingBox->AddBounds(this->Point2Representation->GetBounds());
    }
  this->BoundingBox->AddBounds(this->LineActor->GetBounds());

  return this->BoundingBox->GetBounds();
}

//----------------------------------------------------------------------
void vtkDistanceRepresentation3D::BuildRepresentation()
{
  if ( this->GetMTime() > this->BuildTime ||
       this->Point1Representation->GetMTime() > this->BuildTime ||
       this->Point2Representation->GetMTime() > this->BuildTime ||
       (this->Renderer && this->Renderer->GetVTKWindow() &&
        this->Renderer->GetVTKWindow()->GetMTime() > this->BuildTime) )
    {
    this->Superclass::BuildRepresentation();

    // Okay, compute the distance and set the label
    double p1[3], p2[3];
    this->Point1Representation->GetWorldPosition(p1);
    this->Point2Representation->GetWorldPosition(p2);
    this->Distance = sqrt(vtkMath::Distance2BetweenPoints(p1,p2));

    // Line
    this->LinePoints->SetPoint(0,p1);
    this->LinePoints->SetPoint(1,p2);
    this->LinePoints->Modified();

    // Label
    char string[512];
    double pos[3];
    sprintf(string, this->LabelFormat, this->Distance);
    this->LabelText->SetText(string);
    pos[0] = (p1[0]+p2[0])/2.0; pos[1] = (p1[1]+p2[1])/2.0; pos[2] = (p1[2]+p2[2])/2.0;
    this->LabelActor->SetPosition(pos);
    if (this->Renderer) //make the label face the camera
      {
      this->LabelActor->SetCamera( this->Renderer->GetActiveCamera() );
      }

    if (!this->LabelScaleSpecified)
      {
      // If a font size hasn't been specified by the user, scale the text
      // (font size) according to the length of the line widget.
      this->LabelActor->SetScale(
          this->Distance/20.0, this->Distance/20.0, this->Distance/20.0 );
      }

    // Ticks - generate points that are glyphed
    int i, numTicks;
    double v21[3], x[3];
    v21[0] =  p2[0] - p1[0]; v21[1] =  p2[1] - p1[1]; v21[2] =  p2[2] - p1[2];
    vtkMath::Normalize(v21);
    this->GlyphPoints->Reset();
    this->GlyphPoints->Modified();
    this->GlyphVectors->Reset();
    this->Glyph3D->SetScaleFactor(this->Distance/40);
    double distance;
    if ( this->RulerMode ) // specified tick separation
      {
      numTicks = (this->RulerDistance <= 0.0 ? 1 : static_cast<int>(this->Distance / this->RulerDistance));
      numTicks = (numTicks > 99 ? 99 : numTicks);
      distance = this->RulerDistance;
      }
    else //evenly spaced
      {
      numTicks = this->NumberOfRulerTicks;
      distance = this->Distance / (numTicks + 1);
      }
    for (i=1; i <= numTicks; ++i)
      {
      x[0] = p1[0] + i*v21[0]*distance;
      x[1] = p1[1] + i*v21[1]*distance;
      x[2] = p1[2] + i*v21[2]*distance;
      this->GlyphPoints->InsertNextPoint(x);
      this->GlyphVectors->InsertNextTuple(v21);
      }

    this->BuildTime.Modified();
    }
}

//----------------------------------------------------------------------
void vtkDistanceRepresentation3D::
ReleaseGraphicsResources(vtkWindow *w)
{
  this->LineActor->ReleaseGraphicsResources(w);
  this->LabelActor->ReleaseGraphicsResources(w);
  this->GlyphActor->ReleaseGraphicsResources(w);
}

//----------------------------------------------------------------------
int vtkDistanceRepresentation3D::
RenderOpaqueGeometry(vtkViewport *v)
{
  this->BuildRepresentation();

  this->LineActor->RenderOpaqueGeometry(v);
  this->LabelActor->RenderOpaqueGeometry(v);
  this->GlyphActor->RenderOpaqueGeometry(v);

  return 3;
}

//----------------------------------------------------------------------
int vtkDistanceRepresentation3D::
RenderTranslucentPolygonalGeometry(vtkViewport *v)
{
  this->BuildRepresentation();

  this->LineActor->RenderTranslucentPolygonalGeometry(v);
  this->LabelActor->RenderTranslucentPolygonalGeometry(v);
  this->GlyphActor->RenderTranslucentPolygonalGeometry(v);

  return 3;
}

//----------------------------------------------------------------------
void vtkDistanceRepresentation3D::SetLabelScale( double scale[3] )
{
  this->LabelActor->SetScale( scale );
  this->LabelScaleSpecified = true;
}

//----------------------------------------------------------------------
double * vtkDistanceRepresentation3D::GetLabelScale()
{
  return this->LabelActor->GetScale();
}

//----------------------------------------------------------------------------
vtkProperty * vtkDistanceRepresentation3D::GetLabelProperty()
{
  return this->LabelActor->GetProperty();
}

//----------------------------------------------------------------------
void vtkDistanceRepresentation3D::PrintSelf(ostream& os, vtkIndent indent)
{
  //Superclass typedef defined in vtkTypeMacro() found in vtkSetGet.h
  this->Superclass::PrintSelf(os,indent);
}
<|endoftext|>


<commit_before>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Albrecht
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_STUFF_COMMON_CONVERGENCE_STUDY_HH
#define DUNE_STUFF_COMMON_CONVERGENCE_STUDY_HH

#include <vector>
#include <map>
#include <iostream>

#include <dune/common/exceptions.hh>

#include <dune/stuff/common/string.hh>

namespace Dune {
namespace Stuff {
namespace Common {

class ConvergenceStudy
{
public:
  virtual ~ConvergenceStudy() {}

  virtual std::string identifier() const = 0;

  virtual size_t num_refinements() const = 0;

  virtual std::vector< std::string > provided_norms() const  = 0;

  virtual size_t expected_rate(const std::string type) const = 0;

  virtual double norm_reference_solution(const std::string type) = 0;

  virtual size_t current_grid_size() const = 0;

  virtual double current_grid_width() const = 0;

  virtual void compute_on_current_refinement() = 0;

  virtual double current_error_norm(const std::string type) = 0;

  virtual void refine() = 0;

  std::map< std::string, std::vector< double > > run(const bool relative = true, std::ostream& out = std::cout)
  {
    if (provided_norms().size() == 0)
      DUNE_THROW(Dune::InvalidStateException, "You have to provide at least one norm!");
    std::map< std::string, std::vector< double > > ret;
    for (const auto& norm : provided_norms())
      ret[norm] = std::vector< double >();

    // print table header
    out << identifier() << std::endl;
    if (identifier().size() > 22*(provided_norms().size() + 1))
      out << Stuff::Common::whitespaceify(identifier(), '=') << std::endl;
    else {
      out << "=====================";
      for (size_t nn = 0; nn < provided_norms().size(); ++nn)
        out << "======================";
    }
    out << "\n";
    // * print line of grid and norms
    out << "        grid         ";
    for (const auto& norm : provided_norms()) {
      std::string relative_norm_str = "";
      if (norm.empty()) {
        relative_norm_str = "???";
        if (relative)
          relative_norm_str += " (relative)";
        else
          relative_norm_str += " (absolute)";
      } else if (norm.size() <= 8) {
        relative_norm_str = norm;
        if (relative)
          relative_norm_str += " (relative)";
        else
          relative_norm_str += " (absolute)";
      } else if (norm.size() <= 12) {
        relative_norm_str = norm;
        if (relative)
          relative_norm_str += " (rel.)";
        else
          relative_norm_str += " (abs.)";
      } else {
        relative_norm_str = norm.substr(0, 11);
        if (relative)
          relative_norm_str += " (rel.)";
        else
          relative_norm_str += " (abs.)";
      }
      const double missing = (19.0 - relative_norm_str.size())/2.0;
      for (size_t ii = 0; ii < missing; ++ii)
        relative_norm_str += " ";
      assert(relative_norm_str.size() <= 19);
      out << "| " << std::setw(19) << relative_norm_str << " ";
    }
    out << "\n";
    // * print thin delimiter
    out << "---------------------";
    for (size_t nn = 0; nn < provided_norms().size(); ++nn)
      out << "+---------------------";
    out << "\n";
    // * print size/width/error/EOC markers
    out << "     size |    width ";
    for (size_t nn = 0; nn < provided_norms().size(); ++nn)
      out << "|    error |      EOC ";
    out << "\n";
    // * print thick delimiter
    out << "==========+==========";
    for (size_t nn = 0; nn < provided_norms().size(); ++nn)
      out << "+==========+==========";
    out << std::endl;

    // prepare data structures
    std::map< std::string, double > reference_norm;
    std::map< std::string, double > last_relative_error;
    for (const auto& norm : provided_norms()) {
      if (relative)
        reference_norm[norm] = norm_reference_solution(norm);
      else
        reference_norm[norm] = 0.0;
      last_relative_error[norm] = 0.0;
    }
    double last_grid_width = current_grid_width();

    // iterate
    for (size_t ii = 0; ii <= num_refinements(); ++ii) {
      // print delimiter
      if (ii > 0) {
        out << "----------+----------";
        for (size_t nn = 0; nn < provided_norms().size(); ++nn)
          out << "+----------+----------";
        out << "\n";
      }

      // print grid size
      out << " " << std::setw(8) << current_grid_size() << std::flush;
      // print grid with
      out << " | " << std::setw(8) << std::setprecision(2) << std::scientific << current_grid_width() << std::flush;

      // loop over all norms/columns
      for (const auto& norm : provided_norms()) {
        // compute and print relative error
        double relative_error = current_error_norm(norm);
        if (relative)
          relative_error /= reference_norm[norm];
        ret[norm].push_back(relative_error);
        out << " | " << std::setw(8) << std::setprecision(2) << std::scientific << relative_error << std::flush;
        // print eoc
        out << " | ";
        if (ii == 0)
          out << std::setw(8) << "----" << std::flush;
        else {
          const double eoc_value = std::log(relative_error / last_relative_error[norm])
              / std::log(current_grid_width() / last_grid_width);
          std::stringstream eoc_string;
          eoc_string << std::setw(8) << std::setprecision(2) << std::fixed << eoc_value;
          if (eoc_value > (0.9 * expected_rate(norm)))
            out << Stuff::Common::colorString(eoc_string.str(), Stuff::Common::Colors::green) << std::flush;
          else if (eoc_value > 0.0)
              out << Stuff::Common::colorString(eoc_string.str(), Stuff::Common::Colors::brown) << std::flush;
          else
            out << Stuff::Common::colorString(eoc_string.str(), Stuff::Common::Colors::red) << std::flush;
        }
        // update
        last_relative_error[norm] = relative_error;
      } // loop over all norms/columns
      out << std::endl;
      // update
      last_grid_width = current_grid_width();
      if (ii < num_refinements())
        refine();
    } // iterate

    return ret;
  } // ... run(...)
}; // class ConvergenceStudy

} // namespace Common
} // namespace Stuff
} // namespace Dune

#endif // DUNE_STUFF_COMMON_CONVERGENCE_STUDY_HH
<commit_msg>[common.convergence-study] added timing information<commit_after>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Albrecht
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_STUFF_COMMON_CONVERGENCE_STUDY_HH
#define DUNE_STUFF_COMMON_CONVERGENCE_STUDY_HH

#include <vector>
#include <map>
#include <iostream>

#include <dune/common/exceptions.hh>

#include <dune/stuff/common/string.hh>

namespace Dune {
namespace Stuff {
namespace Common {

class ConvergenceStudy
{
public:
  virtual ~ConvergenceStudy() {}

  virtual std::string identifier() const = 0;

  virtual size_t num_refinements() const = 0;

  virtual std::vector< std::string > provided_norms() const  = 0;

  virtual size_t expected_rate(const std::string type) const = 0;

  virtual double norm_reference_solution(const std::string type) = 0;

  virtual size_t current_grid_size() const = 0;

  virtual double current_grid_width() const = 0;

  /**
   * \return The time it took to solve on this refinement.
   */
  virtual double compute_on_current_refinement() = 0;

  virtual double current_error_norm(const std::string type) = 0;

  virtual void refine() = 0;

  std::map< std::string, std::vector< double > > run(const bool relative = true, std::ostream& out = std::cout)
  {
    if (provided_norms().size() == 0)
      DUNE_THROW(Dune::InvalidStateException, "You have to provide at least one norm!");
    std::map< std::string, std::vector< double > > ret;
    for (const auto& norm : provided_norms())
      ret[norm] = std::vector< double >();

    // print table header
    out << identifier() << std::endl;
    if (identifier().size() > 22*(provided_norms().size() + 1))
      out << Stuff::Common::whitespaceify(identifier(), '=') << std::endl;
    else {
      out << "=====================";
      for (size_t nn = 0; nn < provided_norms().size(); ++nn)
        out << "======================";
    }
    out << "\n";
    // * print line of grid and norms
    out << "        grid         ";
    for (const auto& norm : provided_norms()) {
      std::string relative_norm_str = "";
      if (norm.empty()) {
        relative_norm_str = "???";
        if (relative)
          relative_norm_str += " (relative)";
        else
          relative_norm_str += " (absolute)";
      } else if (norm.size() <= 8) {
        relative_norm_str = norm;
        if (relative)
          relative_norm_str += " (relative)";
        else
          relative_norm_str += " (absolute)";
      } else if (norm.size() <= 12) {
        relative_norm_str = norm;
        if (relative)
          relative_norm_str += " (rel.)";
        else
          relative_norm_str += " (abs.)";
      } else {
        relative_norm_str = norm.substr(0, 11);
        if (relative)
          relative_norm_str += " (rel.)";
        else
          relative_norm_str += " (abs.)";
      }
      const double missing = (19.0 - relative_norm_str.size())/2.0;
      for (size_t ii = 0; ii < missing; ++ii)
        relative_norm_str += " ";
      assert(relative_norm_str.size() <= 19);
      out << "| " << std::setw(19) << relative_norm_str << " ";
    }
    out << "\n";
    // * print thin delimiter
    out << "---------------------";
    for (size_t nn = 0; nn < provided_norms().size(); ++nn)
      out << "+---------------------";
    out << "\n";
    // * print size/width/error/EOC markers
    out << "     size |    width ";
    for (size_t nn = 0; nn < provided_norms().size(); ++nn)
      out << "|    error |      EOC ";
    out << "\n";
    // * print thick delimiter
    out << "==========+==========";
    for (size_t nn = 0; nn < provided_norms().size(); ++nn)
      out << "+==========+==========";
    out << std::endl;

    // prepare data structures
    std::map< std::string, double > reference_norm;
    std::map< std::string, double > last_relative_error;
    for (const auto& norm : provided_norms()) {
      if (relative)
        reference_norm[norm] = norm_reference_solution(norm);
      else
        reference_norm[norm] = 0.0;
      last_relative_error[norm] = 0.0;
    }
    double last_grid_width = current_grid_width();

    // iterate
    for (size_t ii = 0; ii <= num_refinements(); ++ii) {
      // print delimiter
      if (ii > 0) {
        out << "----------+----------";
        for (size_t nn = 0; nn < provided_norms().size(); ++nn)
          out << "+----------+----------";
        out << "\n";
      }

      // print grid size
      out << " " << std::setw(8) << current_grid_size() << std::flush;
      // print grid with
      out << " | " << std::setw(8) << std::setprecision(2) << std::scientific << current_grid_width() << std::flush;

      // do the computation
      const double elapsed = compute_on_current_refinement();

      // loop over all norms/columns
      for (const auto& norm : provided_norms()) {
        // compute and print relative error
        double relative_error = current_error_norm(norm);
        if (relative)
          relative_error /= reference_norm[norm];
        ret[norm].push_back(relative_error);
        out << " | " << std::setw(8) << std::setprecision(2) << std::scientific << relative_error << std::flush;
        // print eoc
        out << " | ";
        if (ii == 0)
          out << std::setw(8) << "----" << std::flush;
        else {
          const double eoc_value = std::log(relative_error / last_relative_error[norm])
              / std::log(current_grid_width() / last_grid_width);
          std::stringstream eoc_string;
          eoc_string << std::setw(8) << std::setprecision(2) << std::fixed << eoc_value;
          if (eoc_value > (0.9 * expected_rate(norm)))
            out << Stuff::Common::colorString(eoc_string.str(), Stuff::Common::Colors::green) << std::flush;
          else if (eoc_value > 0.0)
              out << Stuff::Common::colorString(eoc_string.str(), Stuff::Common::Colors::brown) << std::flush;
          else
            out << Stuff::Common::colorString(eoc_string.str(), Stuff::Common::Colors::red) << std::flush;
        }
        // update
        last_relative_error[norm] = relative_error;
      } // loop over all norms/columns
      // print time
      if (elapsed < 1.0)
        out << "  (solve took " << int(1000*elapsed) << "ms)" << std::endl;
      else
        out << "  (solve took " << std::setprecision(2) << std::fixed << elapsed << "s)" << std::endl;
      // update
      last_grid_width = current_grid_width();
      if (ii < num_refinements())
        refine();
    } // iterate

    return ret;
  } // ... run(...)
}; // class ConvergenceStudy

} // namespace Common
} // namespace Stuff
} // namespace Dune

#endif // DUNE_STUFF_COMMON_CONVERGENCE_STUDY_HH
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2018 Couchbase, Inc
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   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 "callbacks.h"
#include "kvstore.h"
#include "kvstore_config.h"
#ifdef EP_USE_ROCKSDB
#include "rocksdb-kvstore/rocksdb-kvstore_config.h"
#endif
#include "tests/module_tests/test_helpers.h"

#include <benchmark/benchmark.h>
#include <gtest/gtest.h>
#include <platform/dirutils.h>

enum Storage {
    COUCHSTORE = 0
#ifdef EP_USE_ROCKSDB
    ,
    ROCKSDB
#endif
};

class MockWriteCallback : public Callback<TransactionContext, mutation_result> {
public:
    MockWriteCallback() {
    }
    void callback(TransactionContext&, mutation_result& result) {
    }
};

class MockCacheCallback : public StatusCallback<CacheLookup> {
public:
    MockCacheCallback(){};
    void callback(CacheLookup& lookup) {
        // I want to simulate DGM scenarios where we have a HT-miss most times.
        // So, here I return what KVStore understands as "Item not in the
        // HashTable, go to the Storage".
        setStatus(ENGINE_SUCCESS);
    };
};

class MockDiskCallback : public StatusCallback<GetValue> {
public:
    MockDiskCallback() : itemCount(0){};
    void callback(GetValue& val) {
        // Just increase the item count
        // Note: this callback is invoked for each item read from the storage.
        //     This is where the real DiskCallback pushes the Item to
        //     the DCP stream.
        itemCount++;
    };
    // Get the number of items found during a scan
    size_t getItemCount() {
        return itemCount;
    }

protected:
    // Number of items found during a scan
    size_t itemCount;
};

/*
 * Benchmark fixture for KVStore.
 */
class KVStoreBench : public benchmark::Fixture {
protected:
    void SetUp(benchmark::State& state) override {
        numItems = state.range(0);
        auto storage = state.range(1);

        // Initialize KVStoreConfig
        Configuration config;
        uint16_t shardId = 0;
        config.setDbname("KVStoreBench.db");
        switch (storage) {
        case COUCHSTORE:
            state.SetLabel("Couchstore");
            config.setBackend("couchdb");
            kvstoreConfig = std::make_unique<KVStoreConfig>(config, shardId);
            break;
#ifdef EP_USE_ROCKSDB
        case ROCKSDB:
            state.SetLabel("CouchRocks");
            config.setBackend("rocksdb");
            kvstoreConfig =
                    std::make_unique<RocksDBKVStoreConfig>(config, shardId);
            break;
#endif
        }

        // Initialize KVStore
        kvstore = setup_kv_store(*kvstoreConfig);

        // Load some data
        const std::string key = "key";
        std::string value = "value";
        MockWriteCallback wc;
        uint16_t vbid = 0;
        kvstore->begin(std::make_unique<TransactionContext>());
        for (int i = 1; i <= numItems; i++) {
            Item item(makeStoredDocKey(key + std::to_string(i)),
                      0 /*flags*/,
                      0 /*exptime*/,
                      value.c_str(),
                      value.size(),
                      PROTOCOL_BINARY_RAW_BYTES,
                      0 /*cas*/,
                      i /*bySeqno*/,
                      vbid);
            kvstore->set(item, wc);
        }
        kvstore->commit(nullptr /*no collections manifest*/);
        // Just check that the VBucket High Seqno has been updated correctly
        EXPECT_EQ(kvstore->getVBucketState(vbid)->highSeqno, numItems);
    }

    void TearDown(const benchmark::State& state) override {
        kvstore.reset();
        cb::io::rmrf(kvstoreConfig->getDBName());
    }

private:
    std::unique_ptr<KVStore> setup_kv_store(KVStoreConfig& config) {
        auto kvstore = KVStoreFactory::create(config);
        vbucket_state state(vbucket_state_active,
                            0 /*chkid*/,
                            0 /*maxDelSeqNum*/,
                            0 /*highSeqno*/,
                            0 /*purgeSeqno*/,
                            0 /*lastSnapStart*/,
                            0 /*lastSnapEnd*/,
                            0 /*maxCas*/,
                            0 /*hlcCasEpochSeqno*/,
                            false /*mightContainXattrs*/,
                            "" /*failovers*/);
        kvstore.rw->snapshotVBucket(
                vbid, state, VBStatePersist::VBSTATE_PERSIST_WITHOUT_COMMIT);
        return std::move(kvstore.rw);
    }

protected:
    std::unique_ptr<KVStoreConfig> kvstoreConfig;
    std::unique_ptr<KVStore> kvstore;
    uint16_t vbid = 0;
    int numItems;
};

/*
 * Benchmark for KVStore::scan()
 */
BENCHMARK_DEFINE_F(KVStoreBench, Scan)(benchmark::State& state) {
    size_t itemCountTotal = 0;

    while (state.KeepRunning()) {
        // Note: the CacheCallback here just make the code to flow into reading
        // data from disk
        auto cb = std::make_shared<MockDiskCallback>();
        auto cl = std::make_shared<MockCacheCallback>();
        ScanContext* scanContext =
                kvstore->initScanContext(cb,
                                         cl,
                                         vbid,
                                         0 /*startSeqno*/,
                                         DocumentFilter::ALL_ITEMS,
                                         ValueFilter::VALUES_COMPRESSED);
        ASSERT_TRUE(scanContext);

        auto scanStatus = kvstore->scan(scanContext);
        ASSERT_EQ(scanStatus, scan_success);
        auto itemCount = cb->getItemCount();
        ASSERT_EQ(itemCount, numItems);
        itemCountTotal += itemCount;

        kvstore->destroyScanContext(scanContext);
    }

    state.SetItemsProcessed(itemCountTotal);
}

const int NUM_ITEMS = 100000;

BENCHMARK_REGISTER_F(KVStoreBench, Scan)
        ->Args({NUM_ITEMS, COUCHSTORE})
#ifdef EP_USE_ROCKSDB
        ->Args({NUM_ITEMS, ROCKSDB})
#endif
        ;
<commit_msg>MB-29335 CouchRocks: KVStoreBench/Scan slow runtime on SetUp<commit_after>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2018 Couchbase, Inc
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   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 "callbacks.h"
#include "kvstore.h"
#include "kvstore_config.h"
#ifdef EP_USE_ROCKSDB
#include "rocksdb-kvstore/rocksdb-kvstore_config.h"
#endif
#include "tests/module_tests/test_helpers.h"

#include <benchmark/benchmark.h>
#include <gtest/gtest.h>
#include <platform/dirutils.h>

enum Storage {
    COUCHSTORE = 0
#ifdef EP_USE_ROCKSDB
    ,
    ROCKSDB
#endif
};

class MockWriteCallback : public Callback<TransactionContext, mutation_result> {
public:
    MockWriteCallback() {
    }
    void callback(TransactionContext&, mutation_result& result) {
    }
};

class MockCacheCallback : public StatusCallback<CacheLookup> {
public:
    MockCacheCallback(){};
    void callback(CacheLookup& lookup) {
        // I want to simulate DGM scenarios where we have a HT-miss most times.
        // So, here I return what KVStore understands as "Item not in the
        // HashTable, go to the Storage".
        setStatus(ENGINE_SUCCESS);
    };
};

class MockDiskCallback : public StatusCallback<GetValue> {
public:
    MockDiskCallback() : itemCount(0){};
    void callback(GetValue& val) {
        // Just increase the item count
        // Note: this callback is invoked for each item read from the storage.
        //     This is where the real DiskCallback pushes the Item to
        //     the DCP stream.
        itemCount++;
    };
    // Get the number of items found during a scan
    size_t getItemCount() {
        return itemCount;
    }

protected:
    // Number of items found during a scan
    size_t itemCount;
};

/*
 * Benchmark fixture for KVStore.
 */
class KVStoreBench : public benchmark::Fixture {
protected:
    void SetUp(benchmark::State& state) override {
        numItems = state.range(0);
        auto storage = state.range(1);

        // Initialize KVStoreConfig
        Configuration config;
        uint16_t shardId = 0;
        config.setDbname("KVStoreBench.db");
        config.setMaxSize(536870912);
        switch (storage) {
        case COUCHSTORE:
            state.SetLabel("Couchstore");
            config.setBackend("couchdb");
            kvstoreConfig = std::make_unique<KVStoreConfig>(config, shardId);
            break;
#ifdef EP_USE_ROCKSDB
        case ROCKSDB:
            state.SetLabel("CouchRocks");
            config.setBackend("rocksdb");
            kvstoreConfig =
                    std::make_unique<RocksDBKVStoreConfig>(config, shardId);
            break;
#endif
        }

        // Initialize KVStore
        kvstore = setup_kv_store(*kvstoreConfig);

        // Load some data
        const std::string key = "key";
        std::string value = "value";
        MockWriteCallback wc;
        uint16_t vbid = 0;
        kvstore->begin(std::make_unique<TransactionContext>());
        for (int i = 1; i <= numItems; i++) {
            Item item(makeStoredDocKey(key + std::to_string(i)),
                      0 /*flags*/,
                      0 /*exptime*/,
                      value.c_str(),
                      value.size(),
                      PROTOCOL_BINARY_RAW_BYTES,
                      0 /*cas*/,
                      i /*bySeqno*/,
                      vbid);
            kvstore->set(item, wc);
        }
        kvstore->commit(nullptr /*no collections manifest*/);
        // Just check that the VBucket High Seqno has been updated correctly
        EXPECT_EQ(kvstore->getVBucketState(vbid)->highSeqno, numItems);
    }

    void TearDown(const benchmark::State& state) override {
        kvstore.reset();
        cb::io::rmrf(kvstoreConfig->getDBName());
    }

private:
    std::unique_ptr<KVStore> setup_kv_store(KVStoreConfig& config) {
        auto kvstore = KVStoreFactory::create(config);
        vbucket_state state(vbucket_state_active,
                            0 /*chkid*/,
                            0 /*maxDelSeqNum*/,
                            0 /*highSeqno*/,
                            0 /*purgeSeqno*/,
                            0 /*lastSnapStart*/,
                            0 /*lastSnapEnd*/,
                            0 /*maxCas*/,
                            0 /*hlcCasEpochSeqno*/,
                            false /*mightContainXattrs*/,
                            "" /*failovers*/);
        kvstore.rw->snapshotVBucket(
                vbid, state, VBStatePersist::VBSTATE_PERSIST_WITHOUT_COMMIT);
        return std::move(kvstore.rw);
    }

protected:
    std::unique_ptr<KVStoreConfig> kvstoreConfig;
    std::unique_ptr<KVStore> kvstore;
    uint16_t vbid = 0;
    int numItems;
};

/*
 * Benchmark for KVStore::scan()
 */
BENCHMARK_DEFINE_F(KVStoreBench, Scan)(benchmark::State& state) {
    size_t itemCountTotal = 0;

    while (state.KeepRunning()) {
        // Note: the CacheCallback here just make the code to flow into reading
        // data from disk
        auto cb = std::make_shared<MockDiskCallback>();
        auto cl = std::make_shared<MockCacheCallback>();
        ScanContext* scanContext =
                kvstore->initScanContext(cb,
                                         cl,
                                         vbid,
                                         0 /*startSeqno*/,
                                         DocumentFilter::ALL_ITEMS,
                                         ValueFilter::VALUES_COMPRESSED);
        ASSERT_TRUE(scanContext);

        auto scanStatus = kvstore->scan(scanContext);
        ASSERT_EQ(scanStatus, scan_success);
        auto itemCount = cb->getItemCount();
        ASSERT_EQ(itemCount, numItems);
        itemCountTotal += itemCount;

        kvstore->destroyScanContext(scanContext);
    }

    state.SetItemsProcessed(itemCountTotal);
}

const int NUM_ITEMS = 100000;

BENCHMARK_REGISTER_F(KVStoreBench, Scan)
        ->Args({NUM_ITEMS, COUCHSTORE})
#ifdef EP_USE_ROCKSDB
        ->Args({NUM_ITEMS, ROCKSDB})
#endif
        ;
<|endoftext|>


<commit_before>/*
 * OneToManyProcessor.cpp
 */

#include "OneToManyProcessor.h"
#include "WebRtcConnection.h"
#include "rtp/RtpHeaders.h"

namespace erizo {
  DEFINE_LOGGER(OneToManyProcessor, "OneToManyProcessor");
  OneToManyProcessor::OneToManyProcessor() {
    ELOG_DEBUG ("OneToManyProcessor constructor");
    feedbackSink_ = NULL;
  }

  OneToManyProcessor::~OneToManyProcessor() {
    ELOG_DEBUG ("OneToManyProcessor destructor");
    this->closeAll();
  }

  int OneToManyProcessor::deliverAudioData_(char* buf, int len) {
 //   ELOG_DEBUG ("OneToManyProcessor deliverAudio");
    if (subscribers.empty() || len <= 0)
      return 0;

    std::map<std::string, sink_ptr>::iterator it;
    for (it = subscribers.begin(); it != subscribers.end(); ++it) {
      (*it).second->deliverAudioData(buf, len);
    }

    return 0;
  }

  int OneToManyProcessor::deliverVideoData_(char* buf, int len) {
    if (subscribers.empty() || len <= 0)
      return 0;
    RtcpHeader* head = reinterpret_cast<RtcpHeader*>(buf);
    if(head->isFeedback()){
      ELOG_WARN("Receiving Feedback in wrong path: %d", head->packettype);
      if (feedbackSink_!=NULL){
        head->ssrc = htonl(publisher->getVideoSourceSSRC());
        feedbackSink_->deliverFeedback(buf,len);
      }
      return 0;
    }
    std::map<std::string, sink_ptr>::iterator it;
    for (it = subscribers.begin(); it != subscribers.end(); ++it) {
      if((*it).second != NULL) {
        (*it).second->deliverVideoData(buf, len);
      }
    }
    return 0;
  }

  void OneToManyProcessor::setPublisher(MediaSource* webRtcConn) {
    boost::mutex::scoped_lock lock(myMonitor_);
    this->publisher.reset(webRtcConn);
    feedbackSink_ = publisher->getFeedbackSink();
  }

  int OneToManyProcessor::deliverFeedback_(char* buf, int len){
    if (feedbackSink_ != NULL){
      feedbackSink_->deliverFeedback(buf,len);
    }
    return 0;
  }

  void OneToManyProcessor::addSubscriber(MediaSink* webRtcConn,
      const std::string& peerId) {
    ELOG_DEBUG("Adding subscriber");
    boost::mutex::scoped_lock lock(myMonitor_);
    ELOG_DEBUG("From %u, %u ", publisher->getAudioSourceSSRC() , publisher->getVideoSourceSSRC());
    webRtcConn->setAudioSinkSSRC(this->publisher->getAudioSourceSSRC());
    webRtcConn->setVideoSinkSSRC(this->publisher->getVideoSourceSSRC());
    ELOG_DEBUG("Subscribers ssrcs: Audio %u, video, %u from %u, %u ", webRtcConn->getAudioSinkSSRC(), webRtcConn->getVideoSinkSSRC(), this->publisher->getAudioSourceSSRC() , this->publisher->getVideoSourceSSRC());
    FeedbackSource* fbsource = webRtcConn->getFeedbackSource();

    if (fbsource!=NULL){
      ELOG_DEBUG("adding fbsource");
      fbsource->setFeedbackSink(this);
    }
    this->subscribers[peerId] = sink_ptr(webRtcConn);
  }

  void OneToManyProcessor::removeSubscriber(const std::string& peerId) {
    ELOG_DEBUG("Remove subscriber");
    boost::mutex::scoped_lock lock(myMonitor_);
    if (this->subscribers.find(peerId) != subscribers.end()) {
      this->subscribers.erase(peerId);
    }
  }

  void OneToManyProcessor::closeAll() {
    boost::unique_lock<boost::mutex> lock(myMonitor_);
    feedbackSink_ = NULL;
    publisher.reset();
    ELOG_DEBUG ("OneToManyProcessor closeAll");
    std::map<std::string, boost::shared_ptr<MediaSink> >::iterator it = subscribers.begin();
    while (it != subscribers.end()) {
      if ((*it).second != NULL) {
        FeedbackSource* fbsource = (*it).second->getFeedbackSource();
        if (fbsource!=NULL){
          fbsource->setFeedbackSink(NULL);
        }
      }
      subscribers.erase(it++);
    }
    subscribers.clear();
    ELOG_DEBUG ("ClosedAll media in this OneToMany");
  }

}/* namespace erizo */

<commit_msg>Applied OTM changes from commit 2535090d1bfce9fe94f94c8b0e46c21c68fed0e5 in master<commit_after>/*
 * OneToManyProcessor.cpp
 */

#include "OneToManyProcessor.h"
#include "WebRtcConnection.h"
#include "rtp/RtpHeaders.h"

namespace erizo {
  DEFINE_LOGGER(OneToManyProcessor, "OneToManyProcessor");
  OneToManyProcessor::OneToManyProcessor() {
    ELOG_DEBUG ("OneToManyProcessor constructor");
    feedbackSink_ = NULL;
  }

  OneToManyProcessor::~OneToManyProcessor() {
    ELOG_DEBUG ("OneToManyProcessor destructor");
    this->closeAll();
  }

  int OneToManyProcessor::deliverAudioData_(char* buf, int len) {
 //   ELOG_DEBUG ("OneToManyProcessor deliverAudio");
    if (len <= 0)
      return 0;

    boost::unique_lock<boost::mutex> lock(myMonitor_);
    if(subscribers.empty())
      return 0;

    std::map<std::string, sink_ptr>::iterator it;
    for (it = subscribers.begin(); it != subscribers.end(); ++it) {
      (*it).second->deliverAudioData(buf, len);
    }

    return 0;
  }

  int OneToManyProcessor::deliverVideoData_(char* buf, int len) {
    if (len <= 0)
      return 0;
    RtcpHeader* head = reinterpret_cast<RtcpHeader*>(buf);
    if(head->isFeedback()){
      ELOG_WARN("Receiving Feedback in wrong path: %d", head->packettype);
      if (feedbackSink_!=NULL){
        head->ssrc = htonl(publisher->getVideoSourceSSRC());
        feedbackSink_->deliverFeedback(buf,len);
      }
      return 0;
    }
    boost::unique_lock<boost::mutex> lock(myMonitor_);
    if (subscribers.empty())
      return 0;
    std::map<std::string, sink_ptr>::iterator it;
    for (it = subscribers.begin(); it != subscribers.end(); ++it) {
      if((*it).second != NULL) {
        (*it).second->deliverVideoData(buf, len);
      }
    }
    return 0;
  }

  void OneToManyProcessor::setPublisher(MediaSource* webRtcConn) {
    boost::mutex::scoped_lock lock(myMonitor_);
    this->publisher.reset(webRtcConn);
    feedbackSink_ = publisher->getFeedbackSink();
  }

  int OneToManyProcessor::deliverFeedback_(char* buf, int len){
    if (feedbackSink_ != NULL){
      feedbackSink_->deliverFeedback(buf,len);
    }
    return 0;
  }

  void OneToManyProcessor::addSubscriber(MediaSink* webRtcConn,
      const std::string& peerId) {
    ELOG_DEBUG("Adding subscriber");
    boost::mutex::scoped_lock lock(myMonitor_);
    ELOG_DEBUG("From %u, %u ", publisher->getAudioSourceSSRC() , publisher->getVideoSourceSSRC());
    webRtcConn->setAudioSinkSSRC(this->publisher->getAudioSourceSSRC());
    webRtcConn->setVideoSinkSSRC(this->publisher->getVideoSourceSSRC());
    ELOG_DEBUG("Subscribers ssrcs: Audio %u, video, %u from %u, %u ", webRtcConn->getAudioSinkSSRC(), webRtcConn->getVideoSinkSSRC(), this->publisher->getAudioSourceSSRC() , this->publisher->getVideoSourceSSRC());
    FeedbackSource* fbsource = webRtcConn->getFeedbackSource();

    if (fbsource!=NULL){
      ELOG_DEBUG("adding fbsource");
      fbsource->setFeedbackSink(this);
    }
    this->subscribers[peerId] = sink_ptr(webRtcConn);
  }

  void OneToManyProcessor::removeSubscriber(const std::string& peerId) {
    ELOG_DEBUG("Remove subscriber");
    boost::mutex::scoped_lock lock(myMonitor_);
    if (this->subscribers.find(peerId) != subscribers.end()) {
      this->subscribers.erase(peerId);
    }
  }

  void OneToManyProcessor::closeAll() {
    ELOG_DEBUG ("OneToManyProcessor closeAll");
    feedbackSink_ = NULL;
    publisher.reset();
    boost::unique_lock<boost::mutex> lock(myMonitor_);
    std::map<std::string, boost::shared_ptr<MediaSink> >::iterator it = subscribers.begin();
    while (it != subscribers.end()) {
      if ((*it).second != NULL) {
        FeedbackSource* fbsource = (*it).second->getFeedbackSource();
        if (fbsource!=NULL){
          fbsource->setFeedbackSink(NULL);
        }
      }
      subscribers.erase(it++);
    }
    subscribers.clear();
    ELOG_DEBUG ("ClosedAll media in this OneToMany");
  }

}/* namespace erizo */

<|endoftext|>


<commit_before><commit_msg>Cleanup: Remove some unnecessary breaks.<commit_after><|endoftext|>


<commit_before><commit_msg>Remove unused variable.<commit_after><|endoftext|>


<commit_before><commit_msg>Fix wrong comparison detected by updated tests<commit_after><|endoftext|>


<commit_before><commit_msg>fix an error when updating refernece list<commit_after><|endoftext|>


<commit_before><commit_msg>[sensorfw] Contributes JB#27912 remove debug output<commit_after><|endoftext|>


<commit_before>// Copyright 2010-2014 Google
// 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.

// Reader and solver for the shift minimization personnel task
// scheduling problem (see
// https://publications.csiro.au/rpr/download?pid=csiro:EP104071&dsid=DS2)/
//
// Data files are in
//    /cns/li-d/home/operations-research/shift_minization_scheduling
//
// The problem is the following:
//   - There is a list of jobs. Each job has a start date and an end date. They
//     must all be performed.
//   - There is a set of workers. Each worker can perform on or more jobs among
//     a subset of job. One worker cannot perform two jobs that overlaps.
//   - The objective it to minimize the number of active workers, while
//     performing all the jobs.

#include <set>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>

#include "ortools/base/commandlineflags.h"
#include "ortools/base/commandlineflags.h"
#include "ortools/base/logging.h"
#include "ortools/base/strtoint.h"
#include "ortools/util/filelineiter.h"
#include "ortools/base/split.h"
#include "ortools/sat/cp_constraints.h"
#include "ortools/sat/integer_expr.h"
#include "ortools/sat/model.h"
#include "ortools/sat/optimization.h"
#include "ortools/sat/precedences.h"
#include "ortools/sat/sat_solver.h"

DEFINE_string(input, "", "Input file.");
DEFINE_string(params, "", "Sat parameters in text proto format.");
DEFINE_bool(use_core, false, "Use the core based solver.");

namespace operations_research {
namespace sat {
class ShiftMinimizationParser {
 public:
  struct Job {
    int start;
    int end;
  };

  struct Assignment {
    int worker_id;
    int job_index;
  };

  ShiftMinimizationParser()
      : load_status_(NOT_STARTED),
        declared_num_jobs_(0),
        declared_num_workers_(0),
        num_workers_read_(0) {}

  const std::vector<Job>& jobs() const { return jobs_; }
  const std::vector<std::vector<int>>& possible_jobs_per_worker() const {
    return possible_jobs_per_worker_;
  }
  const std::vector<std::vector<Assignment>>& possible_assignments_per_job()
      const {
    return possible_assignments_per_job_;
  }

  // The file format is the following
  // # comments...
  // Type = 1
  // Jobs = <n>
  // <start> <end>  // Repeated n times
  // Qualifications = <k>
  // c: job_1 .. job_c  // repeated k times (a counter and job ids after).
  bool LoadFile(const std::string& file_name) {
    if (load_status_ != NOT_STARTED) {
      return false;
    }

    File* file = nullptr;
    if (!file::Open(file_name, "r", &file, file::Defaults()).ok()) {
      LOG(WARNING) << "Can't open " << file_name;
      return false;
    }

    load_status_ = STARTED;

    for (const std::string& line :
         FileLines(file_name, FileLineIterator::REMOVE_INLINE_CR)) {
      ProcessLine(line);
    }

    LOG(INFO) << "Read file " << file_name << " with " << declared_num_jobs_
              << " jobs, and " << declared_num_workers_ << " workers.";
    return declared_num_jobs_ != 0 && jobs_.size() == declared_num_jobs_ &&
           declared_num_workers_ != 0 &&
           declared_num_workers_ == num_workers_read_;
  }

 private:
  enum LoadStatus { NOT_STARTED, STARTED, JOBS_SEEN, WORKERS_SEEN };

  void ProcessLine(const std::string& line) {
    if (line.empty() || line[0] == '#') {
      return;
    }

    const std::vector<std::string> words = strings::Split(
        line, strings::delimiter::AnyOf(" :\t"), strings::SkipEmpty());

    switch (load_status_) {
      case NOT_STARTED: {
        LOG(FATAL) << "Wrong status: NOT_STARTED";
        break;
      }
      case STARTED: {
        if (words.size() == 3 && words[0] == "Type") {
          CHECK_EQ(1, atoi32(words[2]));
        } else if (words.size() == 3 && words[0] == "Jobs") {
          declared_num_jobs_ = atoi32(words[2]);
          possible_assignments_per_job_.resize(declared_num_jobs_);
          load_status_ = JOBS_SEEN;
        } else {
          LOG(FATAL) << "Wrong state STARTED with line " << line;
        }
        break;
      }
      case JOBS_SEEN: {
        if (words.size() == 2) {
          jobs_.push_back({atoi32(words[0]), atoi32(words[1])});
        } else if (words.size() == 3 && words[0] == "Qualifications") {
          declared_num_workers_ = atoi32(words[2]);
          possible_jobs_per_worker_.resize(declared_num_workers_);
          load_status_ = WORKERS_SEEN;
        } else {
          LOG(FATAL) << "Wrong state JOBS_SEEN with line " << line;
        }
        break;
      }
      case WORKERS_SEEN: {
        CHECK_EQ(atoi32(words[0]), words.size() - 1);
        for (int i = 1; i < words.size(); ++i) {
          const int job = atoi32(words[i]);
          const int pos = possible_jobs_per_worker_[num_workers_read_].size();
          possible_jobs_per_worker_[num_workers_read_].push_back(job);
          possible_assignments_per_job_[job].push_back(
              {num_workers_read_, pos});
        }
        num_workers_read_++;
        break;
      }
    }
  }

  std::vector<Job> jobs_;
  std::vector<std::vector<int>> possible_jobs_per_worker_;
  std::vector<std::vector<Assignment>> possible_assignments_per_job_;
  LoadStatus load_status_;
  int declared_num_jobs_;
  int declared_num_workers_;
  int num_workers_read_;
};

bool Overlaps(const ShiftMinimizationParser::Job& j1,
              const ShiftMinimizationParser::Job& j2) {
  // TODO(user): Are end date inclusive or exclusive? To check.
  // For now, we assume that they are exclusive.
  return !(j1.start > j2.end || j2.start > j1.end);
}

void LoadAndSolve(const std::string& file_name) {
  ShiftMinimizationParser parser;
  CHECK(parser.LoadFile(file_name));

  Model model;
  model.Add(NewSatParameters(FLAGS_params));

  const int num_workers = parser.possible_jobs_per_worker().size();
  const std::vector<ShiftMinimizationParser::Job>& jobs = parser.jobs();
  const int num_jobs = jobs.size();

  std::vector<Literal> active_workers(num_workers);
  std::vector<std::vector<Literal>> worker_job_literals(num_workers);
  std::vector<std::vector<Literal>> selected_workers_per_job(num_jobs);

  for (int w = 0; w < num_workers; ++w) {
    // Status variables for workers, are they active or not?
    active_workers[w] = Literal(model.Add(NewBooleanVariable()), true);

    // Job-Worker literal. worker_job_literals[w][i] is true iff worker w
    // performs it's ith possible job.
    const std::vector<int>& possible = parser.possible_jobs_per_worker()[w];
    for (int p : possible) {
      worker_job_literals[w].push_back(
          Literal(model.Add(NewBooleanVariable()), true));
      selected_workers_per_job[p].push_back(worker_job_literals[w].back());
    }

    // Add conflicts on overlapping jobs for the same worker.
    for (int i = 0; i < possible.size() - 1; ++i) {
      for (int j = i + 1; j < possible.size(); ++j) {
        const int job1 = possible[i];
        const int job2 = possible[j];
        if (Overlaps(jobs[job1], jobs[job2])) {
          const Literal l1 = worker_job_literals[w][i];
          const Literal l2 = worker_job_literals[w][j];
          model.Add(ClauseConstraint({l1.Negated(), l2.Negated()}));
        }
      }
    }

    // Maintain active_workers variable.
    model.Add(ReifiedBoolOr(worker_job_literals[w], active_workers[w]));
  }

  // All jobs must be performed.
  for (int j = 0; j < num_jobs; ++j) {
    // this does not enforce that at most one worker performs one job.
    // It should not change the solution cost.
    // TODO(user): Checks if sum() == 1 improves the solving speed.
    model.Add(ClauseConstraint(selected_workers_per_job[j]));
  }

  // Redundant constraint:
  //   For each time point, count the number of active jobs at that time,
  //   then the number of active workers on these jobs is equal to the number of
  //   active jobs.
  std::set<int> time_points;
  std::set<std::vector<int>> visited_job_lists;
  std::map<std::vector<Literal>, Literal> active_literal_cache;

  for (int j = 0; j < num_jobs; ++j) {
    time_points.insert(parser.jobs()[j].start);
    time_points.insert(parser.jobs()[j].end);
  }

  int num_reused_literals = 0;
  int num_count_constraints = 0;
  int max_intersection_size = 0;

  // Add one counting constraint per time point.
  for (int t : time_points) {
    // Collect all jobs that intersects with this time point.
    std::vector<int> intersecting_jobs;
    for (int j = 0; j < num_jobs; ++j) {
      const ShiftMinimizationParser::Job& job = parser.jobs()[j];
      // Assumption: End date are inclusive.
      if (t >= job.start && t <= job.end) {
        intersecting_jobs.push_back(j);
      }
    }

    // Check that we have not already visited this exact set of candidate jobs.
    if (ContainsKey(visited_job_lists, intersecting_jobs)) continue;
    visited_job_lists.insert(intersecting_jobs);

    // Collect the relevant literals, and regroup them per worker.
    std::map<int, std::vector<Literal>> active_literals_per_workers;
    for (int j : intersecting_jobs) {
      for (const auto& p : parser.possible_assignments_per_job()[j]) {
        const Literal lit = worker_job_literals[p.worker_id][p.job_index];
        active_literals_per_workers[p.worker_id].push_back(lit);
      }
    }

    // Create the worker activity variables.
    std::vector<Literal> active_worker_literals;
    for (const auto& it : active_literals_per_workers) {
      Literal active;
      if (ContainsKey(active_literal_cache, it.second)) {
        active = active_literal_cache[it.second];
        num_reused_literals++;
      } else {
        active = Literal(model.Add(NewBooleanVariable()), true);
        model.Add(Implication(active, active_workers[it.first]));
        model.Add(ReifiedBoolOr(it.second, active));
        active_literal_cache[it.second] = active;
      }

      active_worker_literals.push_back(active);
    }

    // Add the count constraints: We have as many active workers as jobs.
    num_count_constraints++;
    const int num_jobs = intersecting_jobs.size();
    max_intersection_size = std::max(max_intersection_size, num_jobs);
    model.Add(
        CardinalityConstraint(num_jobs, num_jobs, active_worker_literals));
  }

  LOG(INFO) << "Added " << num_count_constraints
            << " count constraints while processing " << time_points.size()
            << " time points.";
  LOG(INFO) << "This has created " << active_literal_cache.size()
            << " active worker literals, and reused them "
            << num_reused_literals << " times.";
  LOG(INFO) << "Lower bound = " << max_intersection_size;

  if (FLAGS_use_core) {
    const std::vector<int64> coeffs(num_workers, 1);
    MinimizeWeightedLiteralSumWithCoreAndLazyEncoding(
        /*log_info=*/true, active_workers, coeffs, nullptr, nullptr, &model);
    return;
  }

  // Objective.
  std::vector<int> weights(num_workers, 1);
  std::vector<IntegerVariable> worker_vars(num_workers);
  for (int w = 0; w < num_workers; ++w) {
    worker_vars[w] =
        model.Add(NewIntegerVariableFromLiteral(active_workers[w]));
  }
  const IntegerVariable objective_var =
      model.Add(NewIntegerVariable(max_intersection_size, num_workers));
  weights.push_back(-1);
  worker_vars.push_back(objective_var);

  model.Add(FixedWeightedSum(worker_vars, weights, 0));

  MinimizeIntegerVariableWithLinearScanAndLazyEncoding(
      /*log_info=*/true, objective_var, nullptr,
      /*feasible_solution_observer=*/
      [&](const Model& model) {
        LOG(INFO) << "Cost " << model.Get(Value(objective_var));
      },
      &model);
}
}  // namespace sat
}  // namespace operations_research

int main(int argc, char** argv) {
  gflags::ParseCommandLineFlags( &argc, &argv, true);
  if (FLAGS_input.empty()) {
    LOG(FATAL) << "Please supply a data file with --input=";
  }

  operations_research::sat::LoadAndSolve(FLAGS_input);
  return EXIT_SUCCESS;
}
<commit_msg>fix example after removal of code in sat<commit_after>// Copyright 2010-2014 Google
// 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.

// Reader and solver for the shift minimization personnel task
// scheduling problem (see
// https://publications.csiro.au/rpr/download?pid=csiro:EP104071&dsid=DS2)/
//
// Data files are in
//    /cns/li-d/home/operations-research/shift_minization_scheduling
//
// The problem is the following:
//   - There is a list of jobs. Each job has a start date and an end date. They
//     must all be performed.
//   - There is a set of workers. Each worker can perform on or more jobs among
//     a subset of job. One worker cannot perform two jobs that overlaps.
//   - The objective it to minimize the number of active workers, while
//     performing all the jobs.

#include <set>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>

#include "ortools/base/commandlineflags.h"
#include "ortools/base/commandlineflags.h"
#include "ortools/base/logging.h"
#include "ortools/base/strtoint.h"
#include "ortools/util/filelineiter.h"
#include "ortools/base/split.h"
#include "ortools/sat/cp_constraints.h"
#include "ortools/sat/integer_expr.h"
#include "ortools/sat/model.h"
#include "ortools/sat/optimization.h"
#include "ortools/sat/precedences.h"
#include "ortools/sat/sat_solver.h"

DEFINE_string(input, "", "Input file.");
DEFINE_string(params, "", "Sat parameters in text proto format.");

namespace operations_research {
namespace sat {
class ShiftMinimizationParser {
 public:
  struct Job {
    int start;
    int end;
  };

  struct Assignment {
    int worker_id;
    int job_index;
  };

  ShiftMinimizationParser()
      : load_status_(NOT_STARTED),
        declared_num_jobs_(0),
        declared_num_workers_(0),
        num_workers_read_(0) {}

  const std::vector<Job>& jobs() const { return jobs_; }
  const std::vector<std::vector<int>>& possible_jobs_per_worker() const {
    return possible_jobs_per_worker_;
  }
  const std::vector<std::vector<Assignment>>& possible_assignments_per_job()
      const {
    return possible_assignments_per_job_;
  }

  // The file format is the following
  // # comments...
  // Type = 1
  // Jobs = <n>
  // <start> <end>  // Repeated n times
  // Qualifications = <k>
  // c: job_1 .. job_c  // repeated k times (a counter and job ids after).
  bool LoadFile(const std::string& file_name) {
    if (load_status_ != NOT_STARTED) {
      return false;
    }

    File* file = nullptr;
    if (!file::Open(file_name, "r", &file, file::Defaults()).ok()) {
      LOG(WARNING) << "Can't open " << file_name;
      return false;
    }

    load_status_ = STARTED;

    for (const std::string& line :
         FileLines(file_name, FileLineIterator::REMOVE_INLINE_CR)) {
      ProcessLine(line);
    }

    LOG(INFO) << "Read file " << file_name << " with " << declared_num_jobs_
              << " jobs, and " << declared_num_workers_ << " workers.";
    return declared_num_jobs_ != 0 && jobs_.size() == declared_num_jobs_ &&
           declared_num_workers_ != 0 &&
           declared_num_workers_ == num_workers_read_;
  }

 private:
  enum LoadStatus { NOT_STARTED, STARTED, JOBS_SEEN, WORKERS_SEEN };

  void ProcessLine(const std::string& line) {
    if (line.empty() || line[0] == '#') {
      return;
    }

    const std::vector<std::string> words = strings::Split(
        line, strings::delimiter::AnyOf(" :\t"), strings::SkipEmpty());

    switch (load_status_) {
      case NOT_STARTED: {
        LOG(FATAL) << "Wrong status: NOT_STARTED";
        break;
      }
      case STARTED: {
        if (words.size() == 3 && words[0] == "Type") {
          CHECK_EQ(1, atoi32(words[2]));
        } else if (words.size() == 3 && words[0] == "Jobs") {
          declared_num_jobs_ = atoi32(words[2]);
          possible_assignments_per_job_.resize(declared_num_jobs_);
          load_status_ = JOBS_SEEN;
        } else {
          LOG(FATAL) << "Wrong state STARTED with line " << line;
        }
        break;
      }
      case JOBS_SEEN: {
        if (words.size() == 2) {
          jobs_.push_back({atoi32(words[0]), atoi32(words[1])});
        } else if (words.size() == 3 && words[0] == "Qualifications") {
          declared_num_workers_ = atoi32(words[2]);
          possible_jobs_per_worker_.resize(declared_num_workers_);
          load_status_ = WORKERS_SEEN;
        } else {
          LOG(FATAL) << "Wrong state JOBS_SEEN with line " << line;
        }
        break;
      }
      case WORKERS_SEEN: {
        CHECK_EQ(atoi32(words[0]), words.size() - 1);
        for (int i = 1; i < words.size(); ++i) {
          const int job = atoi32(words[i]);
          const int pos = possible_jobs_per_worker_[num_workers_read_].size();
          possible_jobs_per_worker_[num_workers_read_].push_back(job);
          possible_assignments_per_job_[job].push_back(
              {num_workers_read_, pos});
        }
        num_workers_read_++;
        break;
      }
    }
  }

  std::vector<Job> jobs_;
  std::vector<std::vector<int>> possible_jobs_per_worker_;
  std::vector<std::vector<Assignment>> possible_assignments_per_job_;
  LoadStatus load_status_;
  int declared_num_jobs_;
  int declared_num_workers_;
  int num_workers_read_;
};

bool Overlaps(const ShiftMinimizationParser::Job& j1,
              const ShiftMinimizationParser::Job& j2) {
  // TODO(user): Are end date inclusive or exclusive? To check.
  // For now, we assume that they are exclusive.
  return !(j1.start > j2.end || j2.start > j1.end);
}

void LoadAndSolve(const std::string& file_name) {
  ShiftMinimizationParser parser;
  CHECK(parser.LoadFile(file_name));

  Model model;
  model.Add(NewSatParameters(FLAGS_params));

  const int num_workers = parser.possible_jobs_per_worker().size();
  const std::vector<ShiftMinimizationParser::Job>& jobs = parser.jobs();
  const int num_jobs = jobs.size();

  std::vector<Literal> active_workers(num_workers);
  std::vector<std::vector<Literal>> worker_job_literals(num_workers);
  std::vector<std::vector<Literal>> selected_workers_per_job(num_jobs);

  for (int w = 0; w < num_workers; ++w) {
    // Status variables for workers, are they active or not?
    active_workers[w] = Literal(model.Add(NewBooleanVariable()), true);

    // Job-Worker literal. worker_job_literals[w][i] is true iff worker w
    // performs it's ith possible job.
    const std::vector<int>& possible = parser.possible_jobs_per_worker()[w];
    for (int p : possible) {
      worker_job_literals[w].push_back(
          Literal(model.Add(NewBooleanVariable()), true));
      selected_workers_per_job[p].push_back(worker_job_literals[w].back());
    }

    // Add conflicts on overlapping jobs for the same worker.
    for (int i = 0; i < possible.size() - 1; ++i) {
      for (int j = i + 1; j < possible.size(); ++j) {
        const int job1 = possible[i];
        const int job2 = possible[j];
        if (Overlaps(jobs[job1], jobs[job2])) {
          const Literal l1 = worker_job_literals[w][i];
          const Literal l2 = worker_job_literals[w][j];
          model.Add(ClauseConstraint({l1.Negated(), l2.Negated()}));
        }
      }
    }

    // Maintain active_workers variable.
    model.Add(ReifiedBoolOr(worker_job_literals[w], active_workers[w]));
  }

  // All jobs must be performed.
  for (int j = 0; j < num_jobs; ++j) {
    // this does not enforce that at most one worker performs one job.
    // It should not change the solution cost.
    // TODO(user): Checks if sum() == 1 improves the solving speed.
    model.Add(ClauseConstraint(selected_workers_per_job[j]));
  }

  // Redundant constraint:
  //   For each time point, count the number of active jobs at that time,
  //   then the number of active workers on these jobs is equal to the number of
  //   active jobs.
  std::set<int> time_points;
  std::set<std::vector<int>> visited_job_lists;
  std::map<std::vector<Literal>, Literal> active_literal_cache;

  for (int j = 0; j < num_jobs; ++j) {
    time_points.insert(parser.jobs()[j].start);
    time_points.insert(parser.jobs()[j].end);
  }

  int num_reused_literals = 0;
  int num_count_constraints = 0;
  int max_intersection_size = 0;

  // Add one counting constraint per time point.
  for (int t : time_points) {
    // Collect all jobs that intersects with this time point.
    std::vector<int> intersecting_jobs;
    for (int j = 0; j < num_jobs; ++j) {
      const ShiftMinimizationParser::Job& job = parser.jobs()[j];
      // Assumption: End date are inclusive.
      if (t >= job.start && t <= job.end) {
        intersecting_jobs.push_back(j);
      }
    }

    // Check that we have not already visited this exact set of candidate jobs.
    if (ContainsKey(visited_job_lists, intersecting_jobs)) continue;
    visited_job_lists.insert(intersecting_jobs);

    // Collect the relevant literals, and regroup them per worker.
    std::map<int, std::vector<Literal>> active_literals_per_workers;
    for (int j : intersecting_jobs) {
      for (const auto& p : parser.possible_assignments_per_job()[j]) {
        const Literal lit = worker_job_literals[p.worker_id][p.job_index];
        active_literals_per_workers[p.worker_id].push_back(lit);
      }
    }

    // Create the worker activity variables.
    std::vector<Literal> active_worker_literals;
    for (const auto& it : active_literals_per_workers) {
      Literal active;
      if (ContainsKey(active_literal_cache, it.second)) {
        active = active_literal_cache[it.second];
        num_reused_literals++;
      } else {
        active = Literal(model.Add(NewBooleanVariable()), true);
        model.Add(Implication(active, active_workers[it.first]));
        model.Add(ReifiedBoolOr(it.second, active));
        active_literal_cache[it.second] = active;
      }

      active_worker_literals.push_back(active);
    }

    // Add the count constraints: We have as many active workers as jobs.
    num_count_constraints++;
    const int num_jobs = intersecting_jobs.size();
    max_intersection_size = std::max(max_intersection_size, num_jobs);
    model.Add(
        CardinalityConstraint(num_jobs, num_jobs, active_worker_literals));
  }

  LOG(INFO) << "Added " << num_count_constraints
            << " count constraints while processing " << time_points.size()
            << " time points.";
  LOG(INFO) << "This has created " << active_literal_cache.size()
            << " active worker literals, and reused them "
            << num_reused_literals << " times.";
  LOG(INFO) << "Lower bound = " << max_intersection_size;

  // Objective.
  std::vector<int> weights(num_workers, 1);
  std::vector<IntegerVariable> worker_vars(num_workers);
  for (int w = 0; w < num_workers; ++w) {
    worker_vars[w] =
        model.Add(NewIntegerVariableFromLiteral(active_workers[w]));
  }
  const IntegerVariable objective_var =
      model.Add(NewIntegerVariable(max_intersection_size, num_workers));
  weights.push_back(-1);
  worker_vars.push_back(objective_var);

  model.Add(FixedWeightedSum(worker_vars, weights, 0));

  MinimizeIntegerVariableWithLinearScanAndLazyEncoding(
      /*log_info=*/true, objective_var, nullptr,
      /*feasible_solution_observer=*/
      [&](const Model& model) {
        LOG(INFO) << "Cost " << model.Get(Value(objective_var));
      },
      &model);
}
}  // namespace sat
}  // namespace operations_research

int main(int argc, char** argv) {
  gflags::ParseCommandLineFlags( &argc, &argv, true);
  if (FLAGS_input.empty()) {
    LOG(FATAL) << "Please supply a data file with --input=";
  }

  operations_research::sat::LoadAndSolve(FLAGS_input);
  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>/*!
    \file errors_exceptions_handler.cpp
    \brief Exceptions handler example
    \author Ivan Shynkarenka
    \date 22.04.2016
    \copyright MIT License
*/

#include "errors/exceptions_handler.h"
#include "system/stack_trace_manager.h"

#include <cfloat>
#include <csignal>
#include <exception>
#include <iostream>
#include <string>
#include <thread>

#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#elif defined(linux) || defined(__linux) || defined(__linux__)
#include <fenv.h>
#endif

void GenerateSIGABRT()
{
    abort();
}

void GenerateSIGFPE()
{
    // Code taken from http://www.devx.com/cplus/Article/34993/1954

#if defined(_WIN32) || defined(_WIN64)
    // Set the x86 floating-point control word according to what
    // exceptions you want to trap. Always call _clearfp before
    // setting the control word
    _clearfp();

    // Because the second parameter in the following call is 0, it
    // only returns the floating-point control word.
    unsigned int cw;
    _controlfp_s(&cw, 0, 0);

    // Set the exception masks off for exceptions that you want to
    // trap. When a mask bit is set, the corresponding floating-point
    // exception is blocked from being generating.
    cw &= ~(EM_OVERFLOW | EM_UNDERFLOW | EM_ZERODIVIDE | EM_DENORMAL | EM_INVALID);

    // For any bit in the second parameter (mask) that is 1, the
    // corresponding bit in the first parameter is used to update
    // the control word.
    unsigned int cwOriginal;
    _controlfp_s(&cwOriginal, cw, MCW_EM);

    // MCW_EM is defined in float.h.
    // Restore the original value when done:
    // _controlfp(cwOriginal, MCW_EM);
#elif defined(linux) || defined(__linux) || defined(__linux__)
    fenv_t newval;
    fegetenv(&newval);
    newval.__control_word &= ~(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW);
    fesetenv(&newval);
#endif

    // Divide by zero
    float a = 1;
    float b = 0;
    float c = a / b;
    a = c;
}

void GenerateSIGILL()
{
    raise(SIGILL);
}

void GenerateSIGINT()
{
    raise(SIGINT);
}

void GenerateSIGSEGV()
{
    raise(SIGSEGV);
}

void GenerateSIGTERM()
{
    raise(SIGTERM);
}

void GenerateExit()
{
    exit(0);
}

void GenerateTerminate()
{
    std::terminate();
}

void GenerateUnexpected()
{
    std::unexpected();
}

void GenerateExceptionThrow()
{
    throw std::exception();
}

#if defined(_WIN32) || defined(_WIN64)
void GenerateInvalidParameter()
{
    char* format = nullptr;
    printf(format);
}

#pragma warning(push)
// VS 4717: 'function' : recursive on all control paths, function will cause runtime stack overflow
#pragma warning(disable: 4717)
void GenerateRecurseAlloc()
{
    char* buffer = new char[0x1FFFFFFF];
    buffer;
    GenerateRecurseAlloc();
}
#pragma warning(pop)

class Base;

void function(Base* instance);

class Base
{
public:
    Base() { function(this); }
    virtual void method(void) = 0;
};

class Derived : public Base
{
public:
    void method(void) override {}
};

void function(Base* instance)
{
    instance->method();
}

void GeneratePureVirtualMethodCall()
{
    Derived derived;
}

void GenerateSEH()
{
    int* p = nullptr;
#pragma warning(push)
// VS 6011: dereferencing NULL pointer <name>
#pragma warning(disable: 6011)
    *p = 0;
#pragma warning(pop)
}

void GenerateRaiseException()
{
    RaiseException(123, EXCEPTION_NONCONTINUABLE, 0, nullptr);
}
#endif

void GenerateCustomException(int type)
{
    switch (type)
    {
        case 1:
            GenerateSIGABRT();
            break;
        case 2:
            GenerateSIGFPE();
            break;
        case 3:
            GenerateSIGILL();
            break;
        case 4:
            GenerateSIGINT();
            break;
        case 5:
            GenerateSIGSEGV();
            break;
        case 6:
            GenerateSIGTERM();
            break;
        case 7:
            GenerateExit();
            break;
        case 8:
            GenerateTerminate();
            break;
        case 9:
            GenerateUnexpected();
            break;
        case 10:
            GenerateExceptionThrow();
            break;
#if defined(_WIN32) || defined(_WIN64)
        case 11:
            GenerateInvalidParameter();
            break;
        case 12:
            GenerateRecurseAlloc();
            break;
        case 13:
            GeneratePureVirtualMethodCall();
            break;
        case 14:
            GenerateSEH();
            break;
        case 15:
            GenerateRaiseException();
            break;
#endif
    }
}

void GenerateCustomException(int type, bool thread)
{
    auto function = [=]()
    {
        // Setup exceptions handler for the created thread
        if (thread)
            CppCommon::ExceptionsHandler::SetupThread();

        GenerateCustomException(type);
    };

    if (thread)
        std::thread(function).join();
    else
        function();
}

int main(int argc, char** argv)
{
    // Initialize stack trace manager of the current process
    CppCommon::StackTraceManager::Initialize();
    // Setup exceptions handler for the current process
    CppCommon::ExceptionsHandler::SetupProcess();

    std::cout << "1 - SIGABRT" << std::endl;
    std::cout << "2 - SIGFPE" << std::endl;
    std::cout << "3 - SIGILL" << std::endl;
    std::cout << "4 - SIGINT" << std::endl;
    std::cout << "5 - SIGSEGV" << std::endl;
    std::cout << "6 - SIGTERM" << std::endl;
    std::cout << "7 - exit" << std::endl;
    std::cout << "8 - terminate" << std::endl;
    std::cout << "9 - unexpected" << std::endl;
    std::cout << "10 - exception throw" << std::endl;
#if defined(_WIN32) || defined(_WIN64)
    std::cout << "11 - invalid parameter" << std::endl;
    std::cout << "12 - new operator fault" << std::endl;
    std::cout << "13 - pure virtual method call" << std::endl;
    std::cout << "14 - SEH exception" << std::endl;
    std::cout << "15 - RaiseException()" << std::endl;
#endif
    std::cout << "Choose an exception type: ";

    std::string line;
    if (getline(std::cin, line))
    {
        int type = std::stoi(line);
        GenerateCustomException(type, true);
    }

    // Cleanup stack trace manager of the current process
    CppCommon::StackTraceManager::Cleanup();

    return 0;
}
<commit_msg>Fix linux build<commit_after>/*!
    \file errors_exceptions_handler.cpp
    \brief Exceptions handler example
    \author Ivan Shynkarenka
    \date 22.04.2016
    \copyright MIT License
*/

#include "errors/exceptions_handler.h"
#include "system/stack_trace_manager.h"

#include <cfloat>
#include <csignal>
#include <exception>
#include <iostream>
#include <string>
#include <thread>

#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#elif defined(linux) || defined(__linux) || defined(__linux__)
#include <fenv.h>
#endif

void GenerateSIGABRT()
{
    abort();
}

void GenerateSIGFPE()
{
    // Code taken from http://www.devx.com/cplus/Article/34993/1954

#if defined(_WIN32) || defined(_WIN64)
    // Set the x86 floating-point control word according to what
    // exceptions you want to trap. Always call _clearfp before
    // setting the control word
    _clearfp();

    // Because the second parameter in the following call is 0, it
    // only returns the floating-point control word.
    unsigned int cw;
    _controlfp_s(&cw, 0, 0);

    // Set the exception masks off for exceptions that you want to
    // trap. When a mask bit is set, the corresponding floating-point
    // exception is blocked from being generating.
    cw &= ~(EM_OVERFLOW | EM_UNDERFLOW | EM_ZERODIVIDE | EM_DENORMAL | EM_INVALID);

    // For any bit in the second parameter (mask) that is 1, the
    // corresponding bit in the first parameter is used to update
    // the control word.
    unsigned int cwOriginal;
    _controlfp_s(&cwOriginal, cw, MCW_EM);

    // MCW_EM is defined in float.h.
    // Restore the original value when done:
    // _controlfp(cwOriginal, MCW_EM);
#elif defined(linux) || defined(__linux) || defined(__linux__)
    fenv_t fenv;
    fegetenv(&fenv);
    fenv.__control &= ~(FE_OVERFLOW | FE_UNDERFLOW | FE_ZERODIVIDE | FE_DENORMAL | FE_INVALID);
    fesetenv(&fenv);
#endif

    // Divide by zero
    float a = 1;
    float b = 0;
    float c = a / b;
    a = c;
}

void GenerateSIGILL()
{
    raise(SIGILL);
}

void GenerateSIGINT()
{
    raise(SIGINT);
}

void GenerateSIGSEGV()
{
    raise(SIGSEGV);
}

void GenerateSIGTERM()
{
    raise(SIGTERM);
}

void GenerateExit()
{
    exit(0);
}

void GenerateTerminate()
{
    std::terminate();
}

void GenerateUnexpected()
{
    std::unexpected();
}

void GenerateExceptionThrow()
{
    throw std::exception();
}

#if defined(_WIN32) || defined(_WIN64)
void GenerateInvalidParameter()
{
    char* format = nullptr;
    printf(format);
}

#pragma warning(push)
// VS 4717: 'function' : recursive on all control paths, function will cause runtime stack overflow
#pragma warning(disable: 4717)
void GenerateRecurseAlloc()
{
    char* buffer = new char[0x1FFFFFFF];
    buffer;
    GenerateRecurseAlloc();
}
#pragma warning(pop)

class Base;

void function(Base* instance);

class Base
{
public:
    Base() { function(this); }
    virtual void method(void) = 0;
};

class Derived : public Base
{
public:
    void method(void) override {}
};

void function(Base* instance)
{
    instance->method();
}

void GeneratePureVirtualMethodCall()
{
    Derived derived;
}

void GenerateSEH()
{
    int* p = nullptr;
#pragma warning(push)
// VS 6011: dereferencing NULL pointer <name>
#pragma warning(disable: 6011)
    *p = 0;
#pragma warning(pop)
}

void GenerateRaiseException()
{
    RaiseException(123, EXCEPTION_NONCONTINUABLE, 0, nullptr);
}
#endif

void GenerateCustomException(int type)
{
    switch (type)
    {
        case 1:
            GenerateSIGABRT();
            break;
        case 2:
            GenerateSIGFPE();
            break;
        case 3:
            GenerateSIGILL();
            break;
        case 4:
            GenerateSIGINT();
            break;
        case 5:
            GenerateSIGSEGV();
            break;
        case 6:
            GenerateSIGTERM();
            break;
        case 7:
            GenerateExit();
            break;
        case 8:
            GenerateTerminate();
            break;
        case 9:
            GenerateUnexpected();
            break;
        case 10:
            GenerateExceptionThrow();
            break;
#if defined(_WIN32) || defined(_WIN64)
        case 11:
            GenerateInvalidParameter();
            break;
        case 12:
            GenerateRecurseAlloc();
            break;
        case 13:
            GeneratePureVirtualMethodCall();
            break;
        case 14:
            GenerateSEH();
            break;
        case 15:
            GenerateRaiseException();
            break;
#endif
    }
}

void GenerateCustomException(int type, bool thread)
{
    auto function = [=]()
    {
        // Setup exceptions handler for the created thread
        if (thread)
            CppCommon::ExceptionsHandler::SetupThread();

        GenerateCustomException(type);
    };

    if (thread)
        std::thread(function).join();
    else
        function();
}

int main(int argc, char** argv)
{
    // Initialize stack trace manager of the current process
    CppCommon::StackTraceManager::Initialize();
    // Setup exceptions handler for the current process
    CppCommon::ExceptionsHandler::SetupProcess();

    std::cout << "1 - SIGABRT" << std::endl;
    std::cout << "2 - SIGFPE" << std::endl;
    std::cout << "3 - SIGILL" << std::endl;
    std::cout << "4 - SIGINT" << std::endl;
    std::cout << "5 - SIGSEGV" << std::endl;
    std::cout << "6 - SIGTERM" << std::endl;
    std::cout << "7 - exit" << std::endl;
    std::cout << "8 - terminate" << std::endl;
    std::cout << "9 - unexpected" << std::endl;
    std::cout << "10 - exception throw" << std::endl;
#if defined(_WIN32) || defined(_WIN64)
    std::cout << "11 - invalid parameter" << std::endl;
    std::cout << "12 - new operator fault" << std::endl;
    std::cout << "13 - pure virtual method call" << std::endl;
    std::cout << "14 - SEH exception" << std::endl;
    std::cout << "15 - RaiseException()" << std::endl;
#endif
    std::cout << "Choose an exception type: ";

    std::string line;
    if (getline(std::cin, line))
    {
        int type = std::stoi(line);
        GenerateCustomException(type, true);
    }

    // Cleanup stack trace manager of the current process
    CppCommon::StackTraceManager::Cleanup();

    return 0;
}
<|endoftext|>


<commit_before><commit_msg>Update comments<commit_after><|endoftext|>