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

  Program:   Visualization Toolkit
  Module:    vtkValuePainter.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 "vtkValuePainter.h"
#include "vtkObjectFactory.h"

#include "vtkAbstractMapper.h"
#include "vtkActor.h"
#include "vtkCellArray.h"
#include "vtkImageData.h"
#include "vtkInformation.h"
#include "vtkInformationDoubleVectorKey.h"
#include "vtkInformationIntegerKey.h"
#include "vtkInformationStringKey.h"
#include "vtkNew.h"
#include "vtkOpenGLTexture.h"
#include "vtkPainterDeviceAdapter.h"
#include "vtkPointData.h"
#include "vtkPolyData.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkSmartPointer.h"
#include "vtkTimerLog.h"

#include "vtkOpenGL.h"
#include "vtkOpenGLError.h"
#include "vtkOpenGLExtensionManager.h"

#include "vtkgl.h" // vtkgl namespace

vtkInformationKeyMacro(vtkValuePainter, SCALAR_MODE, Integer);
vtkInformationKeyMacro(vtkValuePainter, SCALAR_RANGE, DoubleVector);
vtkInformationKeyMacro(vtkValuePainter, ARRAY_ID, Integer);
vtkInformationKeyMacro(vtkValuePainter, ARRAY_NAME, String);
vtkInformationKeyMacro(vtkValuePainter, ARRAY_COMPONENT, Integer);

//TODO: template MapScalars to eliminate casting/conversion
//TODO: make MapScalars extensible if user has a different function in mind
//TODO: make MapScalars output within a band so that you can multipass on >24 bit quantities (like selection does)

class vtkValuePainter::vtkInternals
{
public:
  int FieldAssociation;
  int FieldAttributeType;
  std::string FieldName;
  bool FieldNameSet;
  int Component;
  double ScalarRange[2];
  bool ScalarRangeSet;

  vtkNew<vtkImageData> Texture;

  // Description:
  // Constructor
  vtkInternals()
    {
    this->FieldNameSet = false;
    this->FieldAssociation = 0;
    this->FieldAttributeType = 0;
    this->Component = 0;
    this->ScalarRangeSet = false;
    this->ScalarRange[0] = 0.0;
    this->ScalarRange[1] = -1.0;

    #define MML 0x1000
    this->Texture->SetExtent(0,MML,0,0, 0,0);
    vtkSmartPointer<vtkUnsignedCharArray> chars = vtkSmartPointer<vtkUnsignedCharArray>::New();
    chars->SetNumberOfComponents(3);
    chars->SetNumberOfTuples(MML);
    unsigned char color[3];
    unsigned int i;
    for (i = 0; i < MML; i++)
      {
      vtkValuePainter::ValueToColor(i, 0, MML, color);
      chars->SetTuple3(i, color[0],color[1],color[2]);
      }
    this->Texture->GetPointData()->SetScalars(chars);
    }

  // Description:
  // Destructor
  ~vtkInternals()
    {
    }
};

//----------------------------------------------------------------------------
vtkStandardNewMacro(vtkValuePainter);

//----------------------------------------------------------------------------
vtkValuePainter::vtkValuePainter()
{
  this->Internals = new vtkInternals;
}

//----------------------------------------------------------------------------
vtkValuePainter::~vtkValuePainter()
{
  delete this->Internals;
}

//----------------------------------------------------------------------------
void vtkValuePainter::SetInputArrayToProcess(
      int fieldAssociation,
      const char* name)
{
  if ( !this->Internals->FieldNameSet
    || (this->Internals->FieldAssociation != fieldAssociation)
    || (this->Internals->FieldName != name) )
    {
    this->Internals->FieldAssociation = fieldAssociation;
    this->Internals->FieldName = name;
    this->Internals->FieldNameSet = true;
    this->Modified();
    }
}

//----------------------------------------------------------------------------
void vtkValuePainter::SetInputArrayToProcess(
      int fieldAssociation,
      int fieldAttributeType)
{
  if ( (this->Internals->FieldAssociation != fieldAssociation)
    || (this->Internals->FieldAttributeType != fieldAttributeType)
    || this->Internals->FieldNameSet )
    {
    this->Internals->FieldAssociation = fieldAssociation;
    this->Internals->FieldAttributeType = fieldAttributeType;
    this->Internals->FieldNameSet = false;
    this->Modified();
    }
}

//----------------------------------------------------------------------------
void vtkValuePainter::SetInputComponentToProcess(int comp)
{
  if ( this->Internals->Component != comp)
    {
    this->Internals->Component = comp;
    this->Modified();
    }
}

//----------------------------------------------------------------------------
void vtkValuePainter::SetScalarRange(double min, double max)
{
  if (this->Internals->ScalarRange[0] != min ||
      this->Internals->ScalarRange[1] != max)
    {
    this->Internals->ScalarRange[0] = min;
    this->Internals->ScalarRange[1] = max;
    this->Internals->ScalarRangeSet = (max > min);
    this->Modified();
    }
}

//-----------------------------------------------------------------------------
void vtkValuePainter::ProcessInformation(vtkInformation* info)
{
  bool modify = false;
  bool byname = false;

  int fa = this->Internals->FieldAssociation;
  int aidx = this->Internals->FieldAttributeType;
  std::string aname = this->Internals->FieldName;

  if (info->Has(vtkValuePainter::SCALAR_MODE()))
    {
    if (this->Internals->FieldAssociation != info->Get(vtkValuePainter::SCALAR_MODE()))
      {
      fa = info->Get(vtkValuePainter::SCALAR_MODE());
      modify = true;
      }
    }

  if (info->Has(vtkValuePainter::ARRAY_ID()))
    {
    if (this->Internals->FieldAttributeType != info->Get(vtkValuePainter::ARRAY_ID()))
      {
      aidx = info->Get(vtkValuePainter::ARRAY_ID());
      modify = true;
      byname = false;
      }
    }

  if (info->Has(vtkValuePainter::ARRAY_NAME()))
    {
    if (this->Internals->FieldName != info->Get(vtkValuePainter::ARRAY_NAME()))
      {
      aname = info->Get(vtkValuePainter::ARRAY_NAME());
      modify = true;
      byname = true;
      }
    }

  if (modify)
    {
    if (byname)
      {
      this->SetInputArrayToProcess(fa, aname.c_str());
      }
    else
      {
      this->SetInputArrayToProcess(fa, aidx);
      }
    }

  if (info->Has(vtkValuePainter::ARRAY_COMPONENT()))
    {
    if (this->Internals->Component != info->Get(vtkValuePainter::ARRAY_COMPONENT()))
      {
      this->SetInputComponentToProcess(info->Get(vtkValuePainter::ARRAY_COMPONENT()));
      }
    }

  if (info->Has(vtkValuePainter::SCALAR_RANGE()))
    {
    double *nr = info->Get(vtkValuePainter::SCALAR_RANGE());
    if (this->Internals->ScalarRange[0] != nr[0] || this->Internals->ScalarRange[1] != nr[1])
      {
      this->SetScalarRange(nr[0], nr[1]);
      }
    }
}

//-----------------------------------------------------------------------------
void vtkValuePainter::ValueToColor(double value, double min, double scale,
                                   unsigned char *color)
{
  //TODO: make this configurable
  double valueS = (value - min)/scale;
  valueS = (valueS<0.0?0.0:valueS); //prevent underflow
  valueS = (valueS>1.0?1.0:valueS); //prevent overflow
  int valueI = valueS * 0xffffff;

  color[0] = (unsigned char)((valueI & 0xff0000)>>16);
  color[1] = (unsigned char)((valueI & 0x00ff00)>>8);
  color[2] = (unsigned char)((valueI & 0x0000ff));
}

//-----------------------------------------------------------------------------
void vtkValuePainter::ColorToValue(unsigned char *color, double min, double scale,
                                   double &value)
{
  //TODO: make this configurable
  int valueI = ((int)(*(color+0)))<<16 | ((int)(*(color+1)))<<8 | ((int)(*(color+2)));
  double valueS = valueI/(double)0xffffff;
  value = valueS*scale + min;
}

//-----------------------------------------------------------------------------
void vtkValuePainter::RenderInternal(
  vtkRenderer* renderer,
  vtkActor* vtkNotUsed(actor),
  unsigned long typeflags,
  bool vtkNotUsed(forceCompileOnly))
{
  if (typeflags == 0)
    {
    // No primitive to render.
    return;
    }

  this->Timer->StartTimer();

  vtkOpenGLClearErrorMacro();

  //set render state so that colors we draw are not altered at all
  int oldSampling = glIsEnabled(vtkgl::MULTISAMPLE);
  int oldLight = glIsEnabled(GL_LIGHTING);
  int oldBlend = glIsEnabled(GL_BLEND);
  glDisable(vtkgl::MULTISAMPLE);
  glDisable(GL_LIGHTING);
  glDisable(GL_BLEND);

  vtkPolyData* pd = this->GetInputAsPolyData();

  vtkIdType startCell = 0;

  if (typeflags & vtkPainter::VERTS)
    {
    this->DrawCells(VTK_POLY_VERTEX, pd->GetVerts(), startCell, renderer);
    }

  startCell += pd->GetNumberOfVerts();
  if (typeflags & vtkPainter::LINES)
    {
    this->DrawCells(VTK_POLY_LINE, pd->GetLines(), startCell, renderer);
    }

  startCell += pd->GetNumberOfLines();
  if (typeflags & vtkPainter::POLYS)
    {
    this->DrawCells(VTK_POLYGON, pd->GetPolys(), startCell, renderer);
    }

  startCell += pd->GetNumberOfPolys();
  if (typeflags & vtkPainter::STRIPS)
    {
    this->DrawCells(VTK_TRIANGLE_STRIP, pd->GetStrips(), startCell, renderer);
    }

  //restore render state to whatever it was before
  if (oldSampling)
    {
    glEnable(vtkgl::MULTISAMPLE);
    }
  if (oldLight)
    {
    glEnable(GL_LIGHTING);
    }
  if (oldBlend)
    {
    glEnable(GL_BLEND);
    }

  this->Timer->StopTimer();
  this->TimeToDraw = this->Timer->GetElapsedTime();
}

//-----------------------------------------------------------------------------
void vtkValuePainter::DrawCells(
  int mode, vtkCellArray *connectivity, vtkIdType startCellId,
  vtkRenderer *renderer)
{
  vtkPolyData* pd = this->GetInputAsPolyData();
  vtkPainterDeviceAdapter* device = renderer->GetRenderWindow()->
    GetPainterDeviceAdapter();

  vtkPoints* p = pd->GetPoints();
  if (!p)
    {
    return;
    }
  vtkIdType npts, *pts;
  vtkIdType cellId = startCellId;

  int pointtype = p->GetDataType();
  void* voidpoints = p->GetVoidPointer(0);
  int count = 0;

  int doingCells;
  vtkDataArray *values;

  if (this->Internals->FieldNameSet)
    {
    values = vtkAbstractMapper::GetScalars
      (pd, this->Internals->FieldAssociation, VTK_GET_ARRAY_BY_NAME, 1, this->Internals->FieldName.c_str(), doingCells);
    }
  else
    {
    values = vtkAbstractMapper::GetScalars
      (pd, this->Internals->FieldAssociation, VTK_GET_ARRAY_BY_ID, this->Internals->FieldAttributeType, NULL, doingCells);
    }
  if (!values)
    {
    vtkWarningMacro("Could not find array to draw.")
    return;
    }

  int comp = this->Internals->Component;
  if (comp < 0 || comp >= values->GetNumberOfComponents())
    {
    comp = 0;
    }
  double *minmax;
  if (this->Internals->ScalarRangeSet)
    {
    minmax = this->Internals->ScalarRange;
    }
  else
    {
    minmax = values->GetRange(comp);
    }
  double scale = minmax[1]-minmax[0];
  if (scale <= 0)
    {
    scale = values->GetDataTypeMax()-values->GetDataTypeMin();
    }

  vtkSmartPointer<vtkOpenGLTexture> internalColorTexture;
  if (!doingCells)
    {
    internalColorTexture = vtkSmartPointer<vtkOpenGLTexture>::New();
    //texture ensures that GL interpolates point values across polygons
    internalColorTexture->RepeatOff();
    internalColorTexture->SetInputData(this->Internals->Texture.GetPointer());
    internalColorTexture->Load(renderer);
    }

  unsigned char color[3];
  for (connectivity->InitTraversal(); connectivity->GetNextCell(npts, pts); count++)
    {
    device->BeginPrimitive(mode);

    if (doingCells)
      {
      double value = values->GetComponent(count, comp);
      this->ValueToColor(value, minmax[0], scale, color);

      renderer->GetRenderWindow()->GetPainterDeviceAdapter()
        ->SendAttribute(vtkDataSetAttributes::SCALARS, 3, GL_UNSIGNED_BYTE, color);
      }

    for (vtkIdType cellpointi = 0; cellpointi < npts; cellpointi++)
      {
      vtkIdType pointId = pts[cellpointi];

      if (!doingCells)
        {
        double value = (values->GetComponent(pointId, comp) - minmax[0])/scale;

        renderer->GetRenderWindow()->GetPainterDeviceAdapter()
          ->SendAttribute(vtkDataSetAttributes::TCOORDS,1,VTK_DOUBLE,&value, 0);
        }

      renderer->GetRenderWindow()->GetPainterDeviceAdapter()
        ->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3,
                        pointtype, voidpoints, 3*pointId);
      }

    device->EndPrimitive();
    cellId++;
    if (count == 10000)
      {
      count = 0;
      // report progress
      this->UpdateProgress(static_cast<double>(cellId - startCellId)/this->TotalCells);
      // Abort render.
      if (renderer->GetRenderWindow()->CheckAbortStatus())
        {
        return;
        }
      }
    }
}

//----------------------------------------------------------------------------
void vtkValuePainter::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
}
<commit_msg>Revert "Fix test failure"<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkValuePainter.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 "vtkValuePainter.h"
#include "vtkObjectFactory.h"

#include "vtkAbstractMapper.h"
#include "vtkActor.h"
#include "vtkCellArray.h"
#include "vtkImageData.h"
#include "vtkInformation.h"
#include "vtkInformationDoubleVectorKey.h"
#include "vtkInformationIntegerKey.h"
#include "vtkInformationStringKey.h"
#include "vtkNew.h"
#include "vtkOpenGLTexture.h"
#include "vtkPainterDeviceAdapter.h"
#include "vtkPointData.h"
#include "vtkPolyData.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkSmartPointer.h"
#include "vtkTimerLog.h"

#include "vtkOpenGL.h"
#include "vtkOpenGLError.h"
#include "vtkOpenGLExtensionManager.h"

#include "vtkgl.h" // vtkgl namespace

vtkInformationKeyMacro(vtkValuePainter, SCALAR_MODE, Integer);
vtkInformationKeyMacro(vtkValuePainter, SCALAR_RANGE, DoubleVector);
vtkInformationKeyMacro(vtkValuePainter, ARRAY_ID, Integer);
vtkInformationKeyMacro(vtkValuePainter, ARRAY_NAME, String);
vtkInformationKeyMacro(vtkValuePainter, ARRAY_COMPONENT, Integer);

//TODO: template MapScalars to eliminate casting/conversion
//TODO: make MapScalars extensible if user has a different function in mind
//TODO: make MapScalars output within a band so that you can multipass on >24 bit quantities (like selection does)

class vtkValuePainter::vtkInternals
{
public:
  int FieldAssociation;
  int FieldAttributeType;
  std::string FieldName;
  bool FieldNameSet;
  int Component;
  double ScalarRange[2];
  bool ScalarRangeSet;

  vtkNew<vtkImageData> Texture;

  // Description:
  // Constructor
  vtkInternals()
    {
    this->FieldNameSet = false;
    this->FieldAssociation = 0;
    this->FieldAttributeType = 0;
    this->Component = 0;
    this->ScalarRangeSet = false;
    this->ScalarRange[0] = 0.0;
    this->ScalarRange[1] = -1.0;

    #define MML 0x1000
    this->Texture->SetExtent(0,MML,0,0, 0,0);
    vtkSmartPointer<vtkUnsignedCharArray> chars = vtkSmartPointer<vtkUnsignedCharArray>::New();
    chars->SetNumberOfComponents(3);
    chars->SetNumberOfTuples(MML);
    unsigned char color[3];
    unsigned int i;
    for (i = 0; i < MML; i++)
      {
      vtkValuePainter::ValueToColor(i, 0, MML, color);
      chars->SetTuple3(i, color[0],color[1],color[2]);
      }
    this->Texture->GetPointData()->SetScalars(chars);
    }

  // Description:
  // Destructor
  ~vtkInternals()
    {
    }
};

//----------------------------------------------------------------------------
vtkStandardNewMacro(vtkValuePainter);

//----------------------------------------------------------------------------
vtkValuePainter::vtkValuePainter()
{
  this->Internals = new vtkInternals;
}

//----------------------------------------------------------------------------
vtkValuePainter::~vtkValuePainter()
{
  delete this->Internals;
}

//----------------------------------------------------------------------------
void vtkValuePainter::SetInputArrayToProcess(
      int fieldAssociation,
      const char* name)
{
  if ( !this->Internals->FieldNameSet
    || (this->Internals->FieldAssociation != fieldAssociation)
    || (this->Internals->FieldName != name) )
    {
    this->Internals->FieldAssociation = fieldAssociation;
    this->Internals->FieldName = name;
    this->Internals->FieldNameSet = true;
    this->Modified();
    }
}

//----------------------------------------------------------------------------
void vtkValuePainter::SetInputArrayToProcess(
      int fieldAssociation,
      int fieldAttributeType)
{
  if ( (this->Internals->FieldAssociation != fieldAssociation)
    || (this->Internals->FieldAttributeType != fieldAttributeType)
    || this->Internals->FieldNameSet )
    {
    this->Internals->FieldAssociation = fieldAssociation;
    this->Internals->FieldAttributeType = fieldAttributeType;
    this->Internals->FieldNameSet = false;
    this->Modified();
    }
}

//----------------------------------------------------------------------------
void vtkValuePainter::SetInputComponentToProcess(int comp)
{
  if ( this->Internals->Component != comp)
    {
    this->Internals->Component = comp;
    this->Modified();
    }
}

//----------------------------------------------------------------------------
void vtkValuePainter::SetScalarRange(double min, double max)
{
  if (this->Internals->ScalarRange[0] != min ||
      this->Internals->ScalarRange[1] != max)
    {
    this->Internals->ScalarRange[0] = min;
    this->Internals->ScalarRange[1] = max;
    this->Internals->ScalarRangeSet = (max > min);
    this->Modified();
    }
}

//-----------------------------------------------------------------------------
void vtkValuePainter::ProcessInformation(vtkInformation* info)
{
  bool modify = false;
  bool byname = false;

  int fa = this->Internals->FieldAssociation;
  int aidx = this->Internals->FieldAttributeType;
  std::string aname = this->Internals->FieldName;

  if (info->Has(vtkValuePainter::SCALAR_MODE()))
    {
    if (this->Internals->FieldAssociation != info->Get(vtkValuePainter::SCALAR_MODE()))
      {
      fa = info->Get(vtkValuePainter::SCALAR_MODE());
      modify = true;
      }
    }

  if (info->Has(vtkValuePainter::ARRAY_ID()))
    {
    if (this->Internals->FieldAttributeType != info->Get(vtkValuePainter::ARRAY_ID()))
      {
      aidx = info->Get(vtkValuePainter::ARRAY_ID());
      modify = true;
      byname = false;
      }
    }

  if (info->Has(vtkValuePainter::ARRAY_NAME()))
    {
    if (this->Internals->FieldName != info->Get(vtkValuePainter::ARRAY_NAME()))
      {
      aname = info->Get(vtkValuePainter::ARRAY_NAME());
      modify = true;
      byname = true;
      }
    }

  if (modify)
    {
    if (byname)
      {
      this->SetInputArrayToProcess(fa, aname.c_str());
      }
    else
      {
      this->SetInputArrayToProcess(fa, aidx);
      }
    }

  if (info->Has(vtkValuePainter::ARRAY_COMPONENT()))
    {
    if (this->Internals->Component != info->Get(vtkValuePainter::ARRAY_COMPONENT()))
      {
      this->SetInputComponentToProcess(info->Get(vtkValuePainter::ARRAY_COMPONENT()));
      }
    }

  if (info->Has(vtkValuePainter::SCALAR_RANGE()))
    {
    double *nr = info->Get(vtkValuePainter::SCALAR_RANGE());
    if (this->Internals->ScalarRange[0] != nr[0] || this->Internals->ScalarRange[1] != nr[1])
      {
      this->SetScalarRange(nr[0], nr[1]);
      }
    }
}

//-----------------------------------------------------------------------------
void vtkValuePainter::ValueToColor(double value, double min, double scale,
                                   unsigned char *color)
{
  //TODO: make this configurable
  double valueS = (value - min)/scale;
  valueS = (valueS<0.0?0.0:valueS); //prevent underflow
  valueS = (valueS>1.0?1.0:valueS); //prevent overflow
  int valueI = valueS * 0xffffff;

  color[0] = (unsigned char)((valueI & 0xff0000)>>16);
  color[1] = (unsigned char)((valueI & 0x00ff00)>>8);
  color[2] = (unsigned char)((valueI & 0x0000ff));
}

//-----------------------------------------------------------------------------
void vtkValuePainter::ColorToValue(unsigned char *color, double min, double scale,
                                   double &value)
{
  //TODO: make this configurable
  int valueI = ((int)(*(color+0)))<<16 | ((int)(*(color+1)))<<8 | ((int)(*(color+2)));
  double valueS = valueI/(double)0xffffff;
  value = valueS*scale + min;
}

//-----------------------------------------------------------------------------
void vtkValuePainter::RenderInternal(
  vtkRenderer* renderer,
  vtkActor* vtkNotUsed(actor),
  unsigned long typeflags,
  bool vtkNotUsed(forceCompileOnly))
{
  if (typeflags == 0)
    {
    // No primitive to render.
    return;
    }

  this->Timer->StartTimer();

  vtkOpenGLClearErrorMacro();

  //set render state so that colors we draw are not altered at all
  int oldSampling = glIsEnabled(vtkgl::MULTISAMPLE);
  int oldLight = glIsEnabled(GL_LIGHTING);
  int oldBlend = glIsEnabled(GL_BLEND);
  glDisable(vtkgl::MULTISAMPLE);
  glDisable(GL_LIGHTING);
  glDisable(GL_BLEND);

  vtkPolyData* pd = this->GetInputAsPolyData();

  vtkIdType startCell = 0;

  if (typeflags & vtkPainter::VERTS)
    {
    this->DrawCells(VTK_POLY_VERTEX, pd->GetVerts(), startCell, renderer);
    }

  startCell += pd->GetNumberOfVerts();
  if (typeflags & vtkPainter::LINES)
    {
    this->DrawCells(VTK_POLY_LINE, pd->GetLines(), startCell, renderer);
    }

  startCell += pd->GetNumberOfLines();
  if (typeflags & vtkPainter::POLYS)
    {
    this->DrawCells(VTK_POLYGON, pd->GetPolys(), startCell, renderer);
    }

  startCell += pd->GetNumberOfPolys();
  if (typeflags & vtkPainter::STRIPS)
    {
    this->DrawCells(VTK_TRIANGLE_STRIP, pd->GetStrips(), startCell, renderer);
    }

  //restore render state to whatever it was before
  if (oldSampling)
    {
    glEnable(vtkgl::MULTISAMPLE);
    }
  if (oldLight)
    {
    glEnable(GL_LIGHTING);
    }
  if (oldBlend)
    {
    glEnable(GL_BLEND);
    }

  this->Timer->StopTimer();
  this->TimeToDraw = this->Timer->GetElapsedTime();
}

//-----------------------------------------------------------------------------
void vtkValuePainter::DrawCells(
  int mode, vtkCellArray *connectivity, vtkIdType startCellId,
  vtkRenderer *renderer)
{
  vtkPolyData* pd = this->GetInputAsPolyData();
  vtkPainterDeviceAdapter* device = renderer->GetRenderWindow()->
    GetPainterDeviceAdapter();

  vtkPoints* p = pd->GetPoints();
  if (!p)
    {
    return;
    }
  vtkIdType npts, *pts;
  vtkIdType cellId = startCellId;

  int pointtype = p->GetDataType();
  void* voidpoints = p->GetVoidPointer(0);
  int count = 0;

  int doingCells;
  vtkDataArray *values;

  if (this->Internals->FieldNameSet)
    {
    values = vtkAbstractMapper::GetScalars
      (pd, this->Internals->FieldAssociation, VTK_GET_ARRAY_BY_NAME, 1, this->Internals->FieldName.c_str(), doingCells);
    }
  else
    {
    values = vtkAbstractMapper::GetScalars
      (pd, this->Internals->FieldAssociation, VTK_GET_ARRAY_BY_ID, this->Internals->FieldAttributeType, NULL, doingCells);
    }
  if (!values)
    {
    vtkWarningMacro("Could not find array to draw.")
    return;
    }

  int comp = this->Internals->Component;
  if (comp < 0 || comp >= values->GetNumberOfComponents())
    {
    comp = 0;
    }
  double *minmax;
  if (this->Internals->ScalarRangeSet)
    {
    minmax = this->Internals->ScalarRange;
    }
  else
    {
    minmax = values->GetRange(comp);
    }
  double scale = minmax[1]-minmax[0];
  if (scale <= 0)
    {
    scale = values->GetDataTypeMax()-values->GetDataTypeMin();
    }

  vtkSmartPointer<vtkOpenGLTexture> internalColorTexture;
  if (!doingCells)
    {
    internalColorTexture = vtkSmartPointer<vtkOpenGLTexture>::New();
    //texture ensures that GL interpolates point values across polygons
    internalColorTexture->RepeatOff();
    internalColorTexture->SetInputData(this->Internals->Texture.GetPointer());
    internalColorTexture->Load(renderer);
    }

#if VTK_SIZEOF_CHAR == 1
  GLenum vtkChar2GLenum = GL_UNSIGNED_BYTE;
#elif VTK_SIZE_OF_CHAR == 2
  GLenum vtkChar2GLenum = GL_UNSIGNED_SHORT;
#endif

  unsigned char color[3];
  for (connectivity->InitTraversal(); connectivity->GetNextCell(npts, pts); count++)
    {
    device->BeginPrimitive(mode);

    if (doingCells)
      {
      double value = values->GetComponent(count, comp);
      this->ValueToColor(value, minmax[0], scale, color);

      renderer->GetRenderWindow()->GetPainterDeviceAdapter()
        ->SendAttribute(
        vtkDataSetAttributes::SCALARS, 3, vtkChar2GLenum, color);
      }

    for (vtkIdType cellpointi = 0; cellpointi < npts; cellpointi++)
      {
      vtkIdType pointId = pts[cellpointi];

      if (!doingCells)
        {
        double value = (values->GetComponent(pointId, comp) - minmax[0])/scale;

        renderer->GetRenderWindow()->GetPainterDeviceAdapter()
          ->SendAttribute(vtkDataSetAttributes::TCOORDS,1,VTK_DOUBLE,&value, 0);
        }

      renderer->GetRenderWindow()->GetPainterDeviceAdapter()
        ->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3,
                        pointtype, voidpoints, 3*pointId);
      }

    device->EndPrimitive();
    cellId++;
    if (count == 10000)
      {
      count = 0;
      // report progress
      this->UpdateProgress(static_cast<double>(cellId - startCellId)/this->TotalCells);
      // Abort render.
      if (renderer->GetRenderWindow()->CheckAbortStatus())
        {
        return;
        }
      }
    }
}

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


<commit_before>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015-2016 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// 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.

// https://github.com/pillarjs/path-to-regexp/blob/master/index.js

#ifndef PATH_TO_REGEX_HPP
#define PATH_TO_REGEX_HPP

#include <map>
#include <regex>
#include <string>
#include <vector>

namespace route {

struct Token {
	std::string name      {};	// can be a string or an int (index)
	std::string prefix    {};
	std::string delimiter {};
	std::string pattern   {};
  bool        optional  {false};
  bool        repeat    {false};
  bool        partial   {false};
  bool        asterisk  {false};
	bool        is_string {false};	// If it is a string we only put/have a string in the name-attribute (path in parse-method)
	               	// So if this is true, we can ignore all attributes except name

  void set_string_token(const std::string& name_) {
    name = name_;
    is_string = true;
  }
}; //< struct Token

class PathToRegex {
private:
  //----------------------------------------
  // Internal class type aliases
  using Keys    = std::vector<Token>;
  using Tokens  = std::vector<Token>;
  using Options = std::map<std::string, bool>;
  //----------------------------------------
public:
  /**
   *  Creates a path-regex from string input (path)
   *  Updates keys-vector (empty input parameter)
   *
   *  Calls parse-method and then tokens_to_regex-method based on the tokens returned from parse-method
   *  Puts the tokens that are keys (not string-tokens) into keys-vector
   *
   *  std::vector<Token> keys (empty)
   *    Is created outside the class and sent in as parameter
   *    One Token-object in the keys-vector per parameter found in the path
   *
   *  std::map<std::string, bool> options (optional)
   *    Can contain bool-values for the keys "sensitive", "strict" and/or "end"
   *    Default:
   *      strict = false
   *      sensitive = false
   *      end = true
   */
	static std::regex path_to_regex(const std::string& path, Keys& keys, const Options& options = Options{});

  /**
   *  Creates a path-regex from string input (path)
   *
   *  Calls parse-method and then tokens_to_regex-method based on the tokens returned from parse-method
   *
   *  std::map<std::string, bool> options (optional)
   *    Can contain bool-values for the keys "sensitive", "strict" and/or "end"
   *    Default:
   *      strict = false
   *      sensitive = false
   *      end = true
   */
  static std::regex path_to_regex(const std::string& path, const Options& options = Options{});

  /**
   *  Creates vector of tokens based on the given string (this vector of tokens can be sent as
   *  input to tokens_to_regex-method and includes tokens that are strings, not only tokens
   *  that are parameters in str)
   */
  static Tokens parse(const std::string& str);

  /**
   *  Creates a regex based on the tokens and options (optional) given
   */
  static std::regex tokens_to_regex(const Tokens& tokens, const Options& options = Options{});

  /**
   *  Goes through the tokens-vector and push all tokens that are not string-tokens
   *  onto keys-vector
   */
  static void tokens_to_keys(const Tokens& tokens, Keys& keys);

private:
	static const std::regex PATH_REGEXP;
}; //< class PathToRegex

}; //< namespace route

#endif //< PATH_TO_REGEX_HPP
<commit_msg>Renamed include guard<commit_after>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015-2016 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// 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.

// https://github.com/pillarjs/path-to-regexp/blob/master/index.js

#ifndef ROUTE_PATH_TO_REGEX_HPP
#define ROUTE_PATH_TO_REGEX_HPP

#include <map>
#include <regex>
#include <string>
#include <vector>

namespace route {

struct Token {
	std::string name      {};	// can be a string or an int (index)
	std::string prefix    {};
	std::string delimiter {};
	std::string pattern   {};
  bool        optional  {false};
  bool        repeat    {false};
  bool        partial   {false};
  bool        asterisk  {false};
	bool        is_string {false};	// If it is a string we only put/have a string in the name-attribute (path in parse-method)
	               	// So if this is true, we can ignore all attributes except name

  void set_string_token(const std::string& name_) {
    name = name_;
    is_string = true;
  }
}; //< struct Token

class PathToRegex {
private:
  //----------------------------------------
  // Internal class type aliases
  using Keys    = std::vector<Token>;
  using Tokens  = std::vector<Token>;
  using Options = std::map<std::string, bool>;
  //----------------------------------------
public:
  /**
   *  Creates a path-regex from string input (path)
   *  Updates keys-vector (empty input parameter)
   *
   *  Calls parse-method and then tokens_to_regex-method based on the tokens returned from parse-method
   *  Puts the tokens that are keys (not string-tokens) into keys-vector
   *
   *  std::vector<Token> keys (empty)
   *    Is created outside the class and sent in as parameter
   *    One Token-object in the keys-vector per parameter found in the path
   *
   *  std::map<std::string, bool> options (optional)
   *    Can contain bool-values for the keys "sensitive", "strict" and/or "end"
   *    Default:
   *      strict = false
   *      sensitive = false
   *      end = true
   */
	static std::regex path_to_regex(const std::string& path, Keys& keys, const Options& options = Options{});

  /**
   *  Creates a path-regex from string input (path)
   *
   *  Calls parse-method and then tokens_to_regex-method based on the tokens returned from parse-method
   *
   *  std::map<std::string, bool> options (optional)
   *    Can contain bool-values for the keys "sensitive", "strict" and/or "end"
   *    Default:
   *      strict = false
   *      sensitive = false
   *      end = true
   */
  static std::regex path_to_regex(const std::string& path, const Options& options = Options{});

  /**
   *  Creates vector of tokens based on the given string (this vector of tokens can be sent as
   *  input to tokens_to_regex-method and includes tokens that are strings, not only tokens
   *  that are parameters in str)
   */
  static Tokens parse(const std::string& str);

  /**
   *  Creates a regex based on the tokens and options (optional) given
   */
  static std::regex tokens_to_regex(const Tokens& tokens, const Options& options = Options{});

  /**
   *  Goes through the tokens-vector and push all tokens that are not string-tokens
   *  onto keys-vector
   */
  static void tokens_to_keys(const Tokens& tokens, Keys& keys);

private:
	static const std::regex PATH_REGEXP;
}; //< class PathToRegex

} //< namespace route

#endif //< ROUTE_PATH_TO_REGEX_HPP
<|endoftext|>


<commit_before>#include <iostream>
//~ #include <fstream>
//~ #include <cmath>
#include <ctime>

#include "TH1.h"
//~ #include "TH2.h"
//~ #include "TH3.h"
//~ #include "TCanvas.h"
#include "TRandom3.h"
//~ #include "TVector2.h"
//~ #include "TVector3.h"
//~ #include "TLorentzVector.h"
#include "TString.h"

#include "Math/Minimizer.h"
#include "Math/Factory.h"
#include "Math/Functor.h"

/* Algorithms list
 * minName              algoName
 * ---------------------------------
 * Minuit/Minuit2       Migrad, Simplex, Seek, Combined (default is Migrad)
 * Minuit/Minuit2       Scan (good for scans, not minimizations)
 * Minuit2              Fumili (*** needs different function type ***), Fumili2
 * Fumili               *** needs different function type ***
 * GSLMultiMin          ConjugateFR, ConjugatePR, BFGS, BFGS2, SteepestDescent
 * GSLMultiFit          *** needs different function type ***
 * GSLSimAn
 * Linear               *** needs linear function ***
 * Genetic              *** sloooow and inaccurate ***
 *
 *
 * https://root.cern.ch/fitting
 * https://root.cern.ch/numerical-minimization
 */

const int Ndim = 8;

using namespace ROOT::Math;
using namespace std;

double parabola1(const double* xx)
{
    double x = xx[0];
    double y = xx[1];
    return (x-3)*(x-3)+(y-2)*(y-2);
}

double parabolaN(const double* xx)
{
    double accumulator=0;
    for (int i=0; i< Ndim; ++i) {
        double c = i+1;
        accumulator += (xx[i]-1/c)*(xx[i]-1/c);
    }
    return accumulator;
}

double rosenbrockN(const double* xx)
{
    double accumulator=0;
    for (int i=0; i< Ndim-1; ++i) {
        accumulator += 100*pow(xx[i+1]-xx[i]*xx[i], 2) + pow(xx[i]-1, 2);
    }
    return accumulator;
}

class MCMinimizer
{
protected:
    TRandom3 rng;

    int Ndim = 0;
    double (*function)(const double*); // = &rosenbrockN;

    vector<double> params;
    vector<double> params_min;
    vector<double> params_max;
    vector<string> names;
    double minValue;

    int max_function_calls = 0;
    int printLevel;

public:
    MCMinimizer()
    {
        this->rng = TRandom3(12345);
    }

    inline void SetMCFunction(double (*function)(const double*), int Ndim)
    {
        this->function = function;
        this->Ndim = Ndim;
    }

    inline void SetMCVariable(string name, double val, double min, double max)
    {
        this->params.push_back(val);
        this->params_min.push_back(min);
        this->params_max.push_back(max);
        this->names.push_back(name);
    }

    inline void SetMaxFunctionCalls(int calls)
    {
        this->max_function_calls = calls;
    }

    bool Minimize()
    {
        if (printLevel) cout << "Minimize using MCMinimizer" << endl;
        this->minValue = this->function(&params[0]); // evaluate in given initial point

        for (int i=0; i<this->max_function_calls; ++i) {
            double pars_array[Ndim];
            for (int par=0; par < Ndim; ++par) {     // get random params vector
                pars_array[par] = rng.Uniform(params_min[par], params_max[par]);
            }
            double nmin = (*function)(pars_array);
            if (nmin < this->minValue) {
                this->minValue = nmin;
                params = vector<double>(pars_array, pars_array + Ndim);
            }
        }
        if (printLevel) {
            cout << "FVAL         = " << this->minValue << endl;
            for (int i=0; i<Ndim; ++i) {
                cout << names[i] << "\t  = " << params[i] << endl;
            }
        }
        return true;
    }

    inline void SetPrintLevel(int printLevel)
    {
        this->printLevel = printLevel;
    }

    inline double MinValue()
    {
        return this->minValue;
    }

    inline double* X()
    {
        return &(this->params[0]);
    }
};

class MCZoomMinimizer
{
protected:
    TRandom3 rng;

    int Ndim = 0;
    double (*function)(const double*); // = &rosenbrockN;

    vector<double> params;
    vector<double> params_min;
    vector<double> params_max;
    vector<string> names;
    double minValue;

    int max_function_calls = 0;
    int splits = 0;
    int printLevel;

public:
    MCZoomMinimizer()
    {
        this->rng = TRandom3(12345);
    }

    inline void SetMCFunction(double (*function)(const double*), int Ndim)
    {
        this->function = function;
        this->Ndim = Ndim;
    }

    inline void SetMCVariable(string name, double val, double min, double max)
    {
        this->params.push_back(val);
        this->params_min.push_back(min);
        this->params_max.push_back(max);
        this->names.push_back(name);
    }

    inline void SetMaxFunctionCalls(int calls)
    {
        this->max_function_calls = calls;
    }

    inline void SetSplitNumber(int splits)
    {
        this->splits = splits;
    }

    bool Minimize()
    {
        if (printLevel) cout << "Minimize using MCZoomMinimizer" << endl;
        this->minValue = this->function(&params[0]); // evaluate in given initial point

        for (int ns=0; ns < splits; ++ns) {
            double average[2][Ndim];
            int calls[2][Ndim];
            int call_block = this->max_function_calls/this->splits;
            for (int i=0; i<call_block; ++i) {
                int call_over[Ndim];
                double pars_array[Ndim];
                for (int par=0; par < Ndim; ++par) {     // get random params vector
                    pars_array[par] = rng.Uniform(params_min[par], params_max[par]);
                    int ifup = pars_array[par] > ((params_min[par] + params_max[par])/2);
                    calls[ifup][par]++;
                    call_over[par] = ifup;
                }
                double nmin = (*function)(pars_array);
                for (int par=0; par < Ndim; ++par) {
                    average[call_over[par]][par] += nmin;
                }
                if (nmin < this->minValue) {
                    this->minValue = nmin;
                    params = vector<double>(pars_array, pars_array + Ndim);
                }
            }

            for (int par=0; par < Ndim; ++par) {
                if (average[0][par]/calls[0][par] > average[1][par]/calls[1][par]) {
                    params_max[par] = (params_min[par] + params_max[par])/2;
                }
                else {
                    params_min[par] = (params_min[par] + params_max[par])/2;
                }
            }
        }

        if (printLevel) {
            cout << "FVAL         = " << this->minValue << endl;
            for (int i=0; i<Ndim; ++i) {
                cout << names[i] << "\t  = " << params[i] << endl;
            }
        }
        return true;
    }

    inline void SetPrintLevel(int printLevel)
    {
        this->printLevel = printLevel;
    }

    inline double MinValue()
    {
        return this->minValue;
    }

    inline double* X()
    {
        return &(this->params[0]);
    }
};

int minimizer()
{
    // List of valid minimizers
    vector<pair<string,string>> minVector;
    //                                      name      algorithm
    // minVector.push_back(pair<string,string>("Minuit", "Migrad"));
    // minVector.push_back(pair<string,string>("Minuit", "Simplex"));
    // minVector.push_back(pair<string,string>("Minuit", "Combined"));
    // minVector.push_back(pair<string,string>("Minuit", "Seek"));
    // minVector.push_back(pair<string,string>("Minuit", "Scan"));

    minVector.push_back(pair<string,string>("Minuit2", "Migrad"));
    minVector.push_back(pair<string,string>("Minuit2", "Simplex"));
    // minVector.push_back(pair<string,string>("Minuit2", "Combined"));
    minVector.push_back(pair<string,string>("Minuit2", "Seek"));
    // minVector.push_back(pair<string,string>("Minuit2", "Scan"));
    // minVector.push_back(pair<string,string>("Minuit2", "Fumili"));
    minVector.push_back(pair<string,string>("Minuit2", "Fumili2"));

    // minVector.push_back(pair<string,string>("Fumili",  "Fumili"));

    minVector.push_back(pair<string,string>("GSLMultiMin", "ConjugateFR"));
    minVector.push_back(pair<string,string>("GSLMultiMin", "ConjugatePR"));
    minVector.push_back(pair<string,string>("GSLMultiMin", "BFGS"));
    minVector.push_back(pair<string,string>("GSLMultiMin", "BFGS2"));
    minVector.push_back(pair<string,string>("GSLMultiMin", "SteepestDescent"));

    // minVector.push_back(pair<string,string>("GSLMultiFit", ""));

    minVector.push_back(pair<string,string>("GSLSimAn", ""));

    // minVector.push_back(pair<string,string>("Linear", "");

    // minVector.push_back(pair<string,string>("Genetic", ""));

    for (unsigned int i=0; i < minVector.size(); ++i) {

        Minimizer* min = Factory::CreateMinimizer(minVector[i].first, minVector[i].second);
        if (min==nullptr) {
            cout << "Invalid algorithm: " << minVector[i].first << " - " << minVector[i].second << endl;
            continue;
        }
        else cout << "Using algorithm: " << minVector[i].first << " - " << minVector[i].second << endl;

        // The minimizer needs an IMultiGenFunction, which is easily provided
        // by a Functor, which is a generic wrapper class
        Functor fun = Functor(&rosenbrockN, Ndim);

        // Give the function to the minimizer
        min->SetFunction(fun);

        // Give the function variables
        if (minVector[i].first=="Genetic") {
            // Limited domain (genetic algorithm only)
            for (int i=0; i<Ndim; ++i) {
                min->SetLimitedVariable(i, Form("x%d", i), 0, 0.05, -0.5, +0.5);
            }
        }
        else {
            for (int i=0; i<Ndim; ++i) {
                min->SetVariable(i, Form("x%d", i), 0, 0.05);
            }
        }

        // Verbosity
        min->SetPrintLevel(1);

        // Algorithm strategy (higher=slower & more accurate)
        // min->SetStrategy(1);

        // Algorithms parameters
        min->SetMaxFunctionCalls(100000);
        min->SetMaxIterations(10000);
        min->SetTolerance(0.001);

        // Minimize!
        clock_t time = clock();
        bool success = min->Minimize();
        time = clock() - time;
        cout << "Success: " << success << endl;
        cout << "Time: " << 1000*(double)time/CLOCKS_PER_SEC << " ms " << endl;

        // Get out the values
        const double  minValue = min->MinValue();
        // const double* minPoint = min->X();
        // const double* minErrors= min->Errors();

        cout << "Value: " << minValue << endl;
        //~ for (int i=0; i<Ndim; ++i) {
            //~ cout << "x" << i+1 << ": " << minPoint[i];
            //~ if (minErrors!=nullptr) cout << " ± " << minErrors[i];
            //~ cout << endl;
        //~ }
        cout << endl;
    }

    // Now my minimizer
    {
        MCMinimizer* min = new MCMinimizer();
        cout << "Using algorithm: MCMinimizer" << endl;

        // Give the function to the minimizer
        min->SetMCFunction(rosenbrockN, Ndim);

        // Give the function variables
        for (int i=0; i<Ndim; ++i) {
            min->SetMCVariable(Form("x%d", i), 0, 0.9, 1.1);
        }

        // Verbosity
        min->SetPrintLevel(1);

        // Algorithms parameters
        min->SetMaxFunctionCalls(100000);

        // Minimize!
        clock_t time = clock();
        bool success = min->Minimize();
        time = clock() - time;
        cout << "Success: " << success << endl;
        cout << "Time: " << 1000*(double)time/CLOCKS_PER_SEC << " ms " << endl;

        // Get out the values
        const double  minValue = min->MinValue();
        // const double* minPoint = min->X();
        // const double* minErrors= min->Errors();

        cout << "Value: " << minValue << endl;
        //~ for (int i=0; i<Ndim; ++i) {
            //~ cout << "x" << i+1 << ": " << minPoint[i];
            //~ if (minErrors!=nullptr) cout << " ± " << minErrors[i];
            //~ cout << endl;
        //~ }
        cout << endl;
    }

    // Now my minimizer
    {
        MCZoomMinimizer* min = new MCZoomMinimizer();
        cout << "Using algorithm: MCMinimizer" << endl;

        // Give the function to the minimizer
        min->SetMCFunction(rosenbrockN, Ndim);

        // Give the function variables
        for (int i=0; i<Ndim; ++i) {
            min->SetMCVariable(Form("x%d", i), 0, 0.9, 1.1);
        }

        // Verbosity
        min->SetPrintLevel(1);

        // Algorithms parameters
        min->SetMaxFunctionCalls(100000);
        min->SetSplitNumber(10);

        // Minimize!
        clock_t time = clock();
        bool success = min->Minimize();
        time = clock() - time;
        cout << "Success: " << success << endl;
        cout << "Time: " << 1000*(double)time/CLOCKS_PER_SEC << " ms " << endl;

        // Get out the values
        const double  minValue = min->MinValue();
        // const double* minPoint = min->X();
        // const double* minErrors= min->Errors();

        cout << "Value: " << minValue << endl;
        //~ for (int i=0; i<Ndim; ++i) {
            //~ cout << "x" << i+1 << ": " << minPoint[i];
            //~ if (minErrors!=nullptr) cout << " ± " << minErrors[i];
            //~ cout << endl;
        //~ }
        cout << endl;
    }

    return 0;
}

int main(int, char**)
{
    return minimizer();
}
<commit_msg>Removed<commit_after>#include <iostream>
//~ #include <fstream>
//~ #include <cmath>
#include <ctime>

#include "TH1.h"
//~ #include "TH2.h"
//~ #include "TH3.h"
//~ #include "TCanvas.h"
#include "TRandom3.h"
//~ #include "TVector2.h"
//~ #include "TVector3.h"
//~ #include "TLorentzVector.h"
#include "TString.h"

#include "Math/Minimizer.h"
#include "Math/Factory.h"
#include "Math/Functor.h"

/* Algorithms list
 * minName              algoName
 * ---------------------------------
 * Minuit/Minuit2       Migrad, Simplex, Seek, Combined (default is Migrad)
 * Minuit/Minuit2       Scan (good for scans, not minimizations)
 * Minuit2              Fumili (*** needs different function type ***), Fumili2
 * Fumili               *** needs different function type ***
 * GSLMultiMin          ConjugateFR, ConjugatePR, BFGS, BFGS2, SteepestDescent
 * GSLMultiFit          *** needs different function type ***
 * GSLSimAn
 * Linear               *** needs linear function ***
 * Genetic              *** sloooow and inaccurate ***
 *
 *
 * https://root.cern.ch/fitting
 * https://root.cern.ch/numerical-minimization
 */

const int Ndim = 8;

using namespace ROOT::Math;
using namespace std;

double parabola1(const double* xx)
{
    double x = xx[0];
    double y = xx[1];
    return (x-3)*(x-3)+(y-2)*(y-2);
}

double parabolaN(const double* xx)
{
    double accumulator=0;
    for (int i=0; i< Ndim; ++i) {
        double c = i+1;
        accumulator += (xx[i]-1/c)*(xx[i]-1/c);
    }
    return accumulator;
}

double rosenbrockN(const double* xx)
{
    double accumulator=0;
    for (int i=0; i< Ndim-1; ++i) {
        accumulator += 100*pow(xx[i+1]-xx[i]*xx[i], 2) + pow(xx[i]-1, 2);
    }
    return accumulator;
}

class MCMinimizer
{
protected:
    TRandom3 rng;

    int Ndim = 0;
    double (*function)(const double*); // = &rosenbrockN;

    vector<double> params;
    vector<double> params_min;
    vector<double> params_max;
    vector<string> names;
    double minValue;

    int max_function_calls = 0;
    int printLevel;

public:
    MCMinimizer()
    {
        this->rng = TRandom3(12345);
    }

    inline void SetMCFunction(double (*function)(const double*), int Ndim)
    {
        this->function = function;
        this->Ndim = Ndim;
    }

    inline void SetMCVariable(string name, double val, double min, double max)
    {
        this->params.push_back(val);
        this->params_min.push_back(min);
        this->params_max.push_back(max);
        this->names.push_back(name);
    }

    inline void SetMaxFunctionCalls(int calls)
    {
        this->max_function_calls = calls;
    }

    bool Minimize()
    {
        if (printLevel) cout << "Minimize using MCMinimizer" << endl;
        this->minValue = this->function(&params[0]); // evaluate in given initial point

        for (int i=0; i<this->max_function_calls; ++i) {
            double pars_array[Ndim];
            for (int par=0; par < Ndim; ++par) {     // get random params vector
                pars_array[par] = rng.Uniform(params_min[par], params_max[par]);
            }
            double nmin = (*function)(pars_array);
            if (nmin < this->minValue) {
                this->minValue = nmin;
                params = vector<double>(pars_array, pars_array + Ndim);
            }
        }
        if (printLevel) {
            cout << "FVAL         = " << this->minValue << endl;
            for (int i=0; i<Ndim; ++i) {
                cout << names[i] << "\t  = " << params[i] << endl;
            }
        }
        return true;
    }

    inline void SetPrintLevel(int printLevel)
    {
        this->printLevel = printLevel;
    }

    inline double MinValue()
    {
        return this->minValue;
    }

    inline double* X()
    {
        return &(this->params[0]);
    }
};

int minimizer()
{
    // List of valid minimizers
    vector<pair<string,string>> minVector;
    //                                      name      algorithm
    // minVector.push_back(pair<string,string>("Minuit", "Migrad"));
    // minVector.push_back(pair<string,string>("Minuit", "Simplex"));
    // minVector.push_back(pair<string,string>("Minuit", "Combined"));
    // minVector.push_back(pair<string,string>("Minuit", "Seek"));
    // minVector.push_back(pair<string,string>("Minuit", "Scan"));

    minVector.push_back(pair<string,string>("Minuit2", "Migrad"));
    minVector.push_back(pair<string,string>("Minuit2", "Simplex"));
    // minVector.push_back(pair<string,string>("Minuit2", "Combined"));
    minVector.push_back(pair<string,string>("Minuit2", "Seek"));
    // minVector.push_back(pair<string,string>("Minuit2", "Scan"));
    // minVector.push_back(pair<string,string>("Minuit2", "Fumili"));
    minVector.push_back(pair<string,string>("Minuit2", "Fumili2"));

    // minVector.push_back(pair<string,string>("Fumili",  "Fumili"));

    minVector.push_back(pair<string,string>("GSLMultiMin", "ConjugateFR"));
    minVector.push_back(pair<string,string>("GSLMultiMin", "ConjugatePR"));
    minVector.push_back(pair<string,string>("GSLMultiMin", "BFGS"));
    minVector.push_back(pair<string,string>("GSLMultiMin", "BFGS2"));
    minVector.push_back(pair<string,string>("GSLMultiMin", "SteepestDescent"));

    // minVector.push_back(pair<string,string>("GSLMultiFit", ""));

    minVector.push_back(pair<string,string>("GSLSimAn", ""));

    // minVector.push_back(pair<string,string>("Linear", "");

    // minVector.push_back(pair<string,string>("Genetic", ""));

    for (unsigned int i=0; i < minVector.size(); ++i) {

        Minimizer* min = Factory::CreateMinimizer(minVector[i].first, minVector[i].second);
        if (min==nullptr) {
            cout << "Invalid algorithm: " << minVector[i].first << " - " << minVector[i].second << endl;
            continue;
        }
        else cout << "Using algorithm: " << minVector[i].first << " - " << minVector[i].second << endl;

        // The minimizer needs an IMultiGenFunction, which is easily provided
        // by a Functor, which is a generic wrapper class
        Functor fun = Functor(&rosenbrockN, Ndim);

        // Give the function to the minimizer
        min->SetFunction(fun);

        // Give the function variables
        if (minVector[i].first=="Genetic") {
            // Limited domain (genetic algorithm only)
            for (int i=0; i<Ndim; ++i) {
                min->SetLimitedVariable(i, Form("x%d", i), 0, 0.05, -0.5, +0.5);
            }
        }
        else {
            for (int i=0; i<Ndim; ++i) {
                min->SetVariable(i, Form("x%d", i), 0, 0.05);
            }
        }

        // Verbosity
        min->SetPrintLevel(1);

        // Algorithm strategy (higher=slower & more accurate)
        // min->SetStrategy(1);

        // Algorithms parameters
        min->SetMaxFunctionCalls(100000);
        min->SetMaxIterations(10000);
        min->SetTolerance(0.001);

        // Minimize!
        clock_t time = clock();
        bool success = min->Minimize();
        time = clock() - time;
        cout << "Success: " << success << endl;
        cout << "Time: " << 1000*(double)time/CLOCKS_PER_SEC << " ms " << endl;

        // Get out the values
        const double  minValue = min->MinValue();
        // const double* minPoint = min->X();
        // const double* minErrors= min->Errors();

        cout << "Value: " << minValue << endl;
        //~ for (int i=0; i<Ndim; ++i) {
            //~ cout << "x" << i+1 << ": " << minPoint[i];
            //~ if (minErrors!=nullptr) cout << " ± " << minErrors[i];
            //~ cout << endl;
        //~ }
        cout << endl;
    }

    // Now my minimizer
    {
        MCMinimizer* min = new MCMinimizer();
        cout << "Using algorithm: MCMinimizer" << endl;

        // Give the function to the minimizer
        min->SetMCFunction(rosenbrockN, Ndim);

        // Give the function variables
        for (int i=0; i<Ndim; ++i) {
            min->SetMCVariable(Form("x%d", i), 0, 0.9, 1.1);
        }

        // Verbosity
        min->SetPrintLevel(1);

        // Algorithms parameters
        min->SetMaxFunctionCalls(100000);

        // Minimize!
        clock_t time = clock();
        bool success = min->Minimize();
        time = clock() - time;
        cout << "Success: " << success << endl;
        cout << "Time: " << 1000*(double)time/CLOCKS_PER_SEC << " ms " << endl;

        // Get out the values
        const double  minValue = min->MinValue();
        // const double* minPoint = min->X();
        // const double* minErrors= min->Errors();

        cout << "Value: " << minValue << endl;
        //~ for (int i=0; i<Ndim; ++i) {
            //~ cout << "x" << i+1 << ": " << minPoint[i];
            //~ if (minErrors!=nullptr) cout << " ± " << minErrors[i];
            //~ cout << endl;
        //~ }
        cout << endl;
    }

    return 0;
}

int main(int, char**)
{
    return minimizer();
}
<|endoftext|>


<commit_before>#ifndef _SDD_DD_DEFINITION_HH_
#define _SDD_DD_DEFINITION_HH_

#include <initializer_list>
#include <type_traits> // is_integral

#include "sdd/dd/alpha.hh"
#include "sdd/dd/definition_fwd.hh"
#include "sdd/dd/node.hh"
#include "sdd/dd/terminal.hh"
#include "sdd/mem/ptr.hh"
#include "sdd/mem/ref_counted.hh"
#include "sdd/mem/variant.hh"
#include "sdd/order/order.hh"
#include "sdd/util/print_sizes_fwd.hh"

namespace sdd {

/*------------------------------------------------------------------------------------------------*/

/// @brief SDD at the deepest level.
template <typename C>
using flat_node = node<C, typename C::Values>;

/// @brief All but SDD at the deepest level.
template <typename C>
using hierarchical_node = node<C, SDD<C>>;

/*------------------------------------------------------------------------------------------------*/

/// @internal
/// @brief Tag to describe the type of a node.
enum class node_tag {flat, hierarchical};

/// @internal
/// @brief Signature of the meta-function that returns the node's type corresponding to the
/// given tag.
template <typename C, enum node_tag>
struct node_for_tag;

/// @internal
/// @brief Specialization for flat node.
template <typename C>
struct node_for_tag<C, node_tag::flat>
{
  typedef flat_node<C> type;
};

/// @internal
/// @brief Specialization for hierarchical node.
template <typename C>
struct node_for_tag<C, node_tag::hierarchical>
{
  typedef hierarchical_node<C> type;
};

/*------------------------------------------------------------------------------------------------*/

/// @brief Hierarchical Set Decision Diagram.
template <typename C>
class SDD final
{

  static_assert( std::is_integral<typename C::Variable>::value
               , "A variable must be an integral type.");

private:

  /// @brief A canonized SDD.
  ///
  /// This is the real recursive definition of an SDD: it can be a |0| or |1| terminal, or it
  /// can be a flat or an hierachical node.
  typedef mem::variant< const zero_terminal<C>, const one_terminal<C>
                      , const flat_node<C>, const hierarchical_node<C>>
          data_type;

  /// @brief A unified and canonized SDD, meant to be stored in a unique table.
  ///
  /// It is automatically erased when there is no more reference to it.
  typedef mem::ref_counted<const data_type> unique_type;

  /// @brief Define the smart pointer around a unified SDD.
  ///
  /// It handles the reference counting as well as the deletion of the SDD when it is no longer
  /// referenced.
  typedef mem::ptr<const unique_type> ptr_type;

public:

  /// @brief The type of variables.
  typedef typename C::Variable variable_type;

  /// @brief The type of a set of values.
  typedef typename C::Values values_type;

  /// @brief The type of a value in a set of values.
  typedef typename C::Values::value_type value_type;

private:

  /// @brief The real smart pointer around a unified SDD.
  ptr_type ptr_;

public:

  /// @brief Move constructor.
  ///
  /// O(1).
  SDD(SDD&&) noexcept = default;

  /// @brief Move operator.
  ///
  /// O(1).
  SDD&
  operator=(SDD&&) noexcept = default;

  /// @brief Copy constructor.
  ///
  /// O(1).
  SDD(const SDD&) noexcept = default;

  /// @brief Copy operator.
  ///
  /// O(1).
  SDD&
  operator=(const SDD&) noexcept = default;

  /// @internal
  /// @brief  Construct a terminal.
  /// @param  terminal If true, create the |1| terminal; the |0| terminal otherwise.
  /// @return The terminal |0| or |1|.
  ///
  /// O(1).
  SDD(bool terminal)
    : ptr_(terminal ? one_ptr() : zero_ptr())
  {
  }

  /// @brief Construct a hierarchical SDD.
  /// @param var  The SDD's variable.
  /// @param val  The SDD's valuation, a set of values constructed from an initialization list.
  /// @param succ The SDD's successor.
  ///
  /// O(1), for the creation of the SDD itself, but the complexity of the construction of the
  /// set of values depends on values_type.
  SDD(const variable_type& var, std::initializer_list<value_type> values, const SDD& succ)
    : ptr_(create_node(var, values_type(values), SDD(succ)))
  {
  }

  /// @brief Construct a flat SDD.
  /// @param var  The SDD's variable.
  /// @param val  The SDD's valuation, a set of values.
  /// @param succ The SDD's successor.
  ///
  /// O(1).
  SDD(const variable_type& var, values_type&& val, const SDD& succ)
    : ptr_(create_node(var, std::move(val), succ))
  {
  }

  /// @brief Construct a flat SDD.
  /// @param var  The SDD's variable.
  /// @param val  The SDD's valuation, a set of values.
  /// @param succ The SDD's successor.
  ///
  /// O(1).
  SDD(const variable_type& var, const values_type& val, const SDD& succ)
    : ptr_(create_node(var, val, succ))
  {
  }

  /// @brief Construct a hierarchical SDD.
  /// @param var  The SDD's variable.
  /// @param val  The SDD's valuation, an SDD in this case.
  /// @param succ The SDD's successor.
  ///
  /// O(1).
  SDD(const variable_type& var, const SDD& val, const SDD& succ)
    : ptr_(create_node(var, val, succ))
  {
  }

  /// @brief Construct an SDD with an order.
  template <typename Initializer>
  SDD(const order<C>& o, const Initializer& init)
    : ptr_(one_ptr())
  {
    if (o.empty())
    {
      return;
    }
    // flat
    else if (o.nested().empty())
    {
      ptr_ = create_node(o.variable(), init(o.identifier()), SDD(o.next(), init));
    }
    // hierarchical
    else
    {
      ptr_ = create_node(o.variable(), SDD(o.nested(), init), SDD(o.next(), init));
    }
  }

  /// @brief  Indicate if the SDD is |0|.
  /// @return true if the SDD is |0|, false otherwise.
  ///
  /// O(1).
  bool
  empty()
  const noexcept
  {
    return ptr_ == zero_ptr();
  }

  /// @brief Swap two SDD.
  ///
  /// O(1).
  friend void
  swap(SDD& lhs, SDD& rhs)
  noexcept
  {
    using std::swap;
    swap(lhs.ptr_, rhs.ptr_);
  }

  /// @internal
  /// @brief Construct an SDD from a ptr.
  ///
  /// O(1).
  SDD(const ptr_type& ptr)
  noexcept
    : ptr_(ptr)
  {
  }

  /// @internal
  /// @brief Construct an SDD from a moved ptr.
  ///
  /// O(1).
  SDD(ptr_type&& ptr)
  noexcept
    : ptr_(std::move(ptr))
  {
  }

  /// @internal
  /// @brief  Construct an SDD, flat or hierarchical, with an alpha.
  /// \tparam Valuation If an SDD, constructs a hierarchical SDD; if a set of values,
  /// constructs a flat SDD.
  ///
  /// O(n) where n is the number of arcs in the builder.
  template <typename Valuation>
  SDD(const variable_type& var, dd::alpha_builder<C, Valuation>&& builder)
    : ptr_(create_node(var, std::move(builder)))
  {
  }

  /// @internal
  /// @brief Get the content of the SDD (an mem::ref_counted).
  ///
  /// O(1).
  const unique_type&
  operator*()
  const noexcept
  {
    return *ptr_;
  }

  /// @internal
  /// @brief Get a pointer to the content of the SDD (an mem::ref_counted).
  ///
  /// O(1).
  const unique_type*
  operator->()
  const noexcept
  {
    return ptr_.operator->();
  }

  /// @internal
  /// @brief Get the real smart pointer of the unified data.
  ///
  /// O(1).
  ptr_type
  ptr()
  const noexcept
  {
    return ptr_;
  }

  /// @internal
  /// @brief Create the |0| terminal.
  ///
  /// O(1). The |0| is cached in a static variable.
  static
  ptr_type
  zero_ptr()
  {
    static char* addr = mem::allocate<unique_type>();
    static unique_type* z = new (addr) unique_type(mem::construct<zero_terminal<C>>());
    static const ptr_type zero(mem::unify(z));
    return zero;
  }

  /// @internal
  /// @brief Create the |1| terminal.
  ///
  /// O(1). The |1| is cached in a static variable.
  static
  ptr_type
  one_ptr()
  {
    static char* addr = mem::allocate<unique_type>();
    static unique_type* o = new (addr) unique_type(mem::construct<one_terminal<C>>());
    static const ptr_type one(mem::unify(o));
    return one;
  }

private:

  /// @internal
  /// @brief Helper function to create a node, flat or hierarchical, with only one arc.
  ///
  /// O(1).
  template <typename Valuation>
  static
  ptr_type
  create_node(const variable_type& var, Valuation&& val, const SDD& succ)
  {
    if (succ.empty() or val.empty())
    {
      return zero_ptr();
    }
    else
    {
      dd::alpha_builder<C, Valuation> builder;
      builder.add(std::move(val), succ);
      return unify_node<Valuation>(var, std::move(builder));
    }
  }

  /// @internal
  /// @brief Helper function to create a node, flat or hierarchical, with only one arc.
  ///
  /// O(1).
  template <typename Valuation>
  static
  ptr_type
  create_node(const variable_type& var, const Valuation& val, const SDD& succ)
  {
    if (succ.empty() or val.empty())
    {
      return zero_ptr();
    }
    else
    {
      dd::alpha_builder<C, Valuation> builder;
      builder.add(val, succ);
      return unify_node<Valuation>(var, std::move(builder));
    }
  }

  /// @internal
  /// @brief Helper function to create a node, flat or hierarchical, from an alpha.
  ///
  /// O(n) where n is the number of arcs in the builder.
  template <typename Valuation>
  static
  ptr_type
  create_node(const variable_type& var, dd::alpha_builder<C, Valuation>&& builder)
  {
    if (builder.empty())
    {
      return zero_ptr();
    }
    else
    {
      return unify_node<Valuation>(var, std::move(builder));
    }
  }

  /// @internal
  /// @brief Helper function to unify a node, flat or hierarchical, from an alpha.
  ///
  /// O(n) where n is the number of arcs in the builder.
  template <typename Valuation>
  static
  const unique_type&
  unify_node(const variable_type& var, dd::alpha_builder<C, Valuation>&& builder)
  {
    // Will be erased by the unicity table, either it's an already existing node or a deletion
    // is requested by ptr.
    // Note that the alpha function is allocated right behind the node, thus extra care must be
    // taken. This is also why we use Boost.Intrusive in order to be able to manage memory
    // exactly the way we want.
    char* addr = mem::allocate<unique_type>(builder.size_to_allocate());
    unique_type* u =
      new (addr) unique_type(mem::construct<node<C, Valuation>>(), var, builder);
    return mem::unify(u);
  }

  friend void util::print_sizes<C>(std::ostream&);
};

/*------------------------------------------------------------------------------------------------*/

/// @brief   Equality of two SDD.
/// @related SDD
///
/// O(1).
template <typename C>
inline
bool
operator==(const SDD<C>& lhs, const SDD<C>& rhs)
noexcept
{
  return lhs.ptr() == rhs.ptr();
}

/// @brief   Inequality of two SDD.
/// @related SDD
///
/// O(1).
template <typename C>
inline
bool
operator!=(const SDD<C>& lhs, const SDD<C>& rhs)
noexcept
{
  return not (lhs.ptr() == rhs.ptr());
}

/// @brief   Comparison of two SDD.
/// @related SDD
///
/// O(1). The order of SDD is arbitrary and can change at each run.
template <typename C>
inline
bool
operator<(const SDD<C>& lhs, const SDD<C>& rhs)
noexcept
{
  return lhs.ptr() < rhs.ptr();
}

/// @brief   Export the textual representation of an SDD to a stream.
/// @related SDD
///
/// Use only with small SDD, output can be huge.
template <typename C>
std::ostream&
operator<<(std::ostream& os, const SDD<C>& x)
{
  return os << x->data();
}

/*------------------------------------------------------------------------------------------------*/

/// @brief Return the |0| terminal.
/// @related SDD
///
/// O(1).
template <typename C>
inline
SDD<C>
zero()
noexcept
{
  return {false};
}

/// @brief Return the |1| terminal.
/// @related SDD
///
/// O(1).
template <typename C>
inline
SDD<C>
one()
noexcept
{
  return {true};
}

/*------------------------------------------------------------------------------------------------*/

} // namespace sdd

namespace std {

/*------------------------------------------------------------------------------------------------*/

/// @brief Hash specialization for sdd::dd::SDD.
template <typename C>
struct hash<sdd::SDD<C>>
{
  std::size_t
  operator()(const sdd::SDD<C>& x)
  const noexcept
  {
    return std::hash<decltype(x.ptr())>()(x.ptr());
  }
};

/*------------------------------------------------------------------------------------------------*/

} // namespace std

#endif // _SDD_DD_DEFINITION_HH_
<commit_msg>SDD: zero_ptr() and one_ptr() are private.<commit_after>#ifndef _SDD_DD_DEFINITION_HH_
#define _SDD_DD_DEFINITION_HH_

#include <initializer_list>
#include <type_traits> // is_integral

#include "sdd/dd/alpha.hh"
#include "sdd/dd/definition_fwd.hh"
#include "sdd/dd/node.hh"
#include "sdd/dd/terminal.hh"
#include "sdd/mem/ptr.hh"
#include "sdd/mem/ref_counted.hh"
#include "sdd/mem/variant.hh"
#include "sdd/order/order.hh"
#include "sdd/util/print_sizes_fwd.hh"

namespace sdd {

/*------------------------------------------------------------------------------------------------*/

/// @brief SDD at the deepest level.
template <typename C>
using flat_node = node<C, typename C::Values>;

/// @brief All but SDD at the deepest level.
template <typename C>
using hierarchical_node = node<C, SDD<C>>;

/*------------------------------------------------------------------------------------------------*/

/// @internal
/// @brief Tag to describe the type of a node.
enum class node_tag {flat, hierarchical};

/// @internal
/// @brief Signature of the meta-function that returns the node's type corresponding to the
/// given tag.
template <typename C, enum node_tag>
struct node_for_tag;

/// @internal
/// @brief Specialization for flat node.
template <typename C>
struct node_for_tag<C, node_tag::flat>
{
  typedef flat_node<C> type;
};

/// @internal
/// @brief Specialization for hierarchical node.
template <typename C>
struct node_for_tag<C, node_tag::hierarchical>
{
  typedef hierarchical_node<C> type;
};

/*------------------------------------------------------------------------------------------------*/

/// @brief Hierarchical Set Decision Diagram.
template <typename C>
class SDD final
{

  static_assert( std::is_integral<typename C::Variable>::value
               , "A variable must be an integral type.");

private:

  /// @brief A canonized SDD.
  ///
  /// This is the real recursive definition of an SDD: it can be a |0| or |1| terminal, or it
  /// can be a flat or an hierachical node.
  typedef mem::variant< const zero_terminal<C>, const one_terminal<C>
                      , const flat_node<C>, const hierarchical_node<C>>
          data_type;

  /// @brief A unified and canonized SDD, meant to be stored in a unique table.
  ///
  /// It is automatically erased when there is no more reference to it.
  typedef mem::ref_counted<const data_type> unique_type;

  /// @brief Define the smart pointer around a unified SDD.
  ///
  /// It handles the reference counting as well as the deletion of the SDD when it is no longer
  /// referenced.
  typedef mem::ptr<const unique_type> ptr_type;

public:

  /// @brief The type of variables.
  typedef typename C::Variable variable_type;

  /// @brief The type of a set of values.
  typedef typename C::Values values_type;

  /// @brief The type of a value in a set of values.
  typedef typename C::Values::value_type value_type;

private:

  /// @brief The real smart pointer around a unified SDD.
  ptr_type ptr_;

public:

  /// @brief Move constructor.
  ///
  /// O(1).
  SDD(SDD&&) noexcept = default;

  /// @brief Move operator.
  ///
  /// O(1).
  SDD&
  operator=(SDD&&) noexcept = default;

  /// @brief Copy constructor.
  ///
  /// O(1).
  SDD(const SDD&) noexcept = default;

  /// @brief Copy operator.
  ///
  /// O(1).
  SDD&
  operator=(const SDD&) noexcept = default;

  /// @internal
  /// @brief  Construct a terminal.
  /// @param  terminal If true, create the |1| terminal; the |0| terminal otherwise.
  /// @return The terminal |0| or |1|.
  ///
  /// O(1).
  SDD(bool terminal)
    : ptr_(terminal ? one_ptr() : zero_ptr())
  {
  }

  /// @brief Construct a hierarchical SDD.
  /// @param var  The SDD's variable.
  /// @param val  The SDD's valuation, a set of values constructed from an initialization list.
  /// @param succ The SDD's successor.
  ///
  /// O(1), for the creation of the SDD itself, but the complexity of the construction of the
  /// set of values depends on values_type.
  SDD(const variable_type& var, std::initializer_list<value_type> values, const SDD& succ)
    : ptr_(create_node(var, values_type(values), SDD(succ)))
  {
  }

  /// @brief Construct a flat SDD.
  /// @param var  The SDD's variable.
  /// @param val  The SDD's valuation, a set of values.
  /// @param succ The SDD's successor.
  ///
  /// O(1).
  SDD(const variable_type& var, values_type&& val, const SDD& succ)
    : ptr_(create_node(var, std::move(val), succ))
  {
  }

  /// @brief Construct a flat SDD.
  /// @param var  The SDD's variable.
  /// @param val  The SDD's valuation, a set of values.
  /// @param succ The SDD's successor.
  ///
  /// O(1).
  SDD(const variable_type& var, const values_type& val, const SDD& succ)
    : ptr_(create_node(var, val, succ))
  {
  }

  /// @brief Construct a hierarchical SDD.
  /// @param var  The SDD's variable.
  /// @param val  The SDD's valuation, an SDD in this case.
  /// @param succ The SDD's successor.
  ///
  /// O(1).
  SDD(const variable_type& var, const SDD& val, const SDD& succ)
    : ptr_(create_node(var, val, succ))
  {
  }

  /// @brief Construct an SDD with an order.
  template <typename Initializer>
  SDD(const order<C>& o, const Initializer& init)
    : ptr_(one_ptr())
  {
    if (o.empty())
    {
      return;
    }
    // flat
    else if (o.nested().empty())
    {
      ptr_ = create_node(o.variable(), init(o.identifier()), SDD(o.next(), init));
    }
    // hierarchical
    else
    {
      ptr_ = create_node(o.variable(), SDD(o.nested(), init), SDD(o.next(), init));
    }
  }

  /// @brief  Indicate if the SDD is |0|.
  /// @return true if the SDD is |0|, false otherwise.
  ///
  /// O(1).
  bool
  empty()
  const noexcept
  {
    return ptr_ == zero_ptr();
  }

  /// @brief Swap two SDD.
  ///
  /// O(1).
  friend void
  swap(SDD& lhs, SDD& rhs)
  noexcept
  {
    using std::swap;
    swap(lhs.ptr_, rhs.ptr_);
  }

  /// @internal
  /// @brief Construct an SDD from a ptr.
  ///
  /// O(1).
  SDD(const ptr_type& ptr)
  noexcept
    : ptr_(ptr)
  {
  }

  /// @internal
  /// @brief Construct an SDD from a moved ptr.
  ///
  /// O(1).
  SDD(ptr_type&& ptr)
  noexcept
    : ptr_(std::move(ptr))
  {
  }

  /// @internal
  /// @brief  Construct an SDD, flat or hierarchical, with an alpha.
  /// \tparam Valuation If an SDD, constructs a hierarchical SDD; if a set of values,
  /// constructs a flat SDD.
  ///
  /// O(n) where n is the number of arcs in the builder.
  template <typename Valuation>
  SDD(const variable_type& var, dd::alpha_builder<C, Valuation>&& builder)
    : ptr_(create_node(var, std::move(builder)))
  {
  }

  /// @internal
  /// @brief Get the content of the SDD (an mem::ref_counted).
  ///
  /// O(1).
  const unique_type&
  operator*()
  const noexcept
  {
    return *ptr_;
  }

  /// @internal
  /// @brief Get a pointer to the content of the SDD (an mem::ref_counted).
  ///
  /// O(1).
  const unique_type*
  operator->()
  const noexcept
  {
    return ptr_.operator->();
  }

  /// @internal
  /// @brief Get the real smart pointer of the unified data.
  ///
  /// O(1).
  ptr_type
  ptr()
  const noexcept
  {
    return ptr_;
  }

  /// @internal
  /// @brief Create the |0| terminal.
private:

  ///
  /// O(1). The |0| is cached in a static variable.
  static
  ptr_type
  zero_ptr()
  {
    static char* addr = mem::allocate<unique_type>();
    static unique_type* z = new (addr) unique_type(mem::construct<zero_terminal<C>>());
    static const ptr_type zero(mem::unify(z));
    return zero;
  }

  /// @internal
  /// @brief Create the |1| terminal.
  ///
  /// O(1). The |1| is cached in a static variable.
  static
  ptr_type
  one_ptr()
  {
    static char* addr = mem::allocate<unique_type>();
    static unique_type* o = new (addr) unique_type(mem::construct<one_terminal<C>>());
    static const ptr_type one(mem::unify(o));
    return one;
  }

  /// @internal
  /// @brief Helper function to create a node, flat or hierarchical, with only one arc.
  ///
  /// O(1).
  template <typename Valuation>
  static
  ptr_type
  create_node(const variable_type& var, Valuation&& val, const SDD& succ)
  {
    if (succ.empty() or val.empty())
    {
      return zero_ptr();
    }
    else
    {
      dd::alpha_builder<C, Valuation> builder;
      builder.add(std::move(val), succ);
      return unify_node<Valuation>(var, std::move(builder));
    }
  }

  /// @internal
  /// @brief Helper function to create a node, flat or hierarchical, with only one arc.
  ///
  /// O(1).
  template <typename Valuation>
  static
  ptr_type
  create_node(const variable_type& var, const Valuation& val, const SDD& succ)
  {
    if (succ.empty() or val.empty())
    {
      return zero_ptr();
    }
    else
    {
      dd::alpha_builder<C, Valuation> builder;
      builder.add(val, succ);
      return unify_node<Valuation>(var, std::move(builder));
    }
  }

  /// @internal
  /// @brief Helper function to create a node, flat or hierarchical, from an alpha.
  ///
  /// O(n) where n is the number of arcs in the builder.
  template <typename Valuation>
  static
  ptr_type
  create_node(const variable_type& var, dd::alpha_builder<C, Valuation>&& builder)
  {
    if (builder.empty())
    {
      return zero_ptr();
    }
    else
    {
      return unify_node<Valuation>(var, std::move(builder));
    }
  }

  /// @internal
  /// @brief Helper function to unify a node, flat or hierarchical, from an alpha.
  ///
  /// O(n) where n is the number of arcs in the builder.
  template <typename Valuation>
  static
  const unique_type&
  unify_node(const variable_type& var, dd::alpha_builder<C, Valuation>&& builder)
  {
    // Will be erased by the unicity table, either it's an already existing node or a deletion
    // is requested by ptr.
    // Note that the alpha function is allocated right behind the node, thus extra care must be
    // taken. This is also why we use Boost.Intrusive in order to be able to manage memory
    // exactly the way we want.
    char* addr = mem::allocate<unique_type>(builder.size_to_allocate());
    unique_type* u =
      new (addr) unique_type(mem::construct<node<C, Valuation>>(), var, builder);
    return mem::unify(u);
  }

  friend void util::print_sizes<C>(std::ostream&);
};

/*------------------------------------------------------------------------------------------------*/

/// @brief   Equality of two SDD.
/// @related SDD
///
/// O(1).
template <typename C>
inline
bool
operator==(const SDD<C>& lhs, const SDD<C>& rhs)
noexcept
{
  return lhs.ptr() == rhs.ptr();
}

/// @brief   Inequality of two SDD.
/// @related SDD
///
/// O(1).
template <typename C>
inline
bool
operator!=(const SDD<C>& lhs, const SDD<C>& rhs)
noexcept
{
  return not (lhs.ptr() == rhs.ptr());
}

/// @brief   Comparison of two SDD.
/// @related SDD
///
/// O(1). The order of SDD is arbitrary and can change at each run.
template <typename C>
inline
bool
operator<(const SDD<C>& lhs, const SDD<C>& rhs)
noexcept
{
  return lhs.ptr() < rhs.ptr();
}

/// @brief   Export the textual representation of an SDD to a stream.
/// @related SDD
///
/// Use only with small SDD, output can be huge.
template <typename C>
std::ostream&
operator<<(std::ostream& os, const SDD<C>& x)
{
  return os << x->data();
}

/*------------------------------------------------------------------------------------------------*/

/// @brief Return the |0| terminal.
/// @related SDD
///
/// O(1).
template <typename C>
inline
SDD<C>
zero()
noexcept
{
  return {false};
}

/// @brief Return the |1| terminal.
/// @related SDD
///
/// O(1).
template <typename C>
inline
SDD<C>
one()
noexcept
{
  return {true};
}

/*------------------------------------------------------------------------------------------------*/

} // namespace sdd

namespace std {

/*------------------------------------------------------------------------------------------------*/

/// @brief Hash specialization for sdd::dd::SDD.
template <typename C>
struct hash<sdd::SDD<C>>
{
  std::size_t
  operator()(const sdd::SDD<C>& x)
  const noexcept
  {
    return std::hash<decltype(x.ptr())>()(x.ptr());
  }
};

/*------------------------------------------------------------------------------------------------*/

} // namespace std

#endif // _SDD_DD_DEFINITION_HH_
<|endoftext|>