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

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

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

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

=========================================================================*/
#include <iostream>
#include <fstream>

#include "itkPointSet.h"
#include "itkImageRegionIterator.h"
#include "itkVariableLengthVector.h"
#include "itkResampleImageFilter.h"
#include "itkDanielssonDistanceMapImageFilter.h"
#include "itkSubtractImageFilter.h"
#include "itkMinimumMaximumImageCalculator.h"
#include "itkShrinkImageFilter.h"
#include "itkExpandImageFilter.h"
#include "itkPointSetToImageFilter.h"
#include "itkRescaleIntensityImageFilter.h"

#include "otbImageToSIFTKeyPointSetFilter.h"
#include "otbImage.h"
#include "otbImageFileReader.h"
#include "otbImageFileWriter.h"

typedef itk::VariableLengthVector<float> RealVectorType;
typedef itk::PointSet<RealVectorType,2> PointSetType;
typedef otb::Image<float,2> ImageType;
typedef otb::Image<unsigned char, 2> OutputImageType;

// PointSet iterator types
typedef PointSetType::PointsContainer PointsContainerType;
typedef PointsContainerType::Iterator PointsIteratorType;
typedef PointSetType::PointDataContainer PointDataContainerType;
typedef PointDataContainerType::Iterator PointDataIteratorType;

// Filter
typedef otb::ImageFileReader<ImageType> ReaderType;
typedef otb::ImageFileWriter<OutputImageType> WriterType;
typedef otb::ImageFileWriter<ImageType> WriterInputType;
typedef otb::ImageToSIFTKeyPointSetFilter<ImageType,PointSetType> SiftFilterType;
typedef itk::DanielssonDistanceMapImageFilter <OutputImageType, OutputImageType> DDMFilterType;
typedef itk::ResampleImageFilter<ImageType, ImageType> ResampleFilterType1;
typedef itk::ResampleImageFilter<OutputImageType, OutputImageType> ResampleFilterType2;
typedef itk::AffineTransform<double, 2> TransformType;
typedef itk::SubtractImageFilter<OutputImageType, OutputImageType, ImageType> SubtractFilterType;
typedef itk::MinimumMaximumImageCalculator<ImageType> MaximumCalculatorType;
typedef itk::ShrinkImageFilter<ImageType, ImageType> ShrinkFilterType;
typedef itk::ExpandImageFilter<OutputImageType, OutputImageType> ExpandFilterType;
typedef itk::PointSetToImageFilter<PointSetType, OutputImageType> PointSetFilterType;
typedef itk::RescaleIntensityImageFilter<ImageType, ImageType> RescaleFilterType;
typedef itk::RescaleIntensityImageFilter<ImageType, OutputImageType> OutputRescaleFilterType;

OutputImageType::Pointer base( ImageType::Pointer input,
			       const unsigned octaves,
			       const unsigned int scales,
			       const float threshold,
			       const float ratio)
{
  SiftFilterType::Pointer sift = SiftFilterType::New();
  DDMFilterType::Pointer ddmFilter = DDMFilterType::New();
  PointSetFilterType::Pointer pointSetFilter = PointSetFilterType::New();

  sift->SetInput(0,input);
  sift->SetOctavesNumber(octaves);
  sift->SetScalesNumber(scales);
  sift->SetDoGThreshold(threshold);
  sift->SetEdgeThreshold(ratio);

  pointSetFilter->SetInput(sift->GetOutput());
  pointSetFilter->SetInsideValue(255);
  pointSetFilter->SetOutsideValue(0);
  pointSetFilter->SetSize(input->GetLargestPossibleRegion().GetSize());
  pointSetFilter->SetSpacing(input->GetSpacing());
  pointSetFilter->SetOrigin(input->GetOrigin());

  ddmFilter->SetInput(pointSetFilter->GetOutput());
  ddmFilter->InputIsBinaryOn();
  ddmFilter->Update();

  WriterType::Pointer writer = WriterType::New();
  writer->SetFileName("base_keys.png");
  writer->SetInput(pointSetFilter->GetOutput());
  writer->Update();

  std::cout << "Image base   -> sift key points -> ddm1" << std::endl;

  return ddmFilter->GetOutput();
}

OutputImageType::Pointer rotate( ImageType::Pointer input,
				 const unsigned int octaves,
				 const unsigned int scales,
				 const float threshold,
				 const float ratio,
				 const unsigned int rotation)
{
  SiftFilterType::Pointer sift = SiftFilterType::New();
  DDMFilterType::Pointer ddmFilter = DDMFilterType::New();
  PointSetFilterType::Pointer pointSetFilter = PointSetFilterType::New();

  ResampleFilterType1::Pointer resampler1 = ResampleFilterType1::New();
  ResampleFilterType2::Pointer resampler2 = ResampleFilterType2::New();

  TransformType::Pointer transform1 = TransformType::New();
  TransformType::Pointer transform2 = TransformType::New();

  TransformType::OutputVectorType translation1;
  TransformType::OutputVectorType translation2;
  TransformType::OutputVectorType translation3;
  TransformType::OutputVectorType translation4;

  const ImageType::SpacingType& spacing1 = input->GetSpacing();
  const ImageType::PointType& origin1  = input->GetOrigin();
  ImageType::SizeType size1 = input->GetLargestPossibleRegion().GetSize();

  const double imageCenterX1 = origin1[0] + spacing1[0] * size1[0] / 2.0;
  const double imageCenterY1 = origin1[1] + spacing1[1] * size1[1] / 2.0;
  const double degreesToRadians = atan(1.0) / 45.0;
  const double angle = rotation * degreesToRadians;

  translation1[0] = -imageCenterX1;
  translation1[1] = -imageCenterY1;
  translation2[0] = imageCenterX1;
  translation2[1] = imageCenterY1;

  transform1->Translate( translation1 );
  transform1->Rotate2D( -angle, false );
  transform1->Translate( translation2 );

  resampler1->SetOutputOrigin( origin1 );
  resampler1->SetOutputSpacing( spacing1 );
  resampler1->SetSize( size1 );
  resampler1->SetTransform(transform1);
  resampler1->SetInput(input);
  resampler1->Update();

  sift->SetInput(0,resampler1->GetOutput());
  sift->SetOctavesNumber(octaves);
  sift->SetScalesNumber(scales);
  sift->SetDoGThreshold(threshold);
  sift->SetEdgeThreshold(ratio);

  pointSetFilter->SetInput(sift->GetOutput());
  pointSetFilter->SetInsideValue(255);
  pointSetFilter->SetOutsideValue(0);
  pointSetFilter->SetSize(resampler1->GetOutput()->GetLargestPossibleRegion().GetSize());
  pointSetFilter->SetSpacing(resampler1->GetOutput()->GetSpacing());
  pointSetFilter->SetOrigin(resampler1->GetOutput()->GetOrigin());

  pointSetFilter->Update();

  const ImageType::SpacingType& spacing2 = pointSetFilter->GetOutput()->GetSpacing();
  const ImageType::PointType& origin2  = pointSetFilter->GetOutput()->GetOrigin();
  ImageType::SizeType size2 = pointSetFilter->GetOutput()->GetLargestPossibleRegion().GetSize();

  const double imageCenterX2 = origin2[0] + spacing2[0] * size2[0] / 2.0;
  const double imageCenterY2 = origin2[1] + spacing2[1] * size2[1] / 2.0;

  translation3[0] = -imageCenterX2;
  translation3[1] = -imageCenterY2;
  translation4[0] = imageCenterX2;
  translation4[1] = imageCenterY2;

  transform2->Translate( translation3 );
  transform2->Rotate2D( angle, false );
  transform2->Translate( translation4 );

  resampler2->SetOutputOrigin( origin2 );
  resampler2->SetOutputSpacing( spacing2 );
  resampler2->SetSize( size2 );
  resampler2->SetTransform(transform2);
  resampler2->SetInput(pointSetFilter->GetOutput());

  ddmFilter->SetInput(resampler2->GetOutput());
  ddmFilter->InputIsBinaryOn();
  ddmFilter->Update();

  WriterType::Pointer writer1 = WriterType::New();
  writer1->SetFileName("rotate_keys_a.png");
  writer1->SetInput(pointSetFilter->GetOutput());
  writer1->Update();

  WriterType::Pointer writer2 = WriterType::New();
  writer2->SetFileName("rotate_keys_b.png");
  writer2->SetInput(resampler2->GetOutput());
  writer2->Update();

  std::cout << "Image rotate   -> sift key points -> ddm2" << std::endl;
  return ddmFilter->GetOutput();
}

OutputImageType::Pointer zoom( ImageType::Pointer input,
			       const unsigned int octaves,
			       const unsigned int scales,
			       const float threshold,
			       const float ratio,
			       const unsigned int zoomFactor)
{
  SiftFilterType::Pointer sift = SiftFilterType::New();
  DDMFilterType::Pointer ddmFilter = DDMFilterType::New();
  PointSetFilterType::Pointer pointSetFilter = PointSetFilterType::New();

  ShrinkFilterType::Pointer shrink = ShrinkFilterType::New();
  ExpandFilterType::Pointer expand = ExpandFilterType::New();

  shrink->SetInput(input);
  shrink->SetShrinkFactors(zoomFactor);
  shrink->Update();

  sift->SetInput(0,shrink->GetOutput());
  sift->SetOctavesNumber(octaves);
  sift->SetScalesNumber(scales);
  sift->SetDoGThreshold(threshold);
  sift->SetEdgeThreshold(ratio);

  pointSetFilter->SetInput(sift->GetOutput());
  pointSetFilter->SetInsideValue(255);
  pointSetFilter->SetOutsideValue(0);
  pointSetFilter->SetSize(shrink->GetOutput()->GetLargestPossibleRegion().GetSize());
  pointSetFilter->SetSpacing(shrink->GetOutput()->GetSpacing());
  pointSetFilter->SetOrigin(shrink->GetOutput()->GetOrigin());
  pointSetFilter->Update();

  expand->SetInput(pointSetFilter->GetOutput());
  expand->SetExpandFactors(zoomFactor);
  expand->Update();

  ddmFilter->SetInput(expand->GetOutput());
  ddmFilter->InputIsBinaryOn();
  ddmFilter->Update();

  WriterType::Pointer writer1 = WriterType::New();
  writer1->SetFileName("zoom_keys_a.png");
  writer1->SetInput(pointSetFilter->GetOutput());
  writer1->Update();

  WriterType::Pointer writer2 = WriterType::New();
  writer2->SetFileName("zoom_keys_b.png");
  writer2->SetInput(expand->GetOutput());
  writer2->Update();

  std::cout << "Image zoom   -> sift key points -> ddm3" << std::endl;
  return ddmFilter->GetOutput();
}

OutputImageType::Pointer contrast(ImageType::Pointer input,
				  const unsigned int octaves,
				  const unsigned int scales,
				  const float threshold,
				  const float ratio,
				  const unsigned int contrastMin,
				  const unsigned int contrastMax)
{
  SiftFilterType::Pointer sift = SiftFilterType::New();
  DDMFilterType::Pointer ddmFilter = DDMFilterType::New();
  PointSetFilterType::Pointer pointSetFilter = PointSetFilterType::New();
  RescaleFilterType::Pointer rescaler= RescaleFilterType::New();

  rescaler->SetInput(input);
  rescaler->SetOutputMinimum(static_cast<RescaleFilterType::OutputPixelType>(contrastMin));
  rescaler->SetOutputMaximum(static_cast<RescaleFilterType::OutputPixelType>(contrastMax));

  sift->SetInput(0,rescaler->GetOutput());
  sift->SetOctavesNumber(octaves);
  sift->SetScalesNumber(scales);
  sift->SetDoGThreshold(threshold);
  sift->SetEdgeThreshold(ratio);

  pointSetFilter->SetInput(sift->GetOutput());
  pointSetFilter->SetInsideValue(255);
  pointSetFilter->SetOutsideValue(0);
  pointSetFilter->SetSize(input->GetLargestPossibleRegion().GetSize());
  pointSetFilter->SetSpacing(input->GetSpacing());
  pointSetFilter->SetOrigin(input->GetOrigin());

  ddmFilter->SetInput(pointSetFilter->GetOutput());
  ddmFilter->InputIsBinaryOn();
  ddmFilter->Update();

  std::cout << "Image contrast   -> sift key points -> ddm4" << std::endl;
  return ddmFilter->GetOutput();
}

void combine()
{
  std::cout << "Image combine   -> sift key points -> ddm5" << std::endl;
}

void subtract(OutputImageType::Pointer image1,
	      OutputImageType::Pointer image2)
{
  SubtractFilterType::Pointer subtract = SubtractFilterType::New();
  MaximumCalculatorType::Pointer maximumCalculator = MaximumCalculatorType::New();

  subtract->SetInput1(image1);
  subtract->SetInput2(image2);
  subtract->Update();

  OutputRescaleFilterType::Pointer rescaler = OutputRescaleFilterType::New();
  rescaler->SetInput(subtract->GetOutput());
  rescaler->SetOutputMinimum(0);
  rescaler->SetOutputMaximum(255);

  WriterType::Pointer writer = WriterType::New();
  writer->SetFileName("subtract.png");
  writer->SetInput(rescaler->GetOutput());
  writer->Update();

  WriterType::Pointer writer2 = WriterType::New();
  writer2->SetFileName("ddm1.png");
  writer2->SetInput(image1);
  writer2->Update();

  WriterType::Pointer writer3 = WriterType::New();
  writer3->SetFileName("ddm2.png");
  writer3->SetInput(image2);
  writer3->Update();

  maximumCalculator->SetImage(subtract->GetOutput());
  maximumCalculator->ComputeMaximum();

  std::cout << "Max(sub)= " << maximumCalculator->GetMaximum() << std::endl;
}

int otbImageToSIFTKeyPointSetFilterDistanceMap(int argc, char * argv[])
{
  // Input Image file name
  const char * infname = argv[1];

  const unsigned int octaves = atoi(argv[2]);
  const unsigned int scales = atoi(argv[3]);
  const float threshold = atof(argv[4]);
  const float ratio = atof(argv[5]);

  // Rotation angle [0,360[
  const unsigned int rotation = atoi(argv[6]);

  // Zoom factor
  const unsigned int zoomFactor = atoi(argv[7]);

  // contrast factor
  const unsigned int contrastMin = atoi(argv[8]);
  const unsigned int contrastMax = atoi(argv[9]);

  ReaderType::Pointer reader = ReaderType::New();
  reader->SetFileName(infname);
  reader->Update();

  OutputImageType::Pointer ddm1 = base(reader->GetOutput(),
				       octaves, scales,
				       threshold, ratio);

  OutputImageType::Pointer ddm2 = rotate(reader->GetOutput(),
					 octaves, scales,
					 threshold, ratio,
					 rotation);

  OutputImageType::Pointer ddm3 = zoom(reader->GetOutput(),
				       octaves, scales,
				       threshold, ratio,
				       zoomFactor);

  OutputImageType::Pointer ddm4 = contrast(reader->GetOutput(),
					   octaves, scales,
					   threshold, ratio,
					   contrastMin, contrastMax);

  subtract(ddm1, ddm2);
  subtract(ddm1, ddm3);
  subtract(ddm1, ddm4);

  return EXIT_SUCCESS;
}
<commit_msg>*ajout combinaison des transformations rotation, zoom et contrast<commit_after>/*=========================================================================

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

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

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

=========================================================================*/
#include <iostream>
#include <fstream>

#include "itkPointSet.h"
#include "itkImageRegionIterator.h"
#include "itkVariableLengthVector.h"
#include "itkResampleImageFilter.h"
#include "itkDanielssonDistanceMapImageFilter.h"
#include "itkSubtractImageFilter.h"
#include "itkMinimumMaximumImageCalculator.h"
#include "itkShrinkImageFilter.h"
#include "itkExpandImageFilter.h"
#include "itkPointSetToImageFilter.h"
#include "itkRescaleIntensityImageFilter.h"

#include "otbImageToSIFTKeyPointSetFilter.h"
#include "otbImage.h"
#include "otbImageFileReader.h"
#include "otbImageFileWriter.h"

typedef itk::VariableLengthVector<float> RealVectorType;
typedef itk::PointSet<RealVectorType,2> PointSetType;
typedef otb::Image<float,2> ImageType;
typedef otb::Image<unsigned char, 2> OutputImageType;

// PointSet iterator types
typedef PointSetType::PointsContainer PointsContainerType;
typedef PointsContainerType::Iterator PointsIteratorType;
typedef PointSetType::PointDataContainer PointDataContainerType;
typedef PointDataContainerType::Iterator PointDataIteratorType;

// Filter
typedef otb::ImageFileReader<ImageType> ReaderType;
typedef otb::ImageFileWriter<OutputImageType> WriterType;
typedef otb::ImageFileWriter<ImageType> WriterInputType;

OutputImageType::Pointer sift(ImageType::Pointer input,
			      const unsigned int octaves,
			      const unsigned int scales,
			      const float threshold,
			      const float ratio,
			      const char* siftFileName)
{
  typedef otb::ImageToSIFTKeyPointSetFilter<ImageType,PointSetType> SiftFilterType;
  typedef itk::PointSetToImageFilter<PointSetType, OutputImageType> PointSetFilterType;

  SiftFilterType::Pointer sift = SiftFilterType::New();
  PointSetFilterType::Pointer pointSetFilter = PointSetFilterType::New();

  sift->SetInput(0,input);
  sift->SetOctavesNumber(octaves);
  sift->SetScalesNumber(scales);
  sift->SetDoGThreshold(threshold);
  sift->SetEdgeThreshold(ratio);

  pointSetFilter->SetInput(sift->GetOutput());
  pointSetFilter->SetOutsideValue(0);
  pointSetFilter->SetInsideValue(255);
  pointSetFilter->SetSize(input->GetLargestPossibleRegion().GetSize());
  pointSetFilter->SetSpacing(input->GetSpacing());
  pointSetFilter->SetOrigin(input->GetOrigin());
  pointSetFilter->Update();

  WriterType::Pointer writer = WriterType::New();
  writer->SetFileName(siftFileName);
  writer->SetInput(pointSetFilter->GetOutput());
  writer->Update();

  return pointSetFilter->GetOutput();
}

OutputImageType::Pointer ddm( OutputImageType::Pointer input,
			      const char* ddmFileName)
{
  typedef itk::DanielssonDistanceMapImageFilter <OutputImageType, OutputImageType> DDMFilterType;
  DDMFilterType::Pointer ddmFilter = DDMFilterType::New();

  ddmFilter->SetInput(input);
  ddmFilter->InputIsBinaryOn();
  ddmFilter->Update();

  WriterType::Pointer writer = WriterType::New();
  writer->SetFileName(ddmFileName);
  writer->SetInput(ddmFilter->GetOutput());
  writer->Update();

  return ddmFilter->GetOutput();
}

ImageType::Pointer rotate( ImageType::Pointer input,
			   const unsigned int rotation)
{
  typedef itk::AffineTransform<double, 2> TransformType;
  typedef itk::ResampleImageFilter<ImageType, ImageType>
    ResampleFilterType;
  ResampleFilterType::Pointer resampler = ResampleFilterType::New();

  TransformType::Pointer transform = TransformType::New();
  TransformType::OutputVectorType translation1;
  TransformType::OutputVectorType translation2;

  const ImageType::SpacingType& spacing = input->GetSpacing();
  const ImageType::PointType& origin  = input->GetOrigin();
  ImageType::SizeType size = input->GetLargestPossibleRegion().GetSize();

  const double imageCenterX = origin[0] + spacing[0] * size[0] / 2.0;
  const double imageCenterY = origin[1] + spacing[1] * size[1] / 2.0;
  const double degreesToRadians = atan(1.0) / 45.0;
  const double angle = rotation * degreesToRadians;

  translation1[0] = -imageCenterX;
  translation1[1] = -imageCenterY;
  translation2[0] = imageCenterX;
  translation2[1] = imageCenterY;

  transform->Translate( translation1 );
  transform->Rotate2D( -angle, false );
  transform->Translate( translation2 );

  resampler->SetOutputOrigin( origin );
  resampler->SetOutputSpacing( spacing );
  resampler->SetSize( size );
  resampler->SetTransform(transform);
  resampler->SetInput(input);
  resampler->Update();
  return resampler->GetOutput();
}

OutputImageType::Pointer invRotate(OutputImageType::Pointer input,
				   const unsigned int rotation)
{
  typedef itk::AffineTransform<double, 2> TransformType;
  typedef itk::ResampleImageFilter<OutputImageType, OutputImageType>
    ResampleFilterType;
  ResampleFilterType::Pointer resampler = ResampleFilterType::New();

  TransformType::Pointer transform = TransformType::New();
  TransformType::OutputVectorType translation1;
  TransformType::OutputVectorType translation2;

  const ImageType::SpacingType& spacing = input->GetSpacing();
  const ImageType::PointType& origin  = input->GetOrigin();
  ImageType::SizeType size = input->GetLargestPossibleRegion().GetSize();

  const double imageCenterX = origin[0] + spacing[0] * size[0] / 2.0;
  const double imageCenterY = origin[1] + spacing[1] * size[1] / 2.0;

  const double degreesToRadians = atan(1.0) / 45.0;
  const double angle = rotation * degreesToRadians;

  translation1[0] = -imageCenterX;
  translation1[1] = -imageCenterY;
  translation2[0] = imageCenterX;
  translation2[1] = imageCenterY;

  transform->Translate( translation1 );
  transform->Rotate2D( angle, false );
  transform->Translate( translation2 );

  resampler->SetOutputOrigin( origin );
  resampler->SetOutputSpacing( spacing );
  resampler->SetSize( size );
  resampler->SetTransform(transform);
  resampler->SetInput(input);
  resampler->Update();
  return resampler->GetOutput();
}

ImageType::Pointer zoom( ImageType::Pointer input,
			 const unsigned int zoomFactor)
{
  typedef itk::ShrinkImageFilter<ImageType, ImageType> ShrinkFilterType;
  ShrinkFilterType::Pointer shrink = ShrinkFilterType::New();

  shrink->SetInput(input);
  shrink->SetShrinkFactors(zoomFactor);
  shrink->Update();

  return shrink->GetOutput();
}

OutputImageType::Pointer invZoom( OutputImageType::Pointer input,
				  const unsigned int zoomFactor)
{
  typedef itk::ExpandImageFilter<OutputImageType, OutputImageType> ExpandFilterType;
  ExpandFilterType::Pointer expand = ExpandFilterType::New();

  expand->SetInput(input);
  expand->SetExpandFactors(zoomFactor);
  expand->Update();

  return expand->GetOutput();
}

ImageType::Pointer contrast(ImageType::Pointer input,
			    const unsigned int contrastMin,
			    const unsigned int contrastMax)
{
  typedef itk::RescaleIntensityImageFilter<ImageType, ImageType> RescaleFilterType;
  RescaleFilterType::Pointer rescaler= RescaleFilterType::New();

  rescaler->SetInput(input);
  rescaler->SetOutputMinimum(static_cast<RescaleFilterType::OutputPixelType>(contrastMin));
  rescaler->SetOutputMaximum(static_cast<RescaleFilterType::OutputPixelType>(contrastMax));
  rescaler->Update();
  return rescaler->GetOutput();
}

OutputImageType::Pointer invContrast( OutputImageType::Pointer input,
				      const unsigned int contrastMin,
				      const unsigned int contrastMax)
{
  return input;
}

void subtract(OutputImageType::Pointer image1,
	      OutputImageType::Pointer image2,
	      const char* subtractFileName)
{
  typedef itk::SubtractImageFilter<OutputImageType, OutputImageType, ImageType> SubtractFilterType;
  typedef itk::MinimumMaximumImageCalculator<ImageType> MaximumCalculatorType;
  typedef itk::RescaleIntensityImageFilter<ImageType, OutputImageType> OutputRescaleFilterType;

  SubtractFilterType::Pointer subtract = SubtractFilterType::New();
  MaximumCalculatorType::Pointer maximumCalculator = MaximumCalculatorType::New();

  subtract->SetInput1(image1);
  subtract->SetInput2(image2);
  subtract->Update();

  OutputRescaleFilterType::Pointer rescaler = OutputRescaleFilterType::New();
  rescaler->SetInput(subtract->GetOutput());
  rescaler->SetOutputMinimum(0);
  rescaler->SetOutputMaximum(255);

  WriterType::Pointer writer = WriterType::New();
  writer->SetFileName(subtractFileName);
  writer->SetInput(rescaler->GetOutput());
  writer->Update();

  maximumCalculator->SetImage(subtract->GetOutput());
  maximumCalculator->Compute();

  std::cout << "Mix(sub)= " << maximumCalculator->GetMinimum() << " ";
  std::cout << "Max(sub)= " << maximumCalculator->GetMaximum() << std::endl;
}

int otbImageToSIFTKeyPointSetFilterDistanceMap(int argc, char * argv[])
{
  // Input Image file name
  const char * infname = argv[1];

  const unsigned int octaves = atoi(argv[2]);
  const unsigned int scales = atoi(argv[3]);
  const float threshold = atof(argv[4]);
  const float ratio = atof(argv[5]);

  // Rotation angle [0,360[
  const unsigned int rotation = atoi(argv[6]);

  // Zoom factor
  const unsigned int zoomFactor = atoi(argv[7]);

  // contrast factor
  const unsigned int contrastMin = atoi(argv[8]);
  const unsigned int contrastMax = atoi(argv[9]);

  ReaderType::Pointer reader = ReaderType::New();
  reader->SetFileName(infname);
  reader->Update();

  ImageType::Pointer _rotated =
    rotate(reader->GetOutput(), rotation);
  ImageType::Pointer _zoomed =
    zoom(reader->GetOutput(), zoomFactor);
  ImageType::Pointer _contrasted =
    contrast(reader->GetOutput(), contrastMin, contrastMax);

  ImageType::Pointer _combined1 = zoom(_rotated, zoomFactor);
  ImageType::Pointer _combined2 = contrast(_combined1, contrastMin, contrastMax);

  OutputImageType::Pointer sift_base =
    sift(reader->GetOutput(), octaves, scales, threshold, ratio, "sift_base.png");

  OutputImageType::Pointer _sift_rotated =
    sift(_rotated, octaves, scales, threshold, ratio, "sift_rotated.png");

  OutputImageType::Pointer _sift_zoomed =
    sift(_zoomed, octaves, scales, threshold, ratio, "sift_zoomed.png");

  OutputImageType::Pointer _sift_contrasted =
    sift(_contrasted, octaves, scales, threshold, ratio, "sift_contrasted.png");

  OutputImageType::Pointer _sift_combined =
    sift(_combined2, octaves, scales, threshold, ratio, "sift_combined.png");

  OutputImageType::Pointer sift_rotated =
    invRotate(_sift_rotated, rotation);

  OutputImageType::Pointer sift_zoomed =
    invZoom(_sift_zoomed, zoomFactor);

  OutputImageType::Pointer sift_contrasted =
    invContrast(_sift_contrasted, contrastMin, contrastMax);

  OutputImageType::Pointer _sift_combined1 =
    invContrast(_sift_combined, contrastMin, contrastMax);
  OutputImageType::Pointer _sift_combined2 =
    invRotate(_sift_combined1, rotation);
  OutputImageType::Pointer sift_combined =
    invZoom(_sift_combined2, zoomFactor);

  OutputImageType::Pointer ddm_base = ddm(sift_base, "ddm_base.png");
  OutputImageType::Pointer ddm_rotated = ddm(sift_rotated, "ddm_rotated.png");
  OutputImageType::Pointer ddm_contrasted = ddm(sift_contrasted, "ddm_contrasted.png");
  OutputImageType::Pointer ddm_zoomed = ddm(sift_zoomed, "ddm_zoomed.png");
  OutputImageType::Pointer ddm_combined = ddm(sift_combined, "ddm_combined.png");

  subtract(ddm_base, ddm_rotated,
	   "subtract_rotated.png");

  subtract(ddm_base, ddm_zoomed,
	   "subtract_zoomed.png");

  subtract(ddm_base, ddm_contrasted,
	   "subtract_contrasted.png");

  subtract(ddm_base, ddm_combined,
	   "subtract_combined.png");

  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>/* contacts.cc			KPilot
**
** Copyright (C) 2008 by Bertjan Broeksema <b.broeksema@kdemail.net>
** Copyright (C) 2008 by Jason "vanRijn" Kasper <vr@movingparts.net>
*/

/*
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU Lesser General Public License as published by
** the Free Software Foundation; either version 2.1 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program in a file called COPYING; if not, write to
** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
** MA 02110-1301, USA.
*/

/*
** Bug reports and questions can be sent to kde-pim@kde.org
*/

#include "contacts.h"

#include <akonadi/control.h>
#include <akonadi/collection.h>
#include <akonadi/itemfetchjob.h>
#include <akonadi/itemfetchscope.h>

#include "options.h"

#include "record.h"
#include "hhrecord.h"

#include "contactshhdataproxy.h"
#include "contactsakonadidataproxy.h"

using namespace Akonadi;

Contacts::Contacts( KPilotLink *o, const QVariantList &a )
 : RecordConduit( o, a, CSL1( "AddressDB" ), CSL1( "Keyring Conduit" ) )
{
}

void Contacts::loadSettings()
{
	FUNCTIONSETUP;
}

bool Contacts::initDataProxies()
{
	FUNCTIONSETUP;

	if( !fDatabase )
	{
		addSyncLogEntry( i18n( "Error: Handheld database is not loaded." ) );
		return false;
	}

	// Lets make sure that Akonadi is started.
	if ( !Control::start() )
	{
		addSyncLogEntry( i18n( "Error: Could not start Akonadi." ) );
		return false;
	}

	fHHDataProxy = new ContactsHHDataProxy( fDatabase );

	// TODO: Make the collection id configurable. For now we just hardcode the
	//       collection id. To find out which collection you can sync, use
	//       akonadiconsole->folder properties->internals.
	// Fetch all items with full payload from the root collection
	ItemFetchJob *job = new ItemFetchJob( Collection( 4 ) );
	job->fetchScope().fetchFullPayload();

	if ( job->exec() ) {
		fPCDataProxy = new ContactsAkonadiDataProxy( /* job->items() */ );
		return true;
	}

	return false;
}

bool Contacts::equal( const Record *pcRec, const HHRecord *hhRec ) const
{
	FUNCTIONSETUP;

	if( !pcRec || !hhRec )
	{
		return false;
	}

	return pcRec->equal( hhRec );
}

Record* Contacts::createPCRecord( const HHRecord *hhRec )
{
	FUNCTIONSETUP;
	//TODO: IMPLEMENT
	return 0L;
}

HHRecord* Contacts::createHHRecord( const Record *pcRec )
{
	FUNCTIONSETUP;
	//TODO: IMPLEMENT
	return 0L;
}

void Contacts::_copy( const Record *from, HHRecord *to )
{
	FUNCTIONSETUP;

	//TODO: IMPLEMENT
}

void Contacts::_copy( const HHRecord *from, Record *to  )
{
	FUNCTIONSETUP;

	//TODO: IMPLEMENT
}
<commit_msg>Use the right conduit name so that we not read the mapping file from another conduit.<commit_after>/* contacts.cc			KPilot
**
** Copyright (C) 2008 by Bertjan Broeksema <b.broeksema@kdemail.net>
** Copyright (C) 2008 by Jason "vanRijn" Kasper <vr@movingparts.net>
*/

/*
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU Lesser General Public License as published by
** the Free Software Foundation; either version 2.1 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program in a file called COPYING; if not, write to
** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
** MA 02110-1301, USA.
*/

/*
** Bug reports and questions can be sent to kde-pim@kde.org
*/

#include "contacts.h"

#include <akonadi/control.h>
#include <akonadi/collection.h>
#include <akonadi/itemfetchjob.h>
#include <akonadi/itemfetchscope.h>

#include "options.h"

#include "record.h"
#include "hhrecord.h"

#include "contactshhdataproxy.h"
#include "contactsakonadidataproxy.h"

using namespace Akonadi;

Contacts::Contacts( KPilotLink *o, const QVariantList &a )
 : RecordConduit( o, a, CSL1( "AddressDB" ), CSL1( "Contacts Conduit" ) )
{
}

void Contacts::loadSettings()
{
	FUNCTIONSETUP;
}

bool Contacts::initDataProxies()
{
	FUNCTIONSETUP;

	if( !fDatabase )
	{
		addSyncLogEntry( i18n( "Error: Handheld database is not loaded." ) );
		return false;
	}

	// Lets make sure that Akonadi is started.
	if ( !Control::start() )
	{
		addSyncLogEntry( i18n( "Error: Could not start Akonadi." ) );
		return false;
	}

	fHHDataProxy = new ContactsHHDataProxy( fDatabase );

	// TODO: Make the collection id configurable. For now we just hardcode the
	//       collection id. To find out which collection you can sync, use
	//       akonadiconsole->folder properties->internals.
	// Fetch all items with full payload from the root collection
	ItemFetchJob *job = new ItemFetchJob( Collection( 4 ) );
	job->fetchScope().fetchFullPayload();

	if ( job->exec() ) {
		fPCDataProxy = new ContactsAkonadiDataProxy( /* job->items() */ );
		return true;
	}

	return false;
}

bool Contacts::equal( const Record *pcRec, const HHRecord *hhRec ) const
{
	FUNCTIONSETUP;

	if( !pcRec || !hhRec )
	{
		return false;
	}

	return pcRec->equal( hhRec );
}

Record* Contacts::createPCRecord( const HHRecord *hhRec )
{
	FUNCTIONSETUP;
	//TODO: IMPLEMENT
	return 0L;
}

HHRecord* Contacts::createHHRecord( const Record *pcRec )
{
	FUNCTIONSETUP;
	//TODO: IMPLEMENT
	return 0L;
}

void Contacts::_copy( const Record *from, HHRecord *to )
{
	FUNCTIONSETUP;

	//TODO: IMPLEMENT
}

void Contacts::_copy( const HHRecord *from, Record *to  )
{
	FUNCTIONSETUP;

	//TODO: IMPLEMENT
}
<|endoftext|>


<commit_before>#include "alara.h"
#include "Matrix.h"

/* this is used to determine how many terms are needed in the expansion */
#define MAXEXPTOL 1e-15

/* This is the maximum number of terms allowed for the expansion method
 * If more are needed, the inversion method is used */
#define MAXNUMEXPTERMS 15

/* This is used to determine if poles are degenerate.  Loops should
 * generate poles which are exactly the same, but poles with small
 * relative differences may act as degeneracies anyway */
#define SMALL_REL_DIFF 1e-8

/* routine for to calculate factorial */
double fact(int i)
{
  int idx,idx2;
  /* create a look-up table for factorials */
  const int maxFactorial = 50;
  static double *factorials = NULL;
  if (factorials == NULL)
    {
      factorials = new double[maxFactorial];
      for (idx=0;idx<maxFactorial;idx++)
	{
	  idx2 = idx;
	  factorials[idx] = 1;
	  while (idx2>1) factorials[idx] *= idx2--;
	}
    }

  if (i < maxFactorial)
    return factorials[i];
  else
    {
      double result=1;

      while (i>1) result *= i--;

      return result;
    }
}

double bateman(int row, int col, double* d, double t, int& finitePositive)
{
  double sum, sumInc, den;
  int term, denTerm;

  finitePositive = TRUE;

  sum = 0;
  sumInc = 0;

  for (term=col;term<row;term++)
    {
      /* set denominator element based on Laplace root: d[term]
       * (traditional analytic inverse Laplace transform) */
      den = 1;

      for (denTerm=col;denTerm<term;denTerm++)
	den *= (d[denTerm]-d[term]);

      for (denTerm++;denTerm<=row;denTerm++)
	den *= (d[denTerm]-d[term]);

      /* set numerator element based on Laplace root: d[term] */
      sumInc = expm1(-d[term]*t)-expm1(-d[row]*t);

      /* add element based on Laplace root: d[term] */
      sum += sumInc/den;
    }

  /* negative results are due to round-off error and
   * imply very small results */
  if (sum < 0 || isnan(sum))
    {
      finitePositive = FALSE;
      return 0;
    }
  else
   return sum;

};

double dGn(int idx, double *pole, int *mult, int numPoles, int termNum)
{
  int pNum, pwr;
  double invPwrSum,result = 0;

  if (termNum==0)   /* End Condition - 0th derivative */
    /* return inverse product of pole-otherPoles */
    {
      result = 1;

      /* all poles before the current pole */
      for (pNum=0; pNum<idx; pNum++)
	result /= pow( pole[pNum] - pole[idx] , mult[pNum] );

      /* all poles after the current pole */
      for (pNum++; pNum<numPoles; pNum++)
	result /= pow( pole[pNum] - pole[idx] , mult[pNum] );
    }
  else
    for (pwr=termNum;pwr>0;pwr--)
      {
	invPwrSum = 0;

	/* all poles before the current pole */
	for (pNum=0; pNum<idx; pNum++)
	  invPwrSum += mult[pNum] * pow( pole[pNum]-pole[idx] , -pwr );

	/* all poles after the current pole */
	for (pNum++; pNum<numPoles; pNum++)
	  invPwrSum += mult[pNum] * pow( pole[pNum]-pole[idx] , -pwr );

	/* recursively add terms */
	result += -2*(pwr%2 -.5) * (fact(termNum-1)/fact(termNum-pwr))
	  * invPwrSum * dGn(idx,pole,mult,numPoles,termNum-pwr);
      }

  return result;

}

double laplaceInverse(int row, int col, double *d, double t,
		      int& finitePositive)
{
  int idx, checkIdx, multCnt;
  int numPoles = 0;
  int *mult = new int[row-col+1];
  double *pole = new double[row-col+1];
  double poleResult, result;

  finitePositive = TRUE;

  /* index all the poles with the multiplicities */
  for (idx = col;idx<=row;idx++)
    {
      for (checkIdx=0;checkIdx<numPoles;checkIdx++)
	if ( fabs((d[idx]-pole[checkIdx]))<SMALL_REL_DIFF*d[idx] )
	  {
	    mult[checkIdx]++;
	    break;
	  }
      if (checkIdx == numPoles)
	{
	  pole[checkIdx] = d[idx];
	  mult[checkIdx] = 1;
	  numPoles++;
	}
    }

  /* perform recursive analytic Laplace inversion */
  for (idx=0;idx<numPoles;idx++)
    {
      poleResult = 0;

      for (multCnt=mult[idx];multCnt>0;multCnt--)
	poleResult += dGn(idx, pole, mult, numPoles, mult[idx] - multCnt)
	  * pow(t,multCnt-1)
	  / fact(multCnt-1)
	  / fact(mult[idx]-multCnt) ;

      result += poleResult * exp(-pole[idx]*t);
    }

  delete mult;
  delete pole;

  if (result < 0 || isnan(result))
    {
      finitePositive = FALSE;
      return 0;
    }
  else
    return result;

}

double laplaceExpansion(int row, int col, double *d, double t, int &converged)
{

  int idx, termNum;
  int sz = row-col;
  double result, correction;

  /* initialize matrix with destruction rates */
  Matrix poleMat(d,sz+1);
  Matrix powPoleMat(sz+1);

  /* innocent until proven guilty */
  converged = TRUE;

  /* zeroth term is simply the correct power of t/n!  */
  result = pow(t,sz)/fact(sz);

  /* for each successive term */
  for (termNum=1;termNum<MAXNUMEXPTERMS;termNum++)
    {
      /* multiply the power matrix by the non-power matrix */
      powPoleMat *= poleMat;

      /* power of t/n! times coefficient, with alternating sign!! */
      correction = powPoleMat.rowSum(sz) * ( 1-2*(termNum%2) )
	* pow(t,termNum+sz)/fact(termNum+sz);

      if (fabs(correction/result) > MAXEXPTOL)
	/* use this term if significant */
	result += correction;
      else
	/* otherwise break */
	break;
    }

  /* for monstrous decay rates (e.g. Be-8) the correction or
   * result may become infinite */
  if (termNum == MAXNUMEXPTERMS || isnan(result))
    converged = FALSE;

  return result;
}

double fillTElement(int row, int col, double *P, double *d, double t,
		    int* loopRank, int rank)
{

  int idx,loopIdx,parLoopIdx;
  int defSuccess, altSuccess;
  double result;

  /* process loop information in reverse problem */
  if (rank != row)
    {
      loopIdx = (row+rank) - loopRank[rank];
      parLoopIdx = (row+rank) - loopRank[rank+1];
    }
  else
    {
      loopIdx = loopRank[row];
      parLoopIdx = loopRank[row-1];
    }

  /* do this product up front to eliminate costly
   * computation which may end in 0 anyway */
  double productionProduct = 1;
  for (idx=col;idx<row;idx++)
    productionProduct *= P[idx+1];

  if (productionProduct == 0)
    return productionProduct;

  /* implement default method */

  /* This seemingly complicated condition saves using the loop
   * solution during a reference calculation when only the last
   * isotope introduces the loop.  In this case, there is no real
   * degeneracy, since the destruction rate of the last isotope is
   * zero'ed for a reference calculation.  The condition can be
   * understood as follows:
   *  - when checking for loop solution, if we are calculating the
   *    production from an isotope inside the loop, generally use
   *    the loop sol'n, but only iff
   *  - only the last isotope can ever have a destruction rate of
   *    zero
   *      - if d[row] > 0, use loop sol'n
   *  - even if last isotope does have a 0 destruction rate, if
   *    the previous isotope was already in a loop, we need to use
   *    the loop sol'n
   *      - if loopRank[row-1] > -1, check for loop sol'n \
   *        (This check must be done after the first one because
   *        it ensures that we are not checking loopRank[-1])*/
  if (col<=loopIdx && (d[row] > 0 || parLoopIdx >-1))
    {
      result = laplaceExpansion(row,col,d,t,defSuccess);
      if (!defSuccess)
	/* implement other method adaptively */
	result = laplaceInverse(row,col,d,t,altSuccess);
    }
  else
    result = bateman(row,col,d,t,altSuccess);

  /* used during debugging
  if (isinf(result) || isnan(result) )
    error(2001,"No mathematical method was successful!");  */

  return result*productionProduct;
}

<commit_msg>Overhaul of loop handling!<commit_after>#include "alara.h"
#include "Matrix.h"

/* this is used to determine how many terms are needed in the expansion */
#define MAXEXPTOL 1e-15

/* This is the maximum number of terms allowed for the expansion method
 * If more are needed, the inversion method is used */
#define MAXNUMEXPTERMS 15

/* This is used to determine if poles are degenerate.  Loops should
 * generate poles which are exactly the same, but poles with small
 * relative differences may act as degeneracies anyway */
#define SMALL_REL_DIFF 1e-8

/* routine for to calculate factorial */
double fact(int i)
{
  int idx,idx2;
  /* create a look-up table for factorials */
  const int maxFactorial = 50;
  static double *factorials = NULL;
  if (factorials == NULL)
    {
      factorials = new double[maxFactorial];
      for (idx=0;idx<maxFactorial;idx++)
	{
	  idx2 = idx;
	  factorials[idx] = 1;
	  while (idx2>1) factorials[idx] *= idx2--;
	}
    }

  if (i < maxFactorial)
    return factorials[i];
  else
    {
      double result=1;

      while (i>1) result *= i--;

      return result;
    }
}

double bateman(int row, int col, double* d, double t, int& finitePositive)
{
  double sum, sumInc, den;
  int term, denTerm;

  finitePositive = TRUE;

  sum = 0;
  sumInc = 0;

  for (term=col;term<row;term++)
    {
      /* set denominator element based on Laplace root: d[term]
       * (traditional analytic inverse Laplace transform) */
      den = 1;

      for (denTerm=col;denTerm<term;denTerm++)
	den *= (d[denTerm]-d[term]);

      for (denTerm++;denTerm<=row;denTerm++)
	den *= (d[denTerm]-d[term]);

      /* set numerator element based on Laplace root: d[term] */
      sumInc = expm1(-d[term]*t)-expm1(-d[row]*t);

      /* add element based on Laplace root: d[term] */
      sum += sumInc/den;
    }

  /* negative results are due to round-off error and
   * imply very small results */
  if (sum < 0 || isnan(sum))
    {
      finitePositive = FALSE;
      return 0;
    }
  else
   return sum;

};

double dGn(int idx, double *pole, int *mult, int numPoles, int termNum)
{
  int pNum, pwr;
  double invPwrSum,result = 0;

  if (termNum==0)   /* End Condition - 0th derivative */
    /* return inverse product of pole-otherPoles */
    {
      result = 1;

      /* all poles before the current pole */
      for (pNum=0; pNum<idx; pNum++)
	result /= pow( pole[pNum] - pole[idx] , mult[pNum] );

      /* all poles after the current pole */
      for (pNum++; pNum<numPoles; pNum++)
	result /= pow( pole[pNum] - pole[idx] , mult[pNum] );
    }
  else
    for (pwr=termNum;pwr>0;pwr--)
      {
	invPwrSum = 0;

	/* all poles before the current pole */
	for (pNum=0; pNum<idx; pNum++)
	  invPwrSum += mult[pNum] * pow( pole[pNum]-pole[idx] , -pwr );

	/* all poles after the current pole */
	for (pNum++; pNum<numPoles; pNum++)
	  invPwrSum += mult[pNum] * pow( pole[pNum]-pole[idx] , -pwr );

	/* recursively add terms */
	result += -2*(pwr%2 -.5) * (fact(termNum-1)/fact(termNum-pwr))
	  * invPwrSum * dGn(idx,pole,mult,numPoles,termNum-pwr);
      }

  return result;

}

double laplaceInverse(int row, int col, double *d, double t,
		      int& finitePositive)
{
  int idx, checkIdx, multCnt;
  int numPoles = 0;
  int *mult = new int[row-col+1];
  double *pole = new double[row-col+1];
  double poleResult, result;

  finitePositive = TRUE;

  /* index all the poles with the multiplicities */
  for (idx = col;idx<=row;idx++)
    {
      for (checkIdx=0;checkIdx<numPoles;checkIdx++)
	if ( fabs((d[idx]-pole[checkIdx]))<SMALL_REL_DIFF*d[idx] )
	  {
	    mult[checkIdx]++;
	    break;
	  }
      if (checkIdx == numPoles)
	{
	  pole[checkIdx] = d[idx];
	  mult[checkIdx] = 1;
	  numPoles++;
	}
    }

  /* perform recursive analytic Laplace inversion */
  for (idx=0;idx<numPoles;idx++)
    {
      poleResult = 0;

      for (multCnt=mult[idx];multCnt>0;multCnt--)
	poleResult += dGn(idx, pole, mult, numPoles, mult[idx] - multCnt)
	  * pow(t,multCnt-1)
	  / fact(multCnt-1)
	  / fact(mult[idx]-multCnt) ;

      result += poleResult * exp(-pole[idx]*t);
    }

  delete mult;
  delete pole;

  if (result < 0 || isnan(result))
    {
      finitePositive = FALSE;
      return 0;
    }
  else
    return result;

}

double laplaceExpansion(int row, int col, double *d, double t, int &converged)
{

  int idx, termNum;
  int sz = row-col;
  double result, correction;

  /* initialize matrix with destruction rates */
  Matrix poleMat(d,sz+1);
  Matrix powPoleMat(sz+1);

  /* innocent until proven guilty */
  converged = TRUE;

  /* zeroth term is simply the correct power of t/n!  */
  result = pow(t,sz)/fact(sz);

  /* for each successive term */
  for (termNum=1;termNum<MAXNUMEXPTERMS;termNum++)
    {
      /* multiply the power matrix by the non-power matrix */
      powPoleMat *= poleMat;

      /* power of t/n! times coefficient, with alternating sign!! */
      correction = powPoleMat.rowSum(sz) * ( 1-2*(termNum%2) )
	* pow(t,termNum+sz)/fact(termNum+sz);

      if (fabs(correction/result) > MAXEXPTOL)
	/* use this term if significant */
	result += correction;
      else
	/* otherwise break */
	break;
    }

  /* for monstrous decay rates (e.g. Be-8) the correction or
   * result may become infinite */
  if (termNum == MAXNUMEXPTERMS || isnan(result))
    converged = FALSE;

  return result;
}

double fillTElement(int row, int col, double *P, double *d, double t,
		    int* loopRank, int rank)
{

  int idx,loopIdx,parLoopIdx;
  int defSuccess, altSuccess;
  double result;

  /* process loop information in reverse problem */
  if (rank != row)
    {
      loopIdx = loopRank[rank];
      parLoopIdx = loopRank[rank+1];
    }
  else
    {
      loopIdx = loopRank[row];
      parLoopIdx = loopRank[row-1];
    }

  /* if there is no loop, at this level, row - loopIdx = -1 */
  if (loopIdx == -1)
    loopIdx = row+1;

  /* do this product up front to eliminate costly
   * computation which may end in 0 anyway */
  double productionProduct = 1;
  for (idx=col;idx<row;idx++)
    productionProduct *= P[idx+1];

  if (productionProduct == 0)
    return productionProduct;

  /* implement default method */

  /* This seemingly complicated condition saves using the loop
   * solution during a reference calculation when only the last
   * isotope introduces the loop.  In this case, there is no real
   * degeneracy, since the destruction rate of the last isotope is
   * zero'ed for a reference calculation.  The condition can be
   * understood as follows:
   *  - when checking for loop solution, if we are calculating the
   *    production from an isotope inside the loop, generally use
   *    the loop sol'n, but only iff
   *  - only the last isotope can ever have a destruction rate of
   *    zero
   *      - if d[row] > 0, use loop sol'n
   *  - even if last isotope does have a 0 destruction rate, if
   *    the previous isotope was already in a loop, we need to use
   *    the loop sol'n
   *      - if loopRank[row-1] > -1, check for loop sol'n \
   *        (This check must be done after the first one because
   *        it ensures that we are not checking loopRank[-1])*/
  if (col<=row-loopIdx && (d[row] > 0 || parLoopIdx >-1))
    {
      result = laplaceExpansion(row,col,d,t,defSuccess);
      if (!defSuccess)
	/* implement other method adaptively */
	result = laplaceInverse(row,col,d,t,altSuccess);
    }
  else
    result = bateman(row,col,d,t,altSuccess);

  /* used during debugging
  if (isinf(result) || isnan(result) )
    error(2001,"No mathematical method was successful!");  */

  return result*productionProduct;
}

<|endoftext|>


<commit_before>// cpu/tube/heap_fragment.cpp                                         -*-C++-*-
// ----------------------------------------------------------------------------
//  Copyright (C) 2014 Thaddaeus Frogley
//
//  Permission is hereby granted, free of charge, to any person
//  obtaining a copy of this software and associated documentation
//  files (the "Software"), to deal in the Software without restriction,
//  including without limitation the rights to use, copy, modify,
//  merge, publish, distribute, sublicense, and/or sell copies of
//  the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be
//  included in all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
//  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
//  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
//  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
//  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
//  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
//  OTHER DEALINGS IN THE SOFTWARE.
// ----------------------------------------------------------------------------

#include "cpu/tube/heap_fragment.hpp"
#include <cstdlib>

// ----------------------------------------------------------------------------
//
heap_fragmenter::heap_fragmenter( int count, int size )
{
	// create 'count' allocations of 1..size bytes
	allocated.reserve(count*2);
	for (int i=0;i!=count*2;++i)
		allocated.push_back( new char[ 1 + rand()%(size-1) ] );

	// shuffle them up
	std::random_shuffle(allocated.begin(), allocated.end());

	// remove half
	for (int i=0;i!=count;++i)
	{
		delete[] allocated.back();
		allocated.pop_back();
	}
}

heap_fragmenter::~heap_fragmenter()
{
	while (allocated.empty()==false)
	{
		delete[] allocated.back();
		allocated.pop_back();
	}
}

<commit_msg>added a missing header<commit_after>// cpu/tube/heap_fragment.cpp                                         -*-C++-*-
// ----------------------------------------------------------------------------
//  Copyright (C) 2014 Thaddaeus Frogley
//
//  Permission is hereby granted, free of charge, to any person
//  obtaining a copy of this software and associated documentation
//  files (the "Software"), to deal in the Software without restriction,
//  including without limitation the rights to use, copy, modify,
//  merge, publish, distribute, sublicense, and/or sell copies of
//  the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be
//  included in all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
//  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
//  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
//  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
//  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
//  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
//  OTHER DEALINGS IN THE SOFTWARE.
// ----------------------------------------------------------------------------

#include "cpu/tube/heap_fragment.hpp"
#include <algorithm>
#include <cstdlib>

// ----------------------------------------------------------------------------
//
heap_fragmenter::heap_fragmenter( int count, int size )
{
	// create 'count' allocations of 1..size bytes
	allocated.reserve(count*2);
	for (int i=0;i!=count*2;++i)
		allocated.push_back( new char[ 1 + rand()%(size-1) ] );

	// shuffle them up
	std::random_shuffle(allocated.begin(), allocated.end());

	// remove half
	for (int i=0;i!=count;++i)
	{
		delete[] allocated.back();
		allocated.pop_back();
	}
}

heap_fragmenter::~heap_fragmenter()
{
	while (allocated.empty()==false)
	{
		delete[] allocated.back();
		allocated.pop_back();
	}
}

<|endoftext|>


<commit_before>/*  -*-c++-*-
 *  Copyright (C) 2009 Cedric Pinson <cedric.pinson@plopbyte.net>
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * OpenSceneGraph Public License for more details.
 */

#include <osgAnimation/VertexInfluence>
#include <osgAnimation/RigTransformSoftware>
#include <osgAnimation/BoneMapVisitor>
#include <osgAnimation/RigGeometry>

#include <algorithm>
using namespace osgAnimation;

RigTransformSoftware::RigTransformSoftware()
{
    _needInit = true;
}

RigTransformSoftware::RigTransformSoftware(const RigTransformSoftware& rts,const osg::CopyOp& copyop):
    RigTransform(rts, copyop),
    _needInit(rts._needInit),
    _invalidInfluence(rts._invalidInfluence)
{

}

typedef std::vector<RigTransformSoftware::BonePtrWeight> BoneWeightList;
// sort by name and weight
struct SortByNameAndWeight : public std::less<RigTransformSoftware::BonePtrWeight>
{
    bool operator()(const RigTransformSoftware::BonePtrWeight& b0,
                    const RigTransformSoftware::BonePtrWeight& b1) const
    {
        if (b0.getBoneName() < b1.getBoneName())
            return true;
        else if (b0.getBoneName() > b1.getBoneName())
            return false;
        if (b0.getWeight() < b1.getWeight())
            return true;
        return false;
    }
};

struct SortByBoneWeightList : public std::less<BoneWeightList>
{
    bool operator()(const BoneWeightList& b0,
                    const BoneWeightList& b1) const
    {
        if (b0.size() < b1.size())
            return true;
        else if (b0.size() > b1.size())
            return false;

        int size = b0.size();
        for (int i = 0; i < size; i++)
        {
            bool result = SortByNameAndWeight()(b0[i], b1[i]);
            if (result)
                return true;
            else if (SortByNameAndWeight()(b1[i], b0[i]))
                return false;
        }
        return false;
    }
};

bool RigTransformSoftware::init(RigGeometry& geom)
{
    if (!geom.getSkeleton())
        return false;

    BoneMapVisitor mapVisitor;
    geom.getSkeleton()->accept(mapVisitor);
    BoneMap bm = mapVisitor.getBoneMap();
    initVertexSetFromBones(bm, geom.getVertexInfluenceSet().getUniqVertexGroupList());

    if (geom.getSourceGeometry())
        geom.copyFrom(*geom.getSourceGeometry());

    osg::Vec3Array* normalSrc = dynamic_cast<osg::Vec3Array*>(geom.getSourceGeometry()->getNormalArray());
    osg::Vec3Array* positionSrc = dynamic_cast<osg::Vec3Array*>(geom.getSourceGeometry()->getVertexArray());

    if(!(positionSrc) || positionSrc->empty() )
        return false;
    if(normalSrc&& normalSrc->size()!=positionSrc->size())
        return false;

    geom.setVertexArray(new osg::Vec3Array);
    osg::Vec3Array* positionDst =new osg::Vec3Array;
    geom.setVertexArray(positionDst);
    *positionDst=*positionSrc;
    positionDst->setDataVariance(osg::Object::DYNAMIC);

    if(normalSrc){
        osg::Vec3Array* normalDst =new osg::Vec3Array;
        *normalDst=*normalSrc;
        geom.setNormalArray(normalDst, osg::Array::BIND_PER_VERTEX);
        normalDst->setDataVariance(osg::Object::DYNAMIC);
    }

    _needInit = false;
    return true;
}

void RigTransformSoftware::buildMinimumUpdateSet(const BoneMap&boneMap,const RigGeometry&rig ){

    ///1 Create Index2Vec<BoneWeight>
    typedef std::vector<BonePtrWeight> BoneWeightList;
    typedef std::vector<BoneWeightList> VertIDToBoneWeightList;

    VertIDToBoneWeightList _vertex2Bones;
    _vertex2Bones.clear();
    _vertex2Bones.resize(rig.getSourceGeometry()->getVertexArray()->getNumElements());

    const VertexInfluenceMap *_vertexInfluenceMap=rig.getInfluenceMap();
    for (osgAnimation::VertexInfluenceMap::const_iterator it = _vertexInfluenceMap->begin();
            it != _vertexInfluenceMap->end();
            ++it)
    {
        const BoneInfluenceList& inflist = it->second;
        for(BoneInfluenceList::const_iterator infit=inflist.begin(); infit!=inflist.end(); ++infit)
        {
            const IndexWeight &iw = *infit;
            const unsigned int &index = iw.getIndex();
            float weight = iw.getWeight();
            if (inflist.getBoneName().empty()) {
                OSG_WARN << "VertexInfluenceSet::buildVertex2BoneList warning vertex " << index << " is not assigned to a bone" << std::endl;
            }
            BoneMap::const_iterator it = boneMap.find(inflist.getBoneName());
            if (it == boneMap.end() )
            {
                if (_invalidInfluence.find(inflist.getBoneName()) != _invalidInfluence.end()) {
                    _invalidInfluence[inflist.getBoneName()] = true;
                    OSG_WARN << "RigTransformSoftware Bone " << inflist.getBoneName() << " not found, skip the influence group " << std::endl;
                }
                continue;
            }
            Bone* bone = it->second.get();
            _vertex2Bones[index].push_back(BonePtrWeight(inflist.getBoneName(), weight,bone));;
        }
    }

    // normalize _vertex2Bones weight per vertex
    unsigned vertexID=0;
    for (VertIDToBoneWeightList::iterator it = _vertex2Bones.begin(); it != _vertex2Bones.end(); ++it, ++vertexID)
    {
        BoneWeightList& bones = *it;
        float sum = 0;
        for(BoneWeightList::iterator bwit=bones.begin();bwit!=bones.end();++bwit)
            sum += bwit->getWeight();
        if (sum < 1e-4)
        {
            OSG_WARN << "VertexInfluenceSet::buildVertex2BoneList warning the vertex " << vertexID << " seems to have 0 weight, skip normalize for this vertex" << std::endl;
        }
        else
        {
            float mult = 1.0/sum;
            for(BoneWeightList::iterator bwit=bones.begin();bwit!=bones.end();++bwit)
                bwit->setWeight(bwit->getWeight() * mult);
        }
    }

    ///2 Create inverse mapping Vec<BoneWeight>2Vec<Index> from previous built Index2Vec<BoneWeight>
    ///in order to minimize weighted matrices computation on update
    typedef std::map<BoneWeightList, VertexGroup, SortByBoneWeightList> UnifyBoneGroup;
    UnifyBoneGroup unifyBuffer;
    vertexID=0;
    for (VertIDToBoneWeightList::iterator it = _vertex2Bones.begin(); it != _vertex2Bones.end(); ++it,++vertexID)
    {
        BoneWeightList& bones = *it;
        // sort the vector to have a consistent key
        std::sort(bones.begin(), bones.end(), SortByNameAndWeight());
        // we use the vector<BoneWeight> as key to differentiate group
        UnifyBoneGroup::iterator result = unifyBuffer.find(bones);
        if (result == unifyBuffer.end())
            unifyBuffer[bones].getBoneWeights()=bones;
        unifyBuffer[bones].getVertexes().push_back(vertexID);
    }
    if(_vertex2Bones.size()==unifyBuffer.size()) {
        OSG_WARN << "RigTransformSoftware::build mapping is useless no duplicate VertexGroup : too much " <<_vertex2Bones.size()<<"=="<<unifyBuffer.size()<< std::endl;

    }
    _uniqInfluenceSet2VertIDList.reserve(unifyBuffer.size());

    for (UnifyBoneGroup::iterator it = unifyBuffer.begin(); it != unifyBuffer.end(); ++it)
        _uniqInfluenceSet2VertIDList.push_back(it->second);

    OSG_DEBUG << "uniq groups " << _uniqInfluenceSet2VertIDList.size() << " for " << rig.getName() << std::endl;
}

bool RigTransformSoftware::prepareData(RigGeometry&rig) {
    if(!rig.getSkeleton() && !rig.getParents().empty())
    {
        RigGeometry::FindNearestParentSkeleton finder;
        if(rig.getParents().size() > 1)
            osg::notify(osg::WARN) << "A RigGeometry should not have multi parent ( " << rig.getName() << " )" << std::endl;
        rig.getParents()[0]->accept(finder);

        if(!finder._root.valid())
        {
            osg::notify(osg::WARN) << "A RigGeometry did not find a parent skeleton for RigGeometry ( " << rig.getName() << " )" << std::endl;
            return false;
        }
        rig.setSkeleton(finder._root.get());
    }
    BoneMapVisitor mapVisitor;
    rig.getSkeleton()->accept(mapVisitor);
    BoneMap boneMap = mapVisitor.getBoneMap();

    buildMinimumUpdateSet(boneMap,rig);

    if (rig.getSourceGeometry())
        rig.copyFrom(*rig.getSourceGeometry());

    osg::Vec3Array* normalSrc = dynamic_cast<osg::Vec3Array*>(rig.getSourceGeometry()->getNormalArray());
    osg::Vec3Array* positionSrc = dynamic_cast<osg::Vec3Array*>(rig.getSourceGeometry()->getVertexArray());

    if(!(positionSrc) || positionSrc->empty() )
        return false;
    if(normalSrc&& normalSrc->size()!=positionSrc->size())
        return false;

    rig.setVertexArray(new osg::Vec3Array);
    osg::Vec3Array* positionDst =new osg::Vec3Array;
    rig.setVertexArray(positionDst);
    *positionDst=*positionSrc;
    positionDst->setDataVariance(osg::Object::DYNAMIC);

    if(normalSrc) {
        osg::Vec3Array* normalDst =new osg::Vec3Array;
        *normalDst=*normalSrc;
        rig.setNormalArray(normalDst, osg::Array::BIND_PER_VERTEX);
        normalDst->setDataVariance(osg::Object::DYNAMIC);
    }

    _needInit = false;
    return true;
}
void RigTransformSoftware::operator()(RigGeometry& geom)
{
    if (_needInit)
        if (!init(geom))
            return;

    if (!geom.getSourceGeometry()) {
        OSG_WARN << this << " RigTransformSoftware no source geometry found on RigGeometry" << std::endl;
        return;
    }
    osg::Geometry& source = *geom.getSourceGeometry();
    osg::Geometry& destination = geom;

    osg::Vec3Array* positionSrc = static_cast<osg::Vec3Array*>(source.getVertexArray());
    osg::Vec3Array* positionDst = static_cast<osg::Vec3Array*>(destination.getVertexArray());
    osg::Vec3Array* normalSrc = dynamic_cast<osg::Vec3Array*>(source.getNormalArray());
    osg::Vec3Array* normalDst = static_cast<osg::Vec3Array*>(destination.getNormalArray());

    compute<osg::Vec3>(geom.getMatrixFromSkeletonToGeometry(),
                       geom.getInvMatrixFromSkeletonToGeometry(),
                       &positionSrc->front(),
                       &positionDst->front());
    positionDst->dirty();

    if (normalSrc )
    {
            computeNormal<osg::Vec3>(geom.getMatrixFromSkeletonToGeometry(),
                               geom.getInvMatrixFromSkeletonToGeometry(),
                               &normalSrc->front(),
                               &normalDst->front());
            normalDst->dirty();
    }

}

///convert BoneWeight to BonePtrWeight using bonemap
void RigTransformSoftware::initVertexSetFromBones(const BoneMap& map, const VertexInfluenceSet::UniqVertexGroupList& vertexgroups)
{
    _uniqInfluenceSet2VertIDList.clear();

    int size = vertexgroups.size();
    _uniqInfluenceSet2VertIDList.resize(size);
    //for (VertexInfluenceSet::UniqVertexGroupList::const_iterator vgit=vertexgroups.begin();         vgit!=vertexgroups.end();vgit++)
    for(int i = 0; i < size; i++)
    {
        const VertexInfluenceSet::VertexGroup& vg = vertexgroups[i];
        int nbBones = vg.getBones().size();
        BonePtrWeightList& boneList = _uniqInfluenceSet2VertIDList[i].getBoneWeights();

        double sumOfWeight = 0;
        for (int b = 0; b < nbBones; b++)
        {
            const std::string& bname = vg.getBones()[b].getBoneName();
            float weight = vg.getBones()[b].getWeight();
            BoneMap::const_iterator it = map.find(bname);
            if (it == map.end() )
            {
                if (_invalidInfluence.find(bname) != _invalidInfluence.end()) {
                    _invalidInfluence[bname] = true;
                    OSG_WARN << "RigTransformSoftware Bone " << bname << " not found, skip the influence group " <<bname  << std::endl;
                }
                continue;
            }
            Bone* bone = it->second.get();
            boneList.push_back(BonePtrWeight(bone->getName(), weight, bone));
            sumOfWeight += weight;
        }
        // if a bone referenced by a vertexinfluence is missed it can make the sum less than 1.0
        // so we check it and renormalize the all weight bone
        const double threshold = 1e-4;
        if (!vg.getBones().empty() &&
            (sumOfWeight < 1.0 - threshold ||  sumOfWeight > 1.0 + threshold))
        {
            for (int b = 0; b < (int)boneList.size(); b++)
                boneList[b].setWeight(boneList[b].getWeight() / sumOfWeight);
        }
        _uniqInfluenceSet2VertIDList[i].getVertexes() = vg.getVertexes();
    }
}
<commit_msg>minor changes+fix<commit_after>/*  -*-c++-*-
 *  Copyright (C) 2009 Cedric Pinson <cedric.pinson@plopbyte.net>
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * OpenSceneGraph Public License for more details.
 */

#include <osgAnimation/VertexInfluence>
#include <osgAnimation/RigTransformSoftware>
#include <osgAnimation/BoneMapVisitor>
#include <osgAnimation/RigGeometry>

#include <algorithm>
using namespace osgAnimation;

RigTransformSoftware::RigTransformSoftware()
{
    _needInit = true;
}

RigTransformSoftware::RigTransformSoftware(const RigTransformSoftware& rts,const osg::CopyOp& copyop):
    RigTransform(rts, copyop),
    _needInit(rts._needInit),
    _invalidInfluence(rts._invalidInfluence)
{

}

typedef std::vector<RigTransformSoftware::BonePtrWeight> BoneWeightList;
// sort by name and weight
struct SortByNameAndWeight : public std::less<RigTransformSoftware::BonePtrWeight>
{
    bool operator()(const RigTransformSoftware::BonePtrWeight& b0,
                    const RigTransformSoftware::BonePtrWeight& b1) const
    {
        if (b0.getBoneName() < b1.getBoneName())
            return true;
        else if (b0.getBoneName() > b1.getBoneName())
            return false;
        if (b0.getWeight() < b1.getWeight())
            return true;
        return false;
    }
};

struct SortByBoneWeightList : public std::less<BoneWeightList>
{
    bool operator()(const BoneWeightList& b0,
                    const BoneWeightList& b1) const
    {
        if (b0.size() < b1.size())
            return true;
        else if (b0.size() > b1.size())
            return false;

        int size = b0.size();
        for (int i = 0; i < size; i++)
        {
            bool result = SortByNameAndWeight()(b0[i], b1[i]);
            if (result)
                return true;
            else if (SortByNameAndWeight()(b1[i], b0[i]))
                return false;
        }
        return false;
    }
};

bool RigTransformSoftware::init(RigGeometry& geom)
{
    if (!geom.getSkeleton())
        return false;

    BoneMapVisitor mapVisitor;
    geom.getSkeleton()->accept(mapVisitor);
    BoneMap bm = mapVisitor.getBoneMap();
    initVertexSetFromBones(bm, geom.getVertexInfluenceSet().getUniqVertexGroupList());

    if (geom.getSourceGeometry())
        geom.copyFrom(*geom.getSourceGeometry());

    osg::Vec3Array* normalSrc = dynamic_cast<osg::Vec3Array*>(geom.getSourceGeometry()->getNormalArray());
    osg::Vec3Array* positionSrc = dynamic_cast<osg::Vec3Array*>(geom.getSourceGeometry()->getVertexArray());

    if(!(positionSrc) || positionSrc->empty() )
        return false;
    if(normalSrc&& normalSrc->size()!=positionSrc->size())
        return false;

    geom.setVertexArray(new osg::Vec3Array);
    osg::Vec3Array* positionDst =new osg::Vec3Array;
    geom.setVertexArray(positionDst);
    *positionDst=*positionSrc;
    positionDst->setDataVariance(osg::Object::DYNAMIC);

    if(normalSrc){
        osg::Vec3Array* normalDst =new osg::Vec3Array;
        *normalDst=*normalSrc;
        geom.setNormalArray(normalDst, osg::Array::BIND_PER_VERTEX);
        normalDst->setDataVariance(osg::Object::DYNAMIC);
    }

    _needInit = false;
    return true;
}

void RigTransformSoftware::buildMinimumUpdateSet(const BoneMap&boneMap,const RigGeometry&rig ){

    ///1 Create Index2Vec<BoneWeight>
    std::vector<BoneWeightList> _vertex2Bones;
    _vertex2Bones.resize(rig.getSourceGeometry()->getVertexArray()->getNumElements());

    typedef std::pair<float,unsigned int> FloatInt;
    std::vector< FloatInt > sums;///stat totalweight nbref
    sums.resize(rig.getSourceGeometry()->getVertexArray()->getNumElements()
    );
    const VertexInfluenceMap *_vertexInfluenceMap=rig.getInfluenceMap();
    for (osgAnimation::VertexInfluenceMap::const_iterator it = _vertexInfluenceMap->begin();
            it != _vertexInfluenceMap->end();
            ++it)
    {
        const BoneInfluenceList& inflist = it->second;
        if (inflist.getBoneName().empty()) {
            OSG_WARN << "RigTransformSoftware::VertexInfluenceMap contains unamed bone BoneInfluenceList" << std::endl;
        }
        BoneMap::const_iterator bmit = boneMap.find(inflist.getBoneName());
        if (bmit == boneMap.end() )
        {
            if (_invalidInfluence.find(inflist.getBoneName()) != _invalidInfluence.end()) {
                _invalidInfluence[inflist.getBoneName()] = true;
                OSG_WARN << "RigTransformSoftware Bone " << inflist.getBoneName() << " not found, skip the influence group " << std::endl;
            }
            continue;
        }
        Bone* bone = bmit->second.get();
        for(BoneInfluenceList::const_iterator infit=inflist.begin(); infit!=inflist.end(); ++infit)
        {
            const IndexWeight &iw = *infit;
            const unsigned int &index = iw.getIndex();
            float weight = iw.getWeight();

            _vertex2Bones[index].push_back(BonePtrWeight(inflist.getBoneName(), weight,bone));;
        }
    }

    // normalize _vertex2Bones weight per vertex
    unsigned vertexID=0;
    for (std::vector<BoneWeightList>::iterator it = _vertex2Bones.begin(); it != _vertex2Bones.end(); ++it, ++vertexID)
    {
        BoneWeightList& bones = *it;
        float sum = 0;
        for(BoneWeightList::iterator bwit=bones.begin();bwit!=bones.end();++bwit)
            sum += bwit->getWeight();
        if (sum < 1e-4)
        {
            OSG_WARN << "VertexInfluenceSet::buildVertex2BoneList warning the vertex " << vertexID << " seems to have 0 weight, skip normalize for this vertex" << std::endl;
        }
        else
        {
            float mult = 1.0/sum;
            for(BoneWeightList::iterator bwit=bones.begin();bwit!=bones.end();++bwit)
                bwit->setWeight(bwit->getWeight() * mult);
        }
    }

    ///2 Create inverse mapping Vec<BoneWeight>2Vec<Index> from previous built Index2Vec<BoneWeight>
    ///in order to minimize weighted matrices computation on update
    typedef std::map<BoneWeightList, VertexGroup, SortByBoneWeightList> UnifyBoneGroup;
    UnifyBoneGroup unifyBuffer;
    vertexID=0;
    for (std::vector<BoneWeightList>::iterator it = _vertex2Bones.begin(); it != _vertex2Bones.end(); ++it,++vertexID)
    {
        BoneWeightList& bones = *it;
        // sort the vector to have a consistent key
        std::sort(bones.begin(), bones.end(), SortByNameAndWeight());
        // we use the vector<BoneWeight> as key to differentiate group
        UnifyBoneGroup::iterator result = unifyBuffer.find(bones);
        if (result == unifyBuffer.end())
            unifyBuffer[bones].getBoneWeights()=bones;
        unifyBuffer[bones].getVertexes().push_back(vertexID);
    }
    if(_vertex2Bones.size()==unifyBuffer.size()) {
        OSG_WARN << "RigTransformSoftware::build mapping is useless no duplicate VertexGroup : too much " <<_vertex2Bones.size()<<"=="<<unifyBuffer.size()<< std::endl;

    }
    _uniqInfluenceSet2VertIDList.reserve(unifyBuffer.size());

    for (UnifyBoneGroup::iterator it = unifyBuffer.begin(); it != unifyBuffer.end(); ++it)
        _uniqInfluenceSet2VertIDList.push_back(it->second);

    OSG_DEBUG << "uniq groups " << _uniqInfluenceSet2VertIDList.size() << " for " << rig.getName() << std::endl;
}

bool RigTransformSoftware::prepareData(RigGeometry&rig) {
    ///find skeleton if not set
    if(!rig.getSkeleton() && !rig.getParents().empty())
    {
        RigGeometry::FindNearestParentSkeleton finder;
        if(rig.getParents().size() > 1)
            osg::notify(osg::WARN) << "A RigGeometry should not have multi parent ( " << rig.getName() << " )" << std::endl;
        rig.getParents()[0]->accept(finder);

        if(!finder._root.valid())
        {
            osg::notify(osg::WARN) << "A RigGeometry did not find a parent skeleton for RigGeometry ( " << rig.getName() << " )" << std::endl;
            return false;
        }
        rig.setSkeleton(finder._root.get());
    }
    ///get bonemap from skeleton
    BoneMapVisitor mapVisitor;
    rig.getSkeleton()->accept(mapVisitor);
    BoneMap boneMap = mapVisitor.getBoneMap();

    /// build minimal set of VertexGroup
    buildMinimumUpdateSet(boneMap,rig);

    ///set geom as it source
    if (rig.getSourceGeometry())
        rig.copyFrom(*rig.getSourceGeometry());

    osg::Vec3Array* normalSrc = dynamic_cast<osg::Vec3Array*>(rig.getSourceGeometry()->getNormalArray());
    osg::Vec3Array* positionSrc = dynamic_cast<osg::Vec3Array*>(rig.getSourceGeometry()->getVertexArray());

    if(!(positionSrc) || positionSrc->empty() )
        return false;
    if(normalSrc&& normalSrc->size()!=positionSrc->size())
        return false;

    /// setup Vertex and Normal arrays with copy of sources
    rig.setVertexArray(new osg::Vec3Array);
    osg::Vec3Array* positionDst =new osg::Vec3Array;
    rig.setVertexArray(positionDst);
    *positionDst=*positionSrc;
    positionDst->setDataVariance(osg::Object::DYNAMIC);

    if(normalSrc) {
        osg::Vec3Array* normalDst =new osg::Vec3Array;
        *normalDst=*normalSrc;
        rig.setNormalArray(normalDst, osg::Array::BIND_PER_VERTEX);
        normalDst->setDataVariance(osg::Object::DYNAMIC);
    }

    _needInit = false;
    return true;
}

void RigTransformSoftware::operator()(RigGeometry& geom)
{
    if (_needInit)
        if (!init(geom))
            return;

    if (!geom.getSourceGeometry()) {
        OSG_WARN << this << " RigTransformSoftware no source geometry found on RigGeometry" << std::endl;
        return;
    }
    osg::Geometry& source = *geom.getSourceGeometry();
    osg::Geometry& destination = geom;

    osg::Vec3Array* positionSrc = static_cast<osg::Vec3Array*>(source.getVertexArray());
    osg::Vec3Array* positionDst = static_cast<osg::Vec3Array*>(destination.getVertexArray());
    osg::Vec3Array* normalSrc = dynamic_cast<osg::Vec3Array*>(source.getNormalArray());
    osg::Vec3Array* normalDst = static_cast<osg::Vec3Array*>(destination.getNormalArray());

    compute<osg::Vec3>(geom.getMatrixFromSkeletonToGeometry(),
                       geom.getInvMatrixFromSkeletonToGeometry(),
                       &positionSrc->front(),
                       &positionDst->front());
    positionDst->dirty();

    if (normalSrc )
    {
            computeNormal<osg::Vec3>(geom.getMatrixFromSkeletonToGeometry(),
                               geom.getInvMatrixFromSkeletonToGeometry(),
                               &normalSrc->front(),
                               &normalDst->front());
            normalDst->dirty();
    }

}

///convert BoneWeight to BonePtrWeight using bonemap
void RigTransformSoftware::initVertexSetFromBones(const BoneMap& map, const VertexInfluenceSet::UniqVertexGroupList& vertexgroups)
{
    _uniqInfluenceSet2VertIDList.clear();

    int size = vertexgroups.size();
    _uniqInfluenceSet2VertIDList.resize(size);
    //for (VertexInfluenceSet::UniqVertexGroupList::const_iterator vgit=vertexgroups.begin();         vgit!=vertexgroups.end();vgit++)
    for(int i = 0; i < size; i++)
    {
        const VertexInfluenceSet::VertexGroup& vg = vertexgroups[i];
        int nbBones = vg.getBones().size();
        BonePtrWeightList& boneList = _uniqInfluenceSet2VertIDList[i].getBoneWeights();

        double sumOfWeight = 0;
        for (int b = 0; b < nbBones; b++)
        {
            const std::string& bname = vg.getBones()[b].getBoneName();
            float weight = vg.getBones()[b].getWeight();
            BoneMap::const_iterator it = map.find(bname);
            if (it == map.end() )
            {
                if (_invalidInfluence.find(bname) != _invalidInfluence.end()) {
                    _invalidInfluence[bname] = true;
                    OSG_WARN << "RigTransformSoftware Bone " << bname << " not found, skip the influence group " <<bname  << std::endl;
                }
                continue;
            }
            Bone* bone = it->second.get();
            boneList.push_back(BonePtrWeight(bone->getName(), weight, bone));
            sumOfWeight += weight;
        }
        // if a bone referenced by a vertexinfluence is missed it can make the sum less than 1.0
        // so we check it and renormalize the all weight bone
        const double threshold = 1e-4;
        if (!vg.getBones().empty() &&
            (sumOfWeight < 1.0 - threshold ||  sumOfWeight > 1.0 + threshold))
        {
            for (int b = 0; b < (int)boneList.size(); b++)
                boneList[b].setWeight(boneList[b].getWeight() / sumOfWeight);
        }
        _uniqInfluenceSet2VertIDList[i].getVertexes() = vg.getVertexes();
    }
}
<|endoftext|>


<commit_before>/*
Copyright (c) by respective owners including Yahoo!, Microsoft, and
individual contributors. All rights reserved.  Released under a BSD (revised)
license as described in the file LICENSE.
 */
#include <float.h>
#include <errno.h>

#include "reductions.h"
#include "v_hashmap.h"
#include "label_dictionary.h"
#include "vw.h"

using namespace std;
using namespace LEARNER;

struct cb_adf {
  v_array<example*> ec_seq;

  bool need_to_clear;
  bool is_singleline;
  float csoaa_example_t;
  vw* all;

  base_learner* base;
};

bool check_cb_adf_sequence(cb_adf& data, size_t start_K)
{
  bool isTest = CB::example_is_test(*data.ec_seq[start_K]);
  for (size_t k=start_K; k<data.ec_seq.size(); k++) {
    example *ec = data.ec_seq[k];

    // Each sub-example must have just one cost
    assert(ec->l.cs.costs.size()==1);

    if (CB::example_is_test(*ec) != isTest) {
      isTest = true;
      cerr << "warning: cb_adf example has mix of train/test data; assuming test" << endl;
    }
    if (CB::ec_is_example_header(*ec)) {
      cerr << "warning: example headers at position " << k << ": can only have in initial position!" << endl;
      throw exception();
    }
  }
  return isTest;
}

  bool ec_is_label_definition(example& ec) // label defs look like "0:___" or just "label:___"
  {
    if (ec.indices.size() != 1) return false;
    if (ec.indices[0] != 'l') return false;
    v_array<CB::cb_class> costs = ec.l.cb.costs;
    for (size_t j=0; j<costs.size(); j++)
      if ((costs[j].action != 0) || (costs[j].cost <= 0.)) return false;
    return true;
  }

  bool ec_seq_is_label_definition(v_array<example*>ec_seq)
  {
    if (ec_seq.size() == 0) return false;
    bool is_lab = ec_is_label_definition(*ec_seq[0]);
    for (size_t i=1; i<ec_seq.size(); i++) {
      if (is_lab != ec_is_label_definition(*ec_seq[i])) {
        if (!((i == ec_seq.size()-1) && (example_is_newline(*ec_seq[i])))) {
          cerr << "error: mixed label definition and examples in ldf data!" << endl;
          throw exception();
        }
      }
    }
    return is_lab;
  }

template <bool is_learn>
void do_actual_learning(cb_adf& data, base_learner& base)
{
  //cdbg << "do_actual_learning size=" << data.ec_seq.size() << endl;
  if (data.ec_seq.size() <= 0) return;  // nothing to do

  /////////////////////// handle label definitions
  if (ec_seq_is_label_definition(data.ec_seq)) {
    // pass to cs_ldf
    return;
  }

  /////////////////////// add headers
  size_t K = data.ec_seq.size();
  size_t start_K = 0;
  if (CB::ec_is_example_header(*data.ec_seq[0])) {
    start_K = 1;
    for (size_t k=1; k<K; k++)
      LabelDict::add_example_namespaces_from_example(*data.ec_seq[k], *data.ec_seq[0]);
  }
  bool isTest = check_cb_adf_sequence(data, start_K);

  /////////////////////// do prediction
  size_t predicted_K = start_K;
  //do prediction via CS_LDF oracle
  /*  for (size_t k=start_K; k<K; k++) {
    example *ec = data.ec_seq[k];
    make_single_prediction(data, base, *ec);
    if (ec->partial_prediction < min_score) {
      min_score = ec->partial_prediction;
      predicted_K = k;
    }
    }*/

  /////////////////////// learn
  if (is_learn && !isTest)
    {//do learning
    }

  // Mark the predicted subexample with its class_index, all other with 0
  for (size_t k=start_K; k<K; k++)
    data.ec_seq[k]->pred.multiclass = (k == predicted_K) ? data.ec_seq[k]->l.cs.costs[0].class_index : 0;

  /////////////////////// remove header
  if (start_K > 0)
    for (size_t k=1; k<K; k++)
      LabelDict::del_example_namespaces_from_example(*data.ec_seq[k], *data.ec_seq[0]);
}

void global_print_newline(vw& all)
{
  char temp[1];
  temp[0] = '\n';
  for (size_t i=0; i<all.final_prediction_sink.size(); i++) {
    int f = all.final_prediction_sink[i];
    ssize_t t;
    t = io_buf::write_file_or_socket(f, temp, 1);
    if (t != 1)
      cerr << "write error: " << strerror(errno) << endl;
  }
}

void output_example(vw& all, example& ec, bool& hit_loss, v_array<example*>* ec_seq)
{
  v_array<CB::cb_class> costs = ec.l.cb.costs;

  if (example_is_newline(ec)) return;
  if (CB::ec_is_example_header(ec)) return;
  if (ec_is_label_definition(ec)) return;

  all.sd->total_features += ec.num_features;

  float loss = 0.;

  if (!CB::example_is_test(ec)) {
    for (size_t j=0; j<costs.size(); j++) {
      if (hit_loss) break;
      if (ec.pred.multiclass == costs[j].action) {
        loss = costs[j].cost;
        hit_loss = true;
      }
    }

    all.sd->sum_loss += loss;
    all.sd->sum_loss_since_last_dump += loss;
    assert(loss >= 0);
  }

  for (int* sink = all.final_prediction_sink.begin; sink != all.final_prediction_sink.end; sink++)
    all.print(*sink, (float)ec.pred.multiclass, 0, ec.tag);

  if (all.raw_prediction > 0) {
    string outputString;
    stringstream outputStringStream(outputString);
    for (size_t i = 0; i < costs.size(); i++) {
      if (i > 0) outputStringStream << ' ';
      outputStringStream << costs[i].action << ':' << costs[i].partial_prediction;
    }
    //outputStringStream << endl;
    all.print_text(all.raw_prediction, outputStringStream.str(), ec.tag);
  }

  CB::print_update(all, CB::example_is_test(ec), ec, ec_seq);
}

void output_example_seq(vw& all, cb_adf& data)
{
  if ((data.ec_seq.size() > 0) && !ec_seq_is_label_definition(data.ec_seq)) {
    all.sd->weighted_examples += 1;
    all.sd->example_number++;

    bool hit_loss = false;
    for (example** ecc=data.ec_seq.begin; ecc!=data.ec_seq.end; ecc++)
      output_example(all, **ecc, hit_loss, &(data.ec_seq));

    if (!data.is_singleline && (all.raw_prediction > 0))
      all.print_text(all.raw_prediction, "", data.ec_seq[0]->tag);
  }
}

void clear_seq_and_finish_examples(vw& all, cb_adf& data)
{
  if (data.ec_seq.size() > 0)
    for (example** ecc=data.ec_seq.begin; ecc!=data.ec_seq.end; ecc++)
      if ((*ecc)->in_use)
        VW::finish_example(all, *ecc);
  data.ec_seq.erase();
}

void finish_singleline_example(vw& all, cb_adf&, example& ec)
{
  if (! ec_is_label_definition(ec)) {
    all.sd->weighted_examples += 1;
    all.sd->example_number++;
  }
  bool hit_loss = false;
  output_example(all, ec, hit_loss, nullptr);
  VW::finish_example(all, &ec);
}

void finish_multiline_example(vw& all, cb_adf& data, example& ec)
{
  if (data.need_to_clear) {
    if (data.ec_seq.size() > 0) {
      output_example_seq(all, data);
      global_print_newline(all);
    }
    clear_seq_and_finish_examples(all, data);
    data.need_to_clear = false;
    if (ec.in_use) VW::finish_example(all, &ec);
  }
}

void end_examples(cb_adf& data)
{
  if (data.need_to_clear)
    data.ec_seq.erase();
}

void finish(cb_adf& data)
{
  data.ec_seq.delete_v();
}

template <bool is_learn>
void predict_or_learn(cb_adf& data, base_learner& base, example &ec) {
  vw* all = data.all;
  data.base = &base;
  bool is_test_ec = CB::example_is_test(ec);
  bool need_to_break = data.ec_seq.size() >= all->p->ring_size - 2;

  if (ec_is_label_definition(ec)) {
    if (data.ec_seq.size() > 0) {
      cerr << "error: label definition encountered in data block" << endl;
      throw exception();
    }
    data.ec_seq.push_back(&ec);
    do_actual_learning<is_learn>(data, base);
    data.need_to_clear = true;
  } else if ((example_is_newline(ec) && is_test_ec) || need_to_break) {
    do_actual_learning<is_learn>(data, base);
    data.need_to_clear = true;
  } else {
    if (data.need_to_clear) {  // should only happen if we're NOT driving
      data.ec_seq.erase();
      data.need_to_clear = false;
    }
    data.ec_seq.push_back(&ec);
  }
}

base_learner* cb_adf_setup(vw& all)
{
  if (missing_option<string, true>(all, "cb_adf", "Do Contextual Bandit learning with action dependent features.  Specify singleline or multiline."))
    return nullptr;

  cb_adf& ld = calloc_or_die<cb_adf>();

  ld.all = &all;

  string adf_arg;

  if( all.vm.count("cb_adf") )
    adf_arg = all.vm["cb_adf"].as<string>();

  if (adf_arg.compare("singleline") == 0 || adf_arg.compare("s") == 0)
    ld.is_singleline = true;
  else
    ld.is_singleline = false;

  all.p->lp = CB::cb_label;

  if (count(all.args.begin(), all.args.end(),"--csoaa_ldf") == 0 && count(all.args.begin(), all.args.end(),"--wap_ldf") == 0)
    {
      all.args.push_back("--csoaa_ldf");
      all.args.push_back(adf_arg);
    }

  learner<cb_adf>& l = init_learner(&ld, setup_base(all), predict_or_learn<true>, predict_or_learn<false>);
  if (ld.is_singleline)
    l.set_finish_example(finish_singleline_example);
  else
    l.set_finish_example(finish_multiline_example);
  l.set_finish(finish);
  l.set_end_examples(end_examples);
  return make_base(l);
}
<commit_msg>fixed link conflict<commit_after>/*
Copyright (c) by respective owners including Yahoo!, Microsoft, and
individual contributors. All rights reserved.  Released under a BSD (revised)
license as described in the file LICENSE.
 */
#include <float.h>
#include <errno.h>

#include "reductions.h"
#include "v_hashmap.h"
#include "label_dictionary.h"
#include "vw.h"

using namespace std;
using namespace LEARNER;

struct cb_adf {
  v_array<example*> ec_seq;

  bool need_to_clear;
  bool is_singleline;
  float csoaa_example_t;
  vw* all;

  base_learner* base;
};

namespace CB_ADF {

bool check_cb_adf_sequence(cb_adf& data, size_t start_K)
{
  bool isTest = CB::example_is_test(*data.ec_seq[start_K]);
  for (size_t k=start_K; k<data.ec_seq.size(); k++) {
    example *ec = data.ec_seq[k];

    // Each sub-example must have just one cost
    assert(ec->l.cs.costs.size()==1);

    if (CB::example_is_test(*ec) != isTest) {
      isTest = true;
      cerr << "warning: cb_adf example has mix of train/test data; assuming test" << endl;
    }
    if (CB::ec_is_example_header(*ec)) {
      cerr << "warning: example headers at position " << k << ": can only have in initial position!" << endl;
      throw exception();
    }
  }
  return isTest;
}

  bool ec_is_label_definition(example& ec) // label defs look like "0:___" or just "label:___"
  {
    if (ec.indices.size() != 1) return false;
    if (ec.indices[0] != 'l') return false;
    v_array<CB::cb_class> costs = ec.l.cb.costs;
    for (size_t j=0; j<costs.size(); j++)
      if ((costs[j].action != 0) || (costs[j].cost <= 0.)) return false;
    return true;
  }

  bool ec_seq_is_label_definition(v_array<example*>ec_seq)
  {
    if (ec_seq.size() == 0) return false;
    bool is_lab = ec_is_label_definition(*ec_seq[0]);
    for (size_t i=1; i<ec_seq.size(); i++) {
      if (is_lab != ec_is_label_definition(*ec_seq[i])) {
        if (!((i == ec_seq.size()-1) && (example_is_newline(*ec_seq[i])))) {
          cerr << "error: mixed label definition and examples in ldf data!" << endl;
          throw exception();
        }
      }
    }
    return is_lab;
  }

template <bool is_learn>
void do_actual_learning(cb_adf& data, base_learner& base)
{
  //cdbg << "do_actual_learning size=" << data.ec_seq.size() << endl;
  if (data.ec_seq.size() <= 0) return;  // nothing to do

  /////////////////////// handle label definitions
  if (ec_seq_is_label_definition(data.ec_seq)) {
    // pass to cs_ldf
    return;
  }

  /////////////////////// add headers
  size_t K = data.ec_seq.size();
  size_t start_K = 0;
  if (CB::ec_is_example_header(*data.ec_seq[0])) {
    start_K = 1;
    for (size_t k=1; k<K; k++)
      LabelDict::add_example_namespaces_from_example(*data.ec_seq[k], *data.ec_seq[0]);
  }
  bool isTest = check_cb_adf_sequence(data, start_K);

  /////////////////////// do prediction
  size_t predicted_K = start_K;
  //do prediction via CS_LDF oracle
  /*  for (size_t k=start_K; k<K; k++) {
    example *ec = data.ec_seq[k];
    make_single_prediction(data, base, *ec);
    if (ec->partial_prediction < min_score) {
      min_score = ec->partial_prediction;
      predicted_K = k;
    }
    }*/

  /////////////////////// learn
  if (is_learn && !isTest)
    {//do learning
    }

  // Mark the predicted subexample with its class_index, all other with 0
  for (size_t k=start_K; k<K; k++)
    data.ec_seq[k]->pred.multiclass = (k == predicted_K) ? data.ec_seq[k]->l.cs.costs[0].class_index : 0;

  /////////////////////// remove header
  if (start_K > 0)
    for (size_t k=1; k<K; k++)
      LabelDict::del_example_namespaces_from_example(*data.ec_seq[k], *data.ec_seq[0]);
}

void global_print_newline(vw& all)
{
  char temp[1];
  temp[0] = '\n';
  for (size_t i=0; i<all.final_prediction_sink.size(); i++) {
    int f = all.final_prediction_sink[i];
    ssize_t t;
    t = io_buf::write_file_or_socket(f, temp, 1);
    if (t != 1)
      cerr << "write error: " << strerror(errno) << endl;
  }
}

void output_example(vw& all, example& ec, bool& hit_loss, v_array<example*>* ec_seq)
{
  v_array<CB::cb_class> costs = ec.l.cb.costs;

  if (example_is_newline(ec)) return;
  if (CB::ec_is_example_header(ec)) return;
  if (ec_is_label_definition(ec)) return;

  all.sd->total_features += ec.num_features;

  float loss = 0.;

  if (!CB::example_is_test(ec)) {
    for (size_t j=0; j<costs.size(); j++) {
      if (hit_loss) break;
      if (ec.pred.multiclass == costs[j].action) {
        loss = costs[j].cost;
        hit_loss = true;
      }
    }

    all.sd->sum_loss += loss;
    all.sd->sum_loss_since_last_dump += loss;
    assert(loss >= 0);
  }

  for (int* sink = all.final_prediction_sink.begin; sink != all.final_prediction_sink.end; sink++)
    all.print(*sink, (float)ec.pred.multiclass, 0, ec.tag);

  if (all.raw_prediction > 0) {
    string outputString;
    stringstream outputStringStream(outputString);
    for (size_t i = 0; i < costs.size(); i++) {
      if (i > 0) outputStringStream << ' ';
      outputStringStream << costs[i].action << ':' << costs[i].partial_prediction;
    }
    //outputStringStream << endl;
    all.print_text(all.raw_prediction, outputStringStream.str(), ec.tag);
  }

  CB::print_update(all, CB::example_is_test(ec), ec, ec_seq);
}

void output_example_seq(vw& all, cb_adf& data)
{
  if ((data.ec_seq.size() > 0) && !ec_seq_is_label_definition(data.ec_seq)) {
    all.sd->weighted_examples += 1;
    all.sd->example_number++;

    bool hit_loss = false;
    for (example** ecc=data.ec_seq.begin; ecc!=data.ec_seq.end; ecc++)
      output_example(all, **ecc, hit_loss, &(data.ec_seq));

    if (!data.is_singleline && (all.raw_prediction > 0))
      all.print_text(all.raw_prediction, "", data.ec_seq[0]->tag);
  }
}

void clear_seq_and_finish_examples(vw& all, cb_adf& data)
{
  if (data.ec_seq.size() > 0)
    for (example** ecc=data.ec_seq.begin; ecc!=data.ec_seq.end; ecc++)
      if ((*ecc)->in_use)
        VW::finish_example(all, *ecc);
  data.ec_seq.erase();
}

void finish_singleline_example(vw& all, cb_adf&, example& ec)
{
  if (! ec_is_label_definition(ec)) {
    all.sd->weighted_examples += 1;
    all.sd->example_number++;
  }
  bool hit_loss = false;
  output_example(all, ec, hit_loss, nullptr);
  VW::finish_example(all, &ec);
}

void finish_multiline_example(vw& all, cb_adf& data, example& ec)
{
  if (data.need_to_clear) {
    if (data.ec_seq.size() > 0) {
      output_example_seq(all, data);
      global_print_newline(all);
    }
    clear_seq_and_finish_examples(all, data);
    data.need_to_clear = false;
    if (ec.in_use) VW::finish_example(all, &ec);
  }
}

void end_examples(cb_adf& data)
{
  if (data.need_to_clear)
    data.ec_seq.erase();
}

void finish(cb_adf& data)
{
  data.ec_seq.delete_v();
}

template <bool is_learn>
void predict_or_learn(cb_adf& data, base_learner& base, example &ec) {
  vw* all = data.all;
  data.base = &base;
  bool is_test_ec = CB::example_is_test(ec);
  bool need_to_break = data.ec_seq.size() >= all->p->ring_size - 2;

  if (ec_is_label_definition(ec)) {
    if (data.ec_seq.size() > 0) {
      cerr << "error: label definition encountered in data block" << endl;
      throw exception();
    }
    data.ec_seq.push_back(&ec);
    do_actual_learning<is_learn>(data, base);
    data.need_to_clear = true;
  } else if ((example_is_newline(ec) && is_test_ec) || need_to_break) {
    do_actual_learning<is_learn>(data, base);
    data.need_to_clear = true;
  } else {
    if (data.need_to_clear) {  // should only happen if we're NOT driving
      data.ec_seq.erase();
      data.need_to_clear = false;
    }
    data.ec_seq.push_back(&ec);
  }
}
}

base_learner* cb_adf_setup(vw& all)
{
  if (missing_option<string, true>(all, "cb_adf", "Do Contextual Bandit learning with action dependent features.  Specify singleline or multiline."))
    return nullptr;

  cb_adf& ld = calloc_or_die<cb_adf>();

  ld.all = &all;

  string adf_arg;

  if( all.vm.count("cb_adf") )
    adf_arg = all.vm["cb_adf"].as<string>();

  if (adf_arg.compare("singleline") == 0 || adf_arg.compare("s") == 0)
    ld.is_singleline = true;
  else
    ld.is_singleline = false;

  all.p->lp = CB::cb_label;

  if (count(all.args.begin(), all.args.end(),"--csoaa_ldf") == 0 && count(all.args.begin(), all.args.end(),"--wap_ldf") == 0)
    {
      all.args.push_back("--csoaa_ldf");
      all.args.push_back(adf_arg);
    }

  learner<cb_adf>& l = init_learner(&ld, setup_base(all), CB_ADF::predict_or_learn<true>, CB_ADF::predict_or_learn<false>);
  if (ld.is_singleline)
    l.set_finish_example(CB_ADF::finish_singleline_example);
  else
    l.set_finish_example(CB_ADF::finish_multiline_example);
  l.set_finish(CB_ADF::finish);
  l.set_end_examples(CB_ADF::end_examples);
  return make_base(l);
}
<|endoftext|>


<commit_before>#ifndef DATA__POOOL__H
#define DATA__POOOL__H

#include "MediatorFactory.h"

class AbstractMediator;

#include <map>

/**
 *  The DataPool singleton.
 *  You must register every Mediator in the DataPool.
 *  Use facade to mix up Mediator together and/or filter them !
 **/
class DataPool{ // singleton
	public:
		~DataPool();
		static DataPool *  Instance();
		// Delegate mediator to DataPool
		void               Register   (AbstractMediator * mediator); // take ownership
		AbstractMediator * GetMediator(MediatorType type);
		bool               Contains   (MediatorType type);
	private:
		explicit DataPool(){};
		static DataPool * _pool;
		std::map<MediatorType,AbstractMediator * > _mediators;
};

template< class T >
T * SafeMediatorAccess(){
	T * med = dynamic_cast<T*>(DataPool::Instance()->GetMediator(TraitMediatorId<T>::Id()));
	if ( ! med ){
		std::cout << "Cannot get mediator in DataPool : " << TraitMediatorId<T>::Id() << std::endl;
		return NULL;
	}
	if ( med->Status() == AbstractMediator::M_BAD ){
		std::cout << "Mediator is in BAD state : " << TraitMediatorId<T>::Id() << std::endl;
		return NULL;
	}
	if ( med->Status() == AbstractMediator::M_NOT_READY ){
		std::cout << "Mediator is not initialized yet. Forced init : " << TraitMediatorId<T>::Id() << std::endl;
		med->Init();
		return med;
	}
	// standard case
	return med;
}

#endif // DATA__POOOL__H
<commit_msg>fix g++ build<commit_after>#ifndef DATA__POOOL__H
#define DATA__POOOL__H

#include "MediatorFactory.h"
#include "AbstractMediator.hpp"

#include <map>

/**
 *  The DataPool singleton.
 *  You must register every Mediator in the DataPool.
 *  Use facade to mix up Mediator together and/or filter them !
 **/
class DataPool{ // singleton
	public:
		~DataPool();
		static DataPool *  Instance();
		// Delegate mediator to DataPool
		void               Register   (AbstractMediator * mediator); // take ownership
		AbstractMediator * GetMediator(MediatorType type);
		bool               Contains   (MediatorType type);
	private:
		explicit DataPool(){};
		static DataPool * _pool;
		std::map<MediatorType,AbstractMediator * > _mediators;
};

template< class T >
T * SafeMediatorAccess(){
	T * med = dynamic_cast<T*>(DataPool::Instance()->GetMediator(TraitMediatorId<T>::Id()));
	if ( ! med ){
		std::cout << "Cannot get mediator in DataPool : " << TraitMediatorId<T>::Id() << std::endl;
		return NULL;
	}
	if ( med->Status() == AbstractMediator::M_BAD ){
		std::cout << "Mediator is in BAD state : " << TraitMediatorId<T>::Id() << std::endl;
		return NULL;
	}
	if ( med->Status() == AbstractMediator::M_NOT_READY ){
		std::cout << "Mediator is not initialized yet. Forced init : " << TraitMediatorId<T>::Id() << std::endl;
		med->Init();
		return med;
	}
	// standard case
	return med;
}

#endif // DATA__POOOL__H
<|endoftext|>