<commit_before>
#include "itkCSVNumericObjectFileWriter.h"
#include "antsUtilities.h"
#include "antsAllocImage.h"
#include "itkantsRegistrationHelper.h"
#include "itkCSVArray2DFileReader.h"
#include "itkAffineTransform.h"
#include "itkCompositeTransform.h"
#include "itkDisplacementFieldTransform.h"
#include "itkIdentityTransform.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkMatrixOffsetTransformBase.h"
#include "itkResampleImageFilter.h"
#include "itkTransformFactory.h"
#include "itkTransformFileReader.h"
#include "itkTransformToDisplacementFieldSource.h"

#include "itkBSplineInterpolateImageFunction.h"
#include "itkLinearInterpolateImageFunction.h"
#include "itkGaussianInterpolateImageFunction.h"
#include "itkNearestNeighborInterpolateImageFunction.h"
#include "itkWindowedSincInterpolateImageFunction.h"
#include "itkLabelImageGaussianInterpolateImageFunction.h"

namespace ants
{
template <unsigned int Dimension>
int antsApplyTransformsToPoints( itk::ants::CommandLineParser::Pointer & parser )
{
  typedef double                RealType;
  typedef double                PixelType;
  typedef vnl_matrix<PixelType> MatrixType;
  MatrixType points_out;
  MatrixType points_in;
  //  bool input_points_are_indices = false;

  /**
   * Input object option - for now, we're limiting this to images.
   */
  typename itk::ants::CommandLineParser::OptionType::Pointer inputOption = parser->GetOption( "input" );
  typename itk::ants::CommandLineParser::OptionType::Pointer outputOption = parser->GetOption( "output" );
  if( inputOption && inputOption->GetNumberOfValues() > 0 )
    {
    antscout << "Input csv file: " << inputOption->GetValue() << std::endl;
    std::string ext = itksys::SystemTools::GetFilenameExtension(  ( inputOption->GetValue() ).c_str()  );
    if( strcmp(ext.c_str(), ".csv") == 0 )
      {
      typedef itk::CSVArray2DFileReader<double> ReaderType;
      typename ReaderType::Pointer reader = ReaderType::New();
      reader->SetFileName(  ( inputOption->GetValue() ).c_str()  );
      reader->SetFieldDelimiterCharacter( ',' );
      reader->SetStringDelimiterCharacter( '"' );
      reader->HasColumnHeadersOn();
      reader->HasRowHeadersOff();
      reader->UseStringDelimiterCharacterOff();
      try
        {
        reader->Update();
        }
      catch( itk::ExceptionObject& exp )
        {
        antscout << "Exception caught!" << std::endl;
        antscout << exp << std::endl;
        }
      typedef itk::CSVArray2DDataObject<double> DataFrameObjectType;
      DataFrameObjectType::Pointer dfo = reader->GetOutput();
      points_in = dfo->GetMatrix();
      points_out.set_size( points_in.rows(), Dimension );
      }
    else
      {
      antscout << "An input csv file is required." << std::endl;
      return EXIT_FAILURE;
      }

    if(  points_in.cols() < Dimension )
      {
      antscout << "The number of columns in the input point set is fewer than " << Dimension << " Exiting."
               << std::endl;
      return EXIT_FAILURE;
      }

    if( outputOption && outputOption->GetNumberOfValues() > 0 )
      {
      if( outputOption->GetNumberOfParameters( 0 ) > 1 &&
          parser->Convert<unsigned int>( outputOption->GetParameter( 0, 1 ) ) == 0 )
        {
        antscout << "An input csv file is required." << std::endl;
        return EXIT_FAILURE;
        }
      }

    /**
     * Transform option
     */
    // Register the matrix offset transform base class to the
    // transform factory for compatibility with the current ANTs.
    typedef itk::MatrixOffsetTransformBase<double, Dimension, Dimension> MatrixOffsetTransformType;
    itk::TransformFactory<MatrixOffsetTransformType>::RegisterTransform();
    typedef itk::MatrixOffsetTransformBase<double, Dimension, Dimension> MatrixOffsetTransformType;
    itk::TransformFactory<MatrixOffsetTransformType>::RegisterTransform();

    /**
     * Load an identity transform in case no transforms are loaded.
     */
    // Register the matrix offset transform base class to the
    // transform factory for compatibility with the current ANTs.
    typedef itk::MatrixOffsetTransformBase<double, 2, 2> MatrixOffsetTransformType2D;
    itk::TransformFactory<MatrixOffsetTransformType2D>::RegisterTransform();
    typedef itk::MatrixOffsetTransformBase<double, 3, 3> MatrixOffsetTransformType3D;
    itk::TransformFactory<MatrixOffsetTransformType3D>::RegisterTransform();

    typedef itk::CompositeTransform<double, Dimension> CompositeTransformType;
    typename CompositeTransformType::InputPointType point_in;
    typename CompositeTransformType::OutputPointType point_out;
    typename itk::ants::CommandLineParser::OptionType::Pointer transformOption = parser->GetOption( "transform" );

    typename CompositeTransformType::Pointer compositeTransform = GetCompositeTransformFromParserOption<Dimension>(
        parser, transformOption );
    if( compositeTransform.IsNull() )
      {
      return EXIT_FAILURE;
      }
    for( unsigned int pointct = 0; pointct < points_in.rows(); pointct++ )
      {
      point_in.Fill( 0 );
      point_out.Fill( 0 );
      for( unsigned int p = 0; p < Dimension; p++ )
        {
        point_in[p] = points_in( pointct, p );
        }
      point_out = compositeTransform->TransformPoint( point_in );
      for( unsigned int p = 0; p < Dimension; p++ )
        {
        points_out( pointct, p ) = point_out[p];
        }
      std::cout << " point-in = " << point_in << " point-out = " << point_out << std::endl;
      }

    /**
     * output
     */
    if( outputOption && outputOption->GetNumberOfValues() > 0 )
      {
      std::string outputFileName = "";
      if( outputOption->GetNumberOfParameters( 0 ) > 1 &&
          parser->Convert<unsigned int>( outputOption->GetParameter( 0, 1 ) ) == 0 )
        {
        outputFileName = outputOption->GetParameter( 0, 0 );
        }
      else
        {
        outputFileName = outputOption->GetValue();
        }
      antscout << "Output warped points to csv file: " << outputFileName << std::endl;
      std::vector<std::string> ColumnHeaders;
      std::string              colname = std::string("x");
      ColumnHeaders.push_back( colname );
      colname = std::string("y");
      ColumnHeaders.push_back( colname );
      colname = std::string("z");
      if( Dimension > 2 )
        {
        ColumnHeaders.push_back( colname );
        }
      colname = std::string("t");
      if( Dimension > 3 )
        {
        ColumnHeaders.push_back( colname );
        }

      typedef itk::CSVNumericObjectFileWriter<double, 1, 1> WriterType;
      WriterType::Pointer writer = WriterType::New();
      writer->SetFileName( outputFileName );
      writer->SetInput( &points_out );
      writer->SetColumnHeaders( ColumnHeaders );
      try
        {
        writer->Write();
        }
      catch( itk::ExceptionObject& exp )
        {
        antscout << "Exception caught!" << std::endl;
        antscout << exp << std::endl;
        return EXIT_FAILURE;
        }
      }
    }

  return EXIT_SUCCESS;
}

static void InitializeCommandLineOptions( itk::ants::CommandLineParser *parser )
{
  typedef itk::ants::CommandLineParser::OptionType OptionType;

    {
    std::string description =
      std::string( "This option forces the points to be treated as a specified-" )
      + std::string( "dimensionality." );

    OptionType::Pointer option = OptionType::New();
    option->SetLongName( "dimensionality" );
    option->SetShortName( 'd' );
    option->SetUsageOption( 0, "2/3" );
    option->SetDescription( description );
    parser->AddOption( option );
    }

    {
    std::string description =
      std::string( "Currently, the only input supported is a csv file with " )
      + std::string( "columns including x,y (2D), x,y,z (3D) or x,y,z,t (4D) column headers." )
      + std::string( "The points should be defined in physical space." );

    OptionType::Pointer option = OptionType::New();
    option->SetLongName( "input" );
    option->SetShortName( 'i' );
    option->SetUsageOption( 0, "inputFileName" );
    option->SetDescription( description );
    parser->AddOption( option );
    }

    {
    std::string description =
      std::string( "One can output the warped points to a csv file.");

    OptionType::Pointer option = OptionType::New();
    option->SetLongName( "output" );
    option->SetShortName( 'o' );
    option->SetUsageOption( 0, "warpedOutputFileName" );
    option->SetDescription( description );
    parser->AddOption( option );
    }

    {
    std::string description =
      std::string( "Several transform options are supported including all " )
      + std::string( "those defined in the ITK library in addition to " )
      + std::string( "a deformation field transform.  The ordering of " )
      + std::string( "the transformations follows the ordering specified " )
      + std::string( "on the command line.  An identity transform is pushed " )
      + std::string( "onto the transformation stack. Each new transform " )
      + std::string( "encountered on the command line is also pushed onto " )
      + std::string( "the transformation stack. Then, to warp the input object, " )
      + std::string( "each point comprising the input object is warped first " )
      + std::string( "according to the last transform pushed onto the stack " )
      + std::string( "followed by the second to last transform, etc. until " )
      + std::string( "the last transform encountered which is the identity " )
      + std::string( "transform. " )
      + std::string( "Also, it should be noted that the inverse transform can " )
      + std::string( "be accommodated with the usual caveat that such an inverse " )
      + std::string( "must be defined by the specified transform class " );

    OptionType::Pointer option = OptionType::New();
    option->SetLongName( "transform" );
    option->SetShortName( 't' );
    option->SetUsageOption( 0, "transformFileName" );
    option->SetUsageOption( 1, "[transformFileName,useInverse]" );
    option->SetDescription( description );
    parser->AddOption( option );
    }

    {
    std::string description = std::string( "Print the help menu (short version)." );

    OptionType::Pointer option = OptionType::New();
    option->SetShortName( 'h' );
    option->SetDescription( description );
    option->AddValue( std::string( "0" ) );
    parser->AddOption( option );
    }

    {
    std::string description = std::string( "Print the help menu." );

    OptionType::Pointer option = OptionType::New();
    option->SetLongName( "help" );
    option->SetDescription( description );
    option->AddValue( std::string( "0" ) );
    parser->AddOption( option );
    }
}

// entry point for the library; parameter 'args' is equivalent to 'argv' in (argc,argv) of commandline parameters to
// 'main()'
int antsApplyTransformsToPoints( std::vector<std::string> args, std::ostream* out_stream = NULL )
{
  // put the arguments coming in as 'args' into standard (argc,argv) format;
  // 'args' doesn't have the command name as first, argument, so add it manually;
  // 'args' may have adjacent arguments concatenated into one argument,
  // which the parser should handle
  args.insert( args.begin(), "antsApplyTransformsToPoints" );
  std::remove( args.begin(), args.end(), std::string( "" ) );
  std::remove( args.begin(), args.end(), std::string( "" ) );
  int     argc = args.size();
  char* * argv = new char *[args.size() + 1];
  for( unsigned int i = 0; i < args.size(); ++i )
    {
    // allocate space for the string plus a null character
    argv[i] = new char[args[i].length() + 1];
    std::strncpy( argv[i], args[i].c_str(), args[i].length() );
    // place the null character in the end
    argv[i][args[i].length()] = '\0';
    }
  argv[argc] = 0;
  // class to automatically cleanup argv upon destruction
  class Cleanup_argv
  {
public:
    Cleanup_argv( char* * argv_, int argc_plus_one_ ) : argv( argv_ ), argc_plus_one( argc_plus_one_ )
    {
    }

    ~Cleanup_argv()
    {
      for( unsigned int i = 0; i < argc_plus_one; ++i )
        {
        delete[] argv[i];
        }
      delete[] argv;
    }

private:
    char* *      argv;
    unsigned int argc_plus_one;
  };
  Cleanup_argv cleanup_argv( argv, argc + 1 );

  antscout->set_stream( out_stream );

  itk::ants::CommandLineParser::Pointer parser =
    itk::ants::CommandLineParser::New();

  parser->SetCommand( argv[0] );

  std::string commandDescription =
    std::string( "antsApplyTransformsToPoints, applied to an input image, transforms it " )
    + std::string( "according to a reference image and a transform " )
    + std::string( "(or a set of transforms)." );

  parser->SetCommandDescription( commandDescription );
  InitializeCommandLineOptions( parser );

  parser->Parse( argc, argv );

  if( argc < 2 || ( parser->GetOption( "help" ) &&
                    ( parser->Convert<bool>( parser->GetOption( "help" )->GetValue() ) ) ) )
    {
    parser->PrintMenu( antscout, 5, false );
    if( argc < 2 )
      {
      return EXIT_FAILURE;
      }
    return EXIT_SUCCESS;
    }
  else if( parser->GetOption( 'h' ) &&
           ( parser->Convert<bool>( parser->GetOption( 'h' )->GetValue() ) ) )
    {
    parser->PrintMenu( antscout, 5, true );
    return EXIT_SUCCESS;
    }

  // Read in the first intensity image to get the image dimension.
  std::string filename;

  itk::ants::CommandLineParser::OptionType::Pointer inputOption =
    parser->GetOption( "input" );
  if( inputOption && inputOption->GetNumberOfValues() > 0 )
    {
    if( inputOption->GetNumberOfParameters( 0 ) > 0 )
      {
      filename = inputOption->GetParameter( 0, 0 );
      }
    else
      {
      filename = inputOption->GetValue( 0 );
      }
    }
  else
    {
    antscout << "No csv file point set was specified." << std::endl;
    return EXIT_FAILURE;
    }

  unsigned int                                      dimension = 3;
  itk::ants::CommandLineParser::OptionType::Pointer dimOption =
    parser->GetOption( "dimensionality" );
  if( dimOption && dimOption->GetNumberOfValues() > 0 )
    {
    dimension = parser->Convert<unsigned int>( dimOption->GetValue() );
    }
  else
    {
    antscout << "No -d ( dimensionality ) option is specified.  Exiting." << std::endl;
    return EXIT_FAILURE;
    }

  switch( dimension )
    {
    case 2:
      {
      antsApplyTransformsToPoints<2>( parser );
      }
      break;
    case 3:
      {
      antsApplyTransformsToPoints<3>( parser );
      }
      break;
    case 4:
      {
      antsApplyTransformsToPoints<4>( parser );
      }
      break;
    default:
      antscout << "Unsupported dimension" << std::endl;
      return EXIT_FAILURE;
    }
  return EXIT_SUCCESS;
}
} // namespace ants
<commit_msg>BUG:  Compatibility with earlier changes.<commit_after>
#include "itkCSVNumericObjectFileWriter.h"
#include "antsUtilities.h"
#include "antsAllocImage.h"
#include "itkantsRegistrationHelper.h"
#include "itkCSVArray2DFileReader.h"
#include "itkAffineTransform.h"
#include "itkCompositeTransform.h"
#include "itkDisplacementFieldTransform.h"
#include "itkIdentityTransform.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkMatrixOffsetTransformBase.h"
#include "itkResampleImageFilter.h"
#include "itkTransformFactory.h"
#include "itkTransformFileReader.h"
#include "itkTransformToDisplacementFieldSource.h"

#include "itkBSplineInterpolateImageFunction.h"
#include "itkLinearInterpolateImageFunction.h"
#include "itkGaussianInterpolateImageFunction.h"
#include "itkNearestNeighborInterpolateImageFunction.h"
#include "itkWindowedSincInterpolateImageFunction.h"
#include "itkLabelImageGaussianInterpolateImageFunction.h"

namespace ants
{
template <unsigned int Dimension>
int antsApplyTransformsToPoints( itk::ants::CommandLineParser::Pointer & parser )
{
  typedef double                RealType;
  typedef double                PixelType;
  typedef vnl_matrix<PixelType> MatrixType;
  MatrixType points_out;
  MatrixType points_in;
  //  bool input_points_are_indices = false;

  /**
   * Input object option - for now, we're limiting this to images.
   */
  typename itk::ants::CommandLineParser::OptionType::Pointer inputOption = parser->GetOption( "input" );
  typename itk::ants::CommandLineParser::OptionType::Pointer outputOption = parser->GetOption( "output" );
  if( inputOption && inputOption->GetNumberOfValues() > 0 )
    {
    antscout << "Input csv file: " << inputOption->GetValue() << std::endl;
    std::string ext = itksys::SystemTools::GetFilenameExtension(  ( inputOption->GetValue() ).c_str()  );
    if( strcmp(ext.c_str(), ".csv") == 0 )
      {
      typedef itk::CSVArray2DFileReader<double> ReaderType;
      typename ReaderType::Pointer reader = ReaderType::New();
      reader->SetFileName(  ( inputOption->GetValue() ).c_str()  );
      reader->SetFieldDelimiterCharacter( ',' );
      reader->SetStringDelimiterCharacter( '"' );
      reader->HasColumnHeadersOn();
      reader->HasRowHeadersOff();
      reader->UseStringDelimiterCharacterOff();
      try
        {
        reader->Update();
        }
      catch( itk::ExceptionObject& exp )
        {
        antscout << "Exception caught!" << std::endl;
        antscout << exp << std::endl;
        }
      typedef itk::CSVArray2DDataObject<double> DataFrameObjectType;
      DataFrameObjectType::Pointer dfo = reader->GetOutput();
      points_in = dfo->GetMatrix();
      points_out.set_size( points_in.rows(), Dimension );
      }
    else
      {
      antscout << "An input csv file is required." << std::endl;
      return EXIT_FAILURE;
      }

    if(  points_in.cols() < Dimension )
      {
      antscout << "The number of columns in the input point set is fewer than " << Dimension << " Exiting."
               << std::endl;
      return EXIT_FAILURE;
      }

    if( outputOption && outputOption->GetNumberOfValues() > 0 )
      {
      if( outputOption->GetNumberOfParameters( 0 ) > 1 &&
          parser->Convert<unsigned int>( outputOption->GetParameter( 0, 1 ) ) == 0 )
        {
        antscout << "An input csv file is required." << std::endl;
        return EXIT_FAILURE;
        }
      }

    /**
     * Transform option
     */
    // Register the matrix offset transform base class to the
    // transform factory for compatibility with the current ANTs.
    typedef itk::MatrixOffsetTransformBase<double, Dimension, Dimension> MatrixOffsetTransformType;
    itk::TransformFactory<MatrixOffsetTransformType>::RegisterTransform();
    typedef itk::MatrixOffsetTransformBase<double, Dimension, Dimension> MatrixOffsetTransformType;
    itk::TransformFactory<MatrixOffsetTransformType>::RegisterTransform();

    /**
     * Load an identity transform in case no transforms are loaded.
     */
    // Register the matrix offset transform base class to the
    // transform factory for compatibility with the current ANTs.
    typedef itk::MatrixOffsetTransformBase<double, 2, 2> MatrixOffsetTransformType2D;
    itk::TransformFactory<MatrixOffsetTransformType2D>::RegisterTransform();
    typedef itk::MatrixOffsetTransformBase<double, 3, 3> MatrixOffsetTransformType3D;
    itk::TransformFactory<MatrixOffsetTransformType3D>::RegisterTransform();

    typedef itk::CompositeTransform<double, Dimension> CompositeTransformType;
    typename CompositeTransformType::InputPointType point_in;
    typename CompositeTransformType::OutputPointType point_out;
    typename itk::ants::CommandLineParser::OptionType::Pointer transformOption = parser->GetOption( "transform" );

    std::vector<bool> isDerivedTransform;
    typename CompositeTransformType::Pointer compositeTransform =
      GetCompositeTransformFromParserOption<Dimension>( parser, transformOption, isDerivedTransform );
    if( compositeTransform.IsNull() )
      {
      return EXIT_FAILURE;
      }
    for( unsigned int pointct = 0; pointct < points_in.rows(); pointct++ )
      {
      point_in.Fill( 0 );
      point_out.Fill( 0 );
      for( unsigned int p = 0; p < Dimension; p++ )
        {
        point_in[p] = points_in( pointct, p );
        }
      point_out = compositeTransform->TransformPoint( point_in );
      for( unsigned int p = 0; p < Dimension; p++ )
        {
        points_out( pointct, p ) = point_out[p];
        }
      std::cout << " point-in = " << point_in << " point-out = " << point_out << std::endl;
      }

    /**
     * output
     */
    if( outputOption && outputOption->GetNumberOfValues() > 0 )
      {
      std::string outputFileName = "";
      if( outputOption->GetNumberOfParameters( 0 ) > 1 &&
          parser->Convert<unsigned int>( outputOption->GetParameter( 0, 1 ) ) == 0 )
        {
        outputFileName = outputOption->GetParameter( 0, 0 );
        }
      else
        {
        outputFileName = outputOption->GetValue();
        }
      antscout << "Output warped points to csv file: " << outputFileName << std::endl;
      std::vector<std::string> ColumnHeaders;
      std::string              colname = std::string("x");
      ColumnHeaders.push_back( colname );
      colname = std::string("y");
      ColumnHeaders.push_back( colname );
      colname = std::string("z");
      if( Dimension > 2 )
        {
        ColumnHeaders.push_back( colname );
        }
      colname = std::string("t");
      if( Dimension > 3 )
        {
        ColumnHeaders.push_back( colname );
        }

      typedef itk::CSVNumericObjectFileWriter<double, 1, 1> WriterType;
      WriterType::Pointer writer = WriterType::New();
      writer->SetFileName( outputFileName );
      writer->SetInput( &points_out );
      writer->SetColumnHeaders( ColumnHeaders );
      try
        {
        writer->Write();
        }
      catch( itk::ExceptionObject& exp )
        {
        antscout << "Exception caught!" << std::endl;
        antscout << exp << std::endl;
        return EXIT_FAILURE;
        }
      }
    }

  return EXIT_SUCCESS;
}

static void InitializeCommandLineOptions( itk::ants::CommandLineParser *parser )
{
  typedef itk::ants::CommandLineParser::OptionType OptionType;

    {
    std::string description =
      std::string( "This option forces the points to be treated as a specified-" )
      + std::string( "dimensionality." );

    OptionType::Pointer option = OptionType::New();
    option->SetLongName( "dimensionality" );
    option->SetShortName( 'd' );
    option->SetUsageOption( 0, "2/3" );
    option->SetDescription( description );
    parser->AddOption( option );
    }

    {
    std::string description =
      std::string( "Currently, the only input supported is a csv file with " )
      + std::string( "columns including x,y (2D), x,y,z (3D) or x,y,z,t (4D) column headers." )
      + std::string( "The points should be defined in physical space." );

    OptionType::Pointer option = OptionType::New();
    option->SetLongName( "input" );
    option->SetShortName( 'i' );
    option->SetUsageOption( 0, "inputFileName" );
    option->SetDescription( description );
    parser->AddOption( option );
    }

    {
    std::string description =
      std::string( "One can output the warped points to a csv file.");

    OptionType::Pointer option = OptionType::New();
    option->SetLongName( "output" );
    option->SetShortName( 'o' );
    option->SetUsageOption( 0, "warpedOutputFileName" );
    option->SetDescription( description );
    parser->AddOption( option );
    }

    {
    std::string description =
      std::string( "Several transform options are supported including all " )
      + std::string( "those defined in the ITK library in addition to " )
      + std::string( "a deformation field transform.  The ordering of " )
      + std::string( "the transformations follows the ordering specified " )
      + std::string( "on the command line.  An identity transform is pushed " )
      + std::string( "onto the transformation stack. Each new transform " )
      + std::string( "encountered on the command line is also pushed onto " )
      + std::string( "the transformation stack. Then, to warp the input object, " )
      + std::string( "each point comprising the input object is warped first " )
      + std::string( "according to the last transform pushed onto the stack " )
      + std::string( "followed by the second to last transform, etc. until " )
      + std::string( "the last transform encountered which is the identity " )
      + std::string( "transform. " )
      + std::string( "Also, it should be noted that the inverse transform can " )
      + std::string( "be accommodated with the usual caveat that such an inverse " )
      + std::string( "must be defined by the specified transform class " );

    OptionType::Pointer option = OptionType::New();
    option->SetLongName( "transform" );
    option->SetShortName( 't' );
    option->SetUsageOption( 0, "transformFileName" );
    option->SetUsageOption( 1, "[transformFileName,useInverse]" );
    option->SetDescription( description );
    parser->AddOption( option );
    }

    {
    std::string description = std::string( "Print the help menu (short version)." );

    OptionType::Pointer option = OptionType::New();
    option->SetShortName( 'h' );
    option->SetDescription( description );
    option->AddValue( std::string( "0" ) );
    parser->AddOption( option );
    }

    {
    std::string description = std::string( "Print the help menu." );

    OptionType::Pointer option = OptionType::New();
    option->SetLongName( "help" );
    option->SetDescription( description );
    option->AddValue( std::string( "0" ) );
    parser->AddOption( option );
    }
}

// entry point for the library; parameter 'args' is equivalent to 'argv' in (argc,argv) of commandline parameters to
// 'main()'
int antsApplyTransformsToPoints( std::vector<std::string> args, std::ostream* out_stream = NULL )
{
  // put the arguments coming in as 'args' into standard (argc,argv) format;
  // 'args' doesn't have the command name as first, argument, so add it manually;
  // 'args' may have adjacent arguments concatenated into one argument,
  // which the parser should handle
  args.insert( args.begin(), "antsApplyTransformsToPoints" );
  std::remove( args.begin(), args.end(), std::string( "" ) );
  std::remove( args.begin(), args.end(), std::string( "" ) );
  int     argc = args.size();
  char* * argv = new char *[args.size() + 1];
  for( unsigned int i = 0; i < args.size(); ++i )
    {
    // allocate space for the string plus a null character
    argv[i] = new char[args[i].length() + 1];
    std::strncpy( argv[i], args[i].c_str(), args[i].length() );
    // place the null character in the end
    argv[i][args[i].length()] = '\0';
    }
  argv[argc] = 0;
  // class to automatically cleanup argv upon destruction
  class Cleanup_argv
  {
public:
    Cleanup_argv( char* * argv_, int argc_plus_one_ ) : argv( argv_ ), argc_plus_one( argc_plus_one_ )
    {
    }

    ~Cleanup_argv()
    {
      for( unsigned int i = 0; i < argc_plus_one; ++i )
        {
        delete[] argv[i];
        }
      delete[] argv;
    }

private:
    char* *      argv;
    unsigned int argc_plus_one;
  };
  Cleanup_argv cleanup_argv( argv, argc + 1 );

  antscout->set_stream( out_stream );

  itk::ants::CommandLineParser::Pointer parser =
    itk::ants::CommandLineParser::New();

  parser->SetCommand( argv[0] );

  std::string commandDescription =
    std::string( "antsApplyTransformsToPoints, applied to an input image, transforms it " )
    + std::string( "according to a reference image and a transform " )
    + std::string( "(or a set of transforms)." );

  parser->SetCommandDescription( commandDescription );
  InitializeCommandLineOptions( parser );

  parser->Parse( argc, argv );

  if( argc < 2 || ( parser->GetOption( "help" ) &&
                    ( parser->Convert<bool>( parser->GetOption( "help" )->GetValue() ) ) ) )
    {
    parser->PrintMenu( antscout, 5, false );
    if( argc < 2 )
      {
      return EXIT_FAILURE;
      }
    return EXIT_SUCCESS;
    }
  else if( parser->GetOption( 'h' ) &&
           ( parser->Convert<bool>( parser->GetOption( 'h' )->GetValue() ) ) )
    {
    parser->PrintMenu( antscout, 5, true );
    return EXIT_SUCCESS;
    }

  // Read in the first intensity image to get the image dimension.
  std::string filename;

  itk::ants::CommandLineParser::OptionType::Pointer inputOption =
    parser->GetOption( "input" );
  if( inputOption && inputOption->GetNumberOfValues() > 0 )
    {
    if( inputOption->GetNumberOfParameters( 0 ) > 0 )
      {
      filename = inputOption->GetParameter( 0, 0 );
      }
    else
      {
      filename = inputOption->GetValue( 0 );
      }
    }
  else
    {
    antscout << "No csv file point set was specified." << std::endl;
    return EXIT_FAILURE;
    }

  unsigned int                                      dimension = 3;
  itk::ants::CommandLineParser::OptionType::Pointer dimOption =
    parser->GetOption( "dimensionality" );
  if( dimOption && dimOption->GetNumberOfValues() > 0 )
    {
    dimension = parser->Convert<unsigned int>( dimOption->GetValue() );
    }
  else
    {
    antscout << "No -d ( dimensionality ) option is specified.  Exiting." << std::endl;
    return EXIT_FAILURE;
    }

  switch( dimension )
    {
    case 2:
      {
      antsApplyTransformsToPoints<2>( parser );
      }
      break;
    case 3:
      {
      antsApplyTransformsToPoints<3>( parser );
      }
      break;
    case 4:
      {
      antsApplyTransformsToPoints<4>( parser );
      }
      break;
    default:
      antscout << "Unsupported dimension" << std::endl;
      return EXIT_FAILURE;
    }
  return EXIT_SUCCESS;
}
} // namespace ants
<|endoftext|>


<commit_before>/*! \file
 *
 * \brief Storage of generic data via (key, value) pair (header)
 * \author Benjamin Pritchard (ben@bennyp.org)
 */

#ifndef _GUARD_PROPERTYMAP_HPP_
#define _GUARD_PROPERTYMAP_HPP_

#include <map>

#include "bpmodule/exception/GeneralException.hpp"
#include "bpmodule/datastore/GenericHolder.hpp"
#include "bpmodule/modulelocator/ModuleInfo.hpp"

namespace bpmodule {
namespace datastore {

/*! \brief A mapping of arbirtrary data with some copy-on-write semantics
 *
 * A PropertyMap can store an arbitrary data type, as long that data type
 * has a copy and move constructor. Once stored, the data itself is immutable.
 *
 * Multiple PropertyMap can store references to the same data.
 * Since the data itself is read-only, modifications in one map cannot affect
 * another. Erasing or replacing the data in one map leaves the references
 * in any other maps referencing this data untouched.
 *
 * \tparam KEYTYPE the type of key to use in the map.
 */
template<typename KEYTYPE>
class PropertyMap
{
    public:
        PropertyMap(void)          = default;
        virtual ~PropertyMap(void) = default;

        /*! \brief Copies a property map
         *
         * Underlying data is NOT copied, rather just the references.
         *
         * \param [in] rhs The object to copy
         */
        PropertyMap(const PropertyMap & rhs)             = default;

        /*! \brief Moves the contents of another object to this
         *
         * References to data are removed from the other object.
         *
         * \param [in] rhs The object to copy
         */
        PropertyMap(PropertyMap && rhs)                  = default;

        /*! \brief Assigns the contents of another object to this
         *
         * \copydetails PropertyMap::PropertyMap(const PropertyMap &)
         */
        PropertyMap & operator=(const PropertyMap & rhs) = default;

        /*! \brief Moves the contents of another object to this
         *
         * \copydetails PropertyMap::PropertyMap(PropertyMap &&)
         */
        PropertyMap & operator=(PropertyMap && rhs)      = default;

        /*! \brief Determine if this object contains data for a key
         *
         * \param [in] key The key to the data
         * \return True if the key exists, false otherwise
         */
        bool HasKey(const KEYTYPE & key) const
        {
            return opmap_.count(key);
        }

        /*! \brief Determine if this object contains data of a specific type for a key
         *
         * \tparam T Type to compare to
         *
         * \param [in] key The key to the data
         * \return True if the key exists and is of type T, false otherwise
         */
        template<typename T>
        bool HasType(const KEYTYPE & key) const
        {
            if(!HasKey(key))
                return false;

            // craziest syntax
            return GetOrThrow_(key).value->template IsType<T>();
        }

        /*! \brief Get a string representing the type for a given key
         *
         * \throw bpmodule::exception::MapException
         *        if the key doesn't exist
         *
         * \param [in] key The key to the data
         * \return A string representing the type for a key
         */
        std::string GetType(const KEYTYPE & key) const
        {
            return GetOrThrow_(key).value->Type();
        }

        /*! \brief Get a string representing the type for a given key (demangled)
         *
         * \throw bpmodule::exception::MapException
         *        if the key doesn't exist
         *
         * \param [in] key The key to the data
         * \return A string representing the type for a key
         */
        std::string GetDemangledType(const KEYTYPE & key) const
        {
            return GetOrThrow_(key).value->DemangledType();
        }

        /*! \brief Obtain all the keys contained in this object
         *
         * \return A vector of strings containing all the keys
         */
        std::vector<KEYTYPE> GetKeys(void) const
        {
            std::vector<std::string> v;
            v.reserve(opmap_.size());
            for(auto & it : opmap_)
                v.push_back(it.first);
            return v;
        }

        /*! \brief Returns the source of the information
         *
         * \throw bpmodule::exception::MapException
         *        if the key doesn't exist
         *
         * \param [in] key The key to the data
         */
        modulelocator::ModuleInfo GetSource(const KEYTYPE & key) const
        {
            return GetOrThrow_(key).source;
        }

        /*! \brief Return the number of elements contained
         *
         * \exnothrow
         *
         * \return Number of elements in this container
         */
        size_t Size(void) const noexcept
        {
            return opmap_.size();
        }

    protected:
        /////////////////////////////////////////////////
        // to be exposed selectively by derived classes
        /////////////////////////////////////////////////

        /*! \brief Return a const reference to the underlying data
         *
         * \throw bpmodule::exception::MapException
         *        if the key doesn't exist or
         *        is of the wrong type
         *
         * \tparam T The type of the data
         *
         * \param [in] key The key to the data
         * \return A const referance to the data
         */
        template<typename T>
        const T & GetRef(const KEYTYPE & key) const
        {
            const detail::GenericHolder<T> * ph = GetOrThrow_Cast_<T>(key);
            return ph->GetRef();
        }

        /*! \brief Return a copy of the underlying data
         *
         * \throw bpmodule::exception::MapException
         *        if the key doesn't exist or
         *        is of the wrong type
         *
         * \tparam T The type of the data
         *
         * \param [in] key The key to the data
         * \return A copy of the data
         */
        template<typename T>
        T GetCopy(const KEYTYPE & key) const
        {
            return GetRef<T>(key);
        }

        /*! \brief Set the data associated with a given key via copy
         *
         * If the key exists, the data is overwritten.
         * Then, the data itself may remain if another PropertyMap contains the same data
         * (set via SetRef, etc).
         *
         * \exstrong
         *
         * \tparam T The type of the data
         *
         * \param [in] key The key to the data
         * \param [in] value The data to store
         */
        template<typename T>
        void Set(const KEYTYPE & key, const T & value, const modulelocator::ModuleInfo & source)
        {
            detail::GenericBasePtr v(new detail::GenericHolder<T>(value));
            Set_(key, std::move(v), source);
        }

        /*! \brief Set the data associated with a given key via move semantics
         *
         * \copydetails Set
         */
        template<typename T>
        void Take(const KEYTYPE & key, T && value, const modulelocator::ModuleInfo & source)
        {
            detail::GenericBasePtr v(new detail::GenericHolder<T>(std::move(value)));
            Set_(key, std::move(v));
        }

        /*! \brief Store the same data as found in another object
         *
         * This function does not copy or take the actual data. Rather, only a
         * pointer is copied. Erasing or replacing data in this map does not
         * affect the other map. If the key already exists in this map, it is
         * replaced.
         *
         * \throw bpmodule::exception:MapException if the key is not found in the other map
         *
         * \exstrong
         *
         * \param [in] other The other object from which to get the data
         * \param [in] key The key of the object in the other object
         */
        void SetRef(const PropertyMap<KEYTYPE> & other, const KEYTYPE & key)
        {
            //Setref with the same key
            SetRef(other, key, key);
        }

        /*! \copydoc SetRef
         * \param [in] newkey The key under which to store the data in this object
         */
        void SetRef(const PropertyMap<KEYTYPE> & other, const KEYTYPE & key, const KEYTYPE & newkey)
        {
            // get the shared ptr, etc, from the other property map
            // This should copy the shared_ptr
            PropMapEntry pe = other.GetOrThrow_(key);

            // add it here
            // should have strong exception guarantee
            if(opmap_.count(newkey))
                opmap_.at(newkey) = pe;
            else
                opmap_.emplace(newkey, std::move(pe));
        }

        /*! \brief Remove a key from this data store
         *
         * The data itself may remain if another PropertyMap contains the same data
         * (set via SetRef, etc).
         *
         * The key does not have to exist. If the key doesn't exists, nothing will happen.
         *
         * \exstrong
         *
         * \param [in] key The key to the data
         * \return The number of elements removed
         */
        size_t Erase(const KEYTYPE & key)
        {
            return opmap_.erase(key);
        }

        ///////////////////////////////////
        // Python functions
        ///////////////////////////////////

        /*! \copydoc GetCopy
         *
         * Returns the data as a python object.
         *
         * \throw bpmodule::exception::PythonConvertException if there is a problem with a conversion
         */
        boost::python::object GetCopyPy(const KEYTYPE & key) const
        {
            // may throw
            return GetOrThrow_(key).value->GetPy();
        }

        /*! \copydoc Set
         *
         * Copies the internal python data to a C++ type. Specializes the templated function.
         *
         * \throw bpmodule::exception::PythonConvertException if there is a problem with a conversion
         */
        void SetPy(const KEYTYPE & key, const boost::python::object & value, const modulelocator::ModuleInfo & source)
        {
            // catch errors from conversions in GenericHolderFactory
            try {
                Set_(key, detail::GenericHolderFactory(value), source);
            }
            catch(exception::GeneralException & ex)
            {
                // append key info if GenericHolderFactory throws
                ex.AppendInfo("mapkey", key);
                throw;
            }
        }

    private:

        ////////////////////////////////
        // Actual storage of the data //
        ////////////////////////////////

        /*! \brief Stores a pointer to a placeholder, plus some other information
         */
        struct PropMapEntry
        {
            detail::GenericBasePtr value;      //! The stored data
            modulelocator::ModuleInfo source;  //! Where the data came from
        };

        //! The container to use to store the data
        typedef std::map<std::string, PropMapEntry> PropMap;

        //! Map actually containing the data
        PropMap opmap_;

        ////////////////////////////////
        // Private functions          //
        ////////////////////////////////

        /*! \brief Obtains a PropMapEntry or throws if key doesn't exist
         *
         * \throw bpmodule::exception::MapException if key doesn't exist
         *
         * \exstrong
         *
         * \param [in] key Key of the data to get
         * \return PropMapEntry containing the data for the given key
         */
        PropMapEntry & GetOrThrow_(const KEYTYPE & key)
        {
            if(opmap_.count(key))
                return opmap_.at(key);
            else
                throw exception::GeneralException("Key not found",
                                                  "location", "PropertyMap",
                                                  "mapkey", key);
        }

        //! \copydoc GetOrThrow_
        const PropMapEntry & GetOrThrow_(const KEYTYPE & key) const
        {
            if(opmap_.count(key))
                return opmap_.at(key);
            else
                throw exception::GeneralException("Key not found",
                                                  "location", "PropertyMap",
                                                  "mapkey", key);
        }

        /*! \brief Obtains a pointer to a GenericHolder cast to desired type
         *
         * \throw bpmodule::exception::MapException if key
         *        doesn't exist or if the cast fails.
         *
         * \param [in] key Key of the data to get
         * \return detail::GenericHolder containing the data for the given key
         */
        template<typename T>
        const detail::GenericHolder<T> * GetOrThrow_Cast_(const KEYTYPE & key) const
        {
            const PropMapEntry & pme = GetOrThrow_(key);
            const detail::GenericHolder<T> * ph = dynamic_cast<const detail::GenericHolder<T> *>(pme.value.get());
            if(ph == nullptr)
                throw exception::GeneralException("Bad cast",
                                                  "location", "PropertyMap",
                                                  "mapkey", key,
                                                  "fromtype", pme.value->Type(),
                                                  "totype", typeid(T).name());

            return ph;
        }

        /*! \brief Sets the data for a given key via a GenericBasePtr
         *
         * \exstrong
         *
         * \param [in] key Key of the data to set
         * \param [in] value Pointer to the data to set
         */
        void Set_(const KEYTYPE & key, detail::GenericBasePtr && value, const modulelocator::ModuleInfo & source)
        {
            if(opmap_.count(key))
            {
                PropMapEntry & phe = GetOrThrow_(key);
                phe.value = std::move(value);
            }
            else
            {
                PropMapEntry phe{std::move(value), source};

                // emplace has strong exception guarantee
                opmap_.emplace(key, std::move(phe));
            }
        }

};

} // close namespace datastore
} // close namespace bpmodule

#endif

<commit_msg>Use DataStoreException<commit_after>/*! \file
 *
 * \brief Storage of generic data via (key, value) pair (header)
 * \author Benjamin Pritchard (ben@bennyp.org)
 */

#ifndef _GUARD_PROPERTYMAP_HPP_
#define _GUARD_PROPERTYMAP_HPP_

#include <map>

#include "bpmodule/exception/DataStoreException.hpp"
#include "bpmodule/datastore/GenericHolder.hpp"
#include "bpmodule/modulelocator/ModuleInfo.hpp"

namespace bpmodule {
namespace datastore {

/*! \brief A mapping of arbirtrary data with some copy-on-write semantics
 *
 * A PropertyMap can store an arbitrary data type, as long that data type
 * has a copy and move constructor. Once stored, the data itself is immutable.
 *
 * Multiple PropertyMap can store references to the same data.
 * Since the data itself is read-only, modifications in one map cannot affect
 * another. Erasing or replacing the data in one map leaves the references
 * in any other maps referencing this data untouched.
 *
 * \tparam KEYTYPE the type of key to use in the map.
 */
template<typename KEYTYPE>
class PropertyMap
{
    public:
        PropertyMap(void)          = default;
        virtual ~PropertyMap(void) = default;

        /*! \brief Copies a property map
         *
         * Underlying data is NOT copied, rather just the references.
         *
         * \param [in] rhs The object to copy
         */
        PropertyMap(const PropertyMap & rhs)             = default;

        /*! \brief Moves the contents of another object to this
         *
         * References to data are removed from the other object.
         *
         * \param [in] rhs The object to copy
         */
        PropertyMap(PropertyMap && rhs)                  = default;

        /*! \brief Assigns the contents of another object to this
         *
         * \copydetails PropertyMap::PropertyMap(const PropertyMap &)
         */
        PropertyMap & operator=(const PropertyMap & rhs) = default;

        /*! \brief Moves the contents of another object to this
         *
         * \copydetails PropertyMap::PropertyMap(PropertyMap &&)
         */
        PropertyMap & operator=(PropertyMap && rhs)      = default;

        /*! \brief Determine if this object contains data for a key
         *
         * \param [in] key The key to the data
         * \return True if the key exists, false otherwise
         */
        bool HasKey(const KEYTYPE & key) const
        {
            return opmap_.count(key);
        }

        /*! \brief Determine if this object contains data of a specific type for a key
         *
         * \tparam T Type to compare to
         *
         * \param [in] key The key to the data
         * \return True if the key exists and is of type T, false otherwise
         */
        template<typename T>
        bool HasType(const KEYTYPE & key) const
        {
            if(!HasKey(key))
                return false;

            // craziest syntax
            return GetOrThrow_(key).value->template IsType<T>();
        }

        /*! \brief Get a string representing the type for a given key
         *
         * \throw bpmodule::exception::DataStoreException
         *        if the key doesn't exist
         *
         * \param [in] key The key to the data
         * \return A string representing the type for a key
         */
        std::string GetType(const KEYTYPE & key) const
        {
            return GetOrThrow_(key).value->Type();
        }

        /*! \brief Get a string representing the type for a given key (demangled)
         *
         * \throw bpmodule::exception::DataStoreException
         *        if the key doesn't exist
         *
         * \param [in] key The key to the data
         * \return A string representing the type for a key
         */
        std::string GetDemangledType(const KEYTYPE & key) const
        {
            return GetOrThrow_(key).value->DemangledType();
        }

        /*! \brief Obtain all the keys contained in this object
         *
         * \return A vector of strings containing all the keys
         */
        std::vector<KEYTYPE> GetKeys(void) const
        {
            std::vector<std::string> v;
            v.reserve(opmap_.size());
            for(auto & it : opmap_)
                v.push_back(it.first);
            return v;
        }

        /*! \brief Returns the source of the information
         *
         * \throw bpmodule::exception::DataStoreException
         *        if the key doesn't exist
         *
         * \param [in] key The key to the data
         */
        modulelocator::ModuleInfo GetSource(const KEYTYPE & key) const
        {
            return GetOrThrow_(key).source;
        }

        /*! \brief Return the number of elements contained
         *
         * \exnothrow
         *
         * \return Number of elements in this container
         */
        size_t Size(void) const noexcept
        {
            return opmap_.size();
        }

    protected:
        /////////////////////////////////////////////////
        // to be exposed selectively by derived classes
        /////////////////////////////////////////////////

        /*! \brief Return a const reference to the underlying data
         *
         * \throw bpmodule::exception::DataStoreException
         *        if the key doesn't exist or
         *        is of the wrong type
         *
         * \tparam T The type of the data
         *
         * \param [in] key The key to the data
         * \return A const referance to the data
         */
        template<typename T>
        const T & GetRef(const KEYTYPE & key) const
        {
            const detail::GenericHolder<T> * ph = GetOrThrow_Cast_<T>(key);
            return ph->GetRef();
        }

        /*! \brief Return a copy of the underlying data
         *
         * \throw bpmodule::exception::DataStoreException
         *        if the key doesn't exist or
         *        is of the wrong type
         *
         * \tparam T The type of the data
         *
         * \param [in] key The key to the data
         * \return A copy of the data
         */
        template<typename T>
        T GetCopy(const KEYTYPE & key) const
        {
            return GetRef<T>(key);
        }

        /*! \brief Set the data associated with a given key via copy
         *
         * If the key exists, the data is overwritten.
         * Then, the data itself may remain if another PropertyMap contains the same data
         * (set via SetRef, etc).
         *
         * \exstrong
         *
         * \tparam T The type of the data
         *
         * \param [in] key The key to the data
         * \param [in] value The data to store
         */
        template<typename T>
        void Set(const KEYTYPE & key, const T & value, const modulelocator::ModuleInfo & source)
        {
            detail::GenericBasePtr v(new detail::GenericHolder<T>(value));
            Set_(key, std::move(v), source);
        }

        /*! \brief Set the data associated with a given key via move semantics
         *
         * \copydetails Set
         */
        template<typename T>
        void Take(const KEYTYPE & key, T && value, const modulelocator::ModuleInfo & source)
        {
            detail::GenericBasePtr v(new detail::GenericHolder<T>(std::move(value)));
            Set_(key, std::move(v));
        }

        /*! \brief Store the same data as found in another object
         *
         * This function does not copy or take the actual data. Rather, only a
         * pointer is copied. Erasing or replacing data in this map does not
         * affect the other map. If the key already exists in this map, it is
         * replaced.
         *
         * \throw bpmodule::exception:DataStoreException if the key is not found in the other map
         *
         * \exstrong
         *
         * \param [in] other The other object from which to get the data
         * \param [in] key The key of the object in the other object
         */
        void SetRef(const PropertyMap<KEYTYPE> & other, const KEYTYPE & key)
        {
            //Setref with the same key
            SetRef(other, key, key);
        }

        /*! \copydoc SetRef
         * \param [in] newkey The key under which to store the data in this object
         */
        void SetRef(const PropertyMap<KEYTYPE> & other, const KEYTYPE & key, const KEYTYPE & newkey)
        {
            // get the shared ptr, etc, from the other property map
            // This should copy the shared_ptr
            PropMapEntry pe = other.GetOrThrow_(key);

            // add it here
            // should have strong exception guarantee
            if(opmap_.count(newkey))
                opmap_.at(newkey) = pe;
            else
                opmap_.emplace(newkey, std::move(pe));
        }

        /*! \brief Remove a key from this data store
         *
         * The data itself may remain if another PropertyMap contains the same data
         * (set via SetRef, etc).
         *
         * The key does not have to exist. If the key doesn't exists, nothing will happen.
         *
         * \exstrong
         *
         * \param [in] key The key to the data
         * \return The number of elements removed
         */
        size_t Erase(const KEYTYPE & key)
        {
            return opmap_.erase(key);
        }

        ///////////////////////////////////
        // Python functions
        ///////////////////////////////////

        /*! \copydoc GetCopy
         *
         * Returns the data as a python object.
         *
         * \throw bpmodule::exception::PythonConvertException if there is a problem with a conversion
         */
        boost::python::object GetCopyPy(const KEYTYPE & key) const
        {
            // may throw
            return GetOrThrow_(key).value->GetPy();
        }

        /*! \copydoc Set
         *
         * Copies the internal python data to a C++ type. Specializes the templated function.
         *
         * \throw bpmodule::exception::PythonConvertException if there is a problem with a conversion
         */
        void SetPy(const KEYTYPE & key, const boost::python::object & value, const modulelocator::ModuleInfo & source)
        {
            // catch errors from conversions in GenericHolderFactory
            try {
                Set_(key, detail::GenericHolderFactory(value), source);
            }
            catch(exception::DataStoreException & ex)
            {
                // append key info if GenericHolderFactory throws
                ex.AppendInfo("mapkey", key);
                throw;
            }
        }

    private:

        ////////////////////////////////
        // Actual storage of the data //
        ////////////////////////////////

        /*! \brief Stores a pointer to a placeholder, plus some other information
         */
        struct PropMapEntry
        {
            detail::GenericBasePtr value;      //! The stored data
            modulelocator::ModuleInfo source;  //! Where the data came from
        };

        //! The container to use to store the data
        typedef std::map<std::string, PropMapEntry> PropMap;

        //! Map actually containing the data
        PropMap opmap_;

        ////////////////////////////////
        // Private functions          //
        ////////////////////////////////

        /*! \brief Obtains a PropMapEntry or throws if key doesn't exist
         *
         * \throw bpmodule::exception::DataStoreException if key doesn't exist
         *
         * \exstrong
         *
         * \param [in] key Key of the data to get
         * \return PropMapEntry containing the data for the given key
         */
        PropMapEntry & GetOrThrow_(const KEYTYPE & key)
        {
            if(opmap_.count(key))
                return opmap_.at(key);
            else
                throw exception::DataStoreException("Key not found", key,
                                                    "location", "PropertyMap");
        }

        //! \copydoc GetOrThrow_
        const PropMapEntry & GetOrThrow_(const KEYTYPE & key) const
        {
            if(opmap_.count(key))
                return opmap_.at(key);
            else
                throw exception::DataStoreException("Key not found", key,
                                                    "location", "PropertyMap");
        }

        /*! \brief Obtains a pointer to a GenericHolder cast to desired type
         *
         * \throw bpmodule::exception::DataStoreException if key
         *        doesn't exist or if the cast fails.
         *
         * \param [in] key Key of the data to get
         * \return detail::GenericHolder containing the data for the given key
         */
        template<typename T>
        const detail::GenericHolder<T> * GetOrThrow_Cast_(const KEYTYPE & key) const
        {
            const PropMapEntry & pme = GetOrThrow_(key);
            const detail::GenericHolder<T> * ph = dynamic_cast<const detail::GenericHolder<T> *>(pme.value.get());
            if(ph == nullptr)
                throw exception::DataStoreException("Bad cast", key,
                                                    "location", "PropertyMap",
                                                    "fromtype", pme.value->Type(),
                                                    "totype", typeid(T).name());

            return ph;
        }

        /*! \brief Sets the data for a given key via a GenericBasePtr
         *
         * \exstrong
         *
         * \param [in] key Key of the data to set
         * \param [in] value Pointer to the data to set
         */
        void Set_(const KEYTYPE & key, detail::GenericBasePtr && value, const modulelocator::ModuleInfo & source)
        {
            if(opmap_.count(key))
            {
                PropMapEntry & phe = GetOrThrow_(key);
                phe.value = std::move(value);
            }
            else
            {
                PropMapEntry phe{std::move(value), source};

                // emplace has strong exception guarantee
                opmap_.emplace(key, std::move(phe));
            }
        }

};

} // close namespace datastore
} // close namespace bpmodule

#endif

<|endoftext|>


<commit_before>/*******************************************************************************
* ALMA - Atacama Large Millimiter Array
* (c) European Southern Observatory, 2011
*
* This library 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 library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
*
* "@(#) $Id: bdNTSenderTest.cpp,v 1.11 2011/11/09 12:01:36 bjeram Exp $"
*
* who       when      what
* --------  --------  ----------------------------------------------
* bjeram  2011-04-19  created
*/
#include "bulkDataNTSenderFlow.h"
#include <iostream>
#include <ace/Get_Opt.h>

using namespace AcsBulkdata;

int main(int argc, char *argv[])
{
	char c;
	double send_time;
	unsigned int sleepPeriod=0;
	unsigned int dataSize=65000;
	ACE_Time_Value start_time, elapsed_time;

	LoggingProxy m_logger(0, 0, 31, 0);

	LoggingProxy::init (&m_logger);
    ACS_CHECK_LOGGER;

	// Parse the args
    ACE_Get_Opt get_opts (argc, argv, "w:s:");
    while(( c = get_opts()) != -1 ) {
    	switch(c) {
    	case 'w':
    		sleepPeriod = atoi(get_opts.opt_arg());
    		break;
    	case 's':
    		dataSize = atoi(get_opts.opt_arg());
    		break;
    	}
    }//while

	BulkDataNTSenderStream senderStream1("DefaultStream");

	BulkDataNTSenderFlow* flow0 = senderStream1.createFlow("00");
	BulkDataNTSenderFlow* flow1 = senderStream1.createFlow("01");

	sleep(1); //here we should wait for at least one receiver
	//std::cout << "press a key to start.." << std::endl;
	//getchar();

	unsigned char parm[]="123";

	flow0->startSend(parm, 3);

// for test purpose we do not invoke startSend
//	strcpy(parm, "abc");
//	flow1->startSend(parm, 3);

	//unsigned char data[]="Hello wrold !!!!";
	unsigned char *data= new unsigned char[dataSize];
	for (unsigned int i=0; i<dataSize; i++)
			data[i]=i;

	ACS_SHORT_LOG((LM_INFO, "Going to send: %d Bytes to %d receivers", dataSize, flow0->getNumberOfReceivers()));
	start_time = ACE_OS::gettimeofday();
	flow0->sendData(data, dataSize);
	elapsed_time = ACE_OS::gettimeofday() - start_time;
	send_time = (elapsed_time.sec()+( elapsed_time.usec() / 1000000. ));
	ACS_SHORT_LOG((LM_INFO, "Transfer rate: %f", (dataSize/(1024*1024))/send_time));

	flow1->sendData(data, dataSize);

	for (unsigned int i=0; i<dataSize; i++)
				data[i]=i%10;
	flow0->sendData(data, dataSize);
	flow1->sendData(data, dataSize);

	sleep(2);
	//std::cout << "press a key to send stop.." << std::endl;
	//getchar();
	flow0->stopSend();
	flow1->stopSend();

	if (sleepPeriod>0)
	{
		sleep(sleepPeriod);
	}
	else
	{
		std::cout << "press a key to exit.." << std::endl;
		getchar();
	}

	delete flow0;
// flow1 will be deleted when senderStream1 is deleted

}
<commit_msg>transfer rate is now properly calculated and log cache increased to 10<commit_after>/*******************************************************************************
* ALMA - Atacama Large Millimiter Array
* (c) European Southern Observatory, 2011
*
* This library 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 library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
*
* "@(#) $Id: bdNTSenderTest.cpp,v 1.12 2012/01/13 15:22:09 bjeram Exp $"
*
* who       when      what
* --------  --------  ----------------------------------------------
* bjeram  2011-04-19  created
*/
#include "bulkDataNTSenderFlow.h"
#include <iostream>
#include <ace/Get_Opt.h>

using namespace AcsBulkdata;

int main(int argc, char *argv[])
{
	char c;
	double send_time;
	unsigned int sleepPeriod=0;
	unsigned int dataSize=65000;
	ACE_Time_Value start_time, elapsed_time;

	LoggingProxy m_logger(10, 0, 31, 0);

	LoggingProxy::init (&m_logger);
    ACS_CHECK_LOGGER;

	// Parse the args
    ACE_Get_Opt get_opts (argc, argv, "w:s:");
    while(( c = get_opts()) != -1 ) {
    	switch(c) {
    	case 'w':
    		sleepPeriod = atoi(get_opts.opt_arg());
    		break;
    	case 's':
    		dataSize = atoi(get_opts.opt_arg());
    		break;
    	}
    }//while

	BulkDataNTSenderStream senderStream1("DefaultStream");

	BulkDataNTSenderFlow* flow0 = senderStream1.createFlow("00");
	BulkDataNTSenderFlow* flow1 = senderStream1.createFlow("01");

	sleep(1); //here we should wait for at least one receiver
	//std::cout << "press a key to start.." << std::endl;
	//getchar();

	unsigned char parm[]="123";

	flow0->startSend(parm, 3);

// for test purpose we do not invoke startSend
//	strcpy(parm, "abc");
//	flow1->startSend(parm, 3);

	//unsigned char data[]="Hello wrold !!!!";
	unsigned char *data= new unsigned char[dataSize];
	for (unsigned int i=0; i<dataSize; i++)
			data[i]=i;

	ACS_SHORT_LOG((LM_INFO, "Going to send: %d Bytes to %d receivers", dataSize, flow0->getNumberOfReceivers()));
	start_time = ACE_OS::gettimeofday();
	flow0->sendData(data, dataSize);
	elapsed_time = ACE_OS::gettimeofday() - start_time;
	send_time = (elapsed_time.sec()+( elapsed_time.usec() / 1000000. ));
	ACS_SHORT_LOG((LM_INFO, "Transfer rate: %f", (dataSize/(1024.0*1024.0))/send_time));

	flow1->sendData(data, dataSize);

	for (unsigned int i=0; i<dataSize; i++)
				data[i]=i%10;
	flow0->sendData(data, dataSize);
	flow1->sendData(data, dataSize);

	sleep(2);
	//std::cout << "press a key to send stop.." << std::endl;
	//getchar();
	flow0->stopSend();
	flow1->stopSend();

	if (sleepPeriod>0)
	{
		sleep(sleepPeriod);
	}
	else
	{
		std::cout << "press a key to exit.." << std::endl;
		getchar();
	}

	delete flow0;
	m_logger.flush();
// flow1 will be deleted when senderStream1 is deleted

}
<|endoftext|>


<commit_before>
/*
 ********************************************************************************
 ***************************** Implementation Details ***************************
 ********************************************************************************
 */
#ifndef _Stroika_Foundation_Database_SQLite_inl_
#define _Stroika_Foundation_Database_SQLite_inl_    1

namespace   Stroika {
    namespace   Foundation {
        namespace   Database {
            namespace   SQLite {

                /*
                 ********************************************************************************
                 *********************************** SQLite::DB *********************************
                 ********************************************************************************
                 */
                inline  sqlite3*    DB::Peek ()
                {
                    return fDB_;
                }

            }
        }
    }
}
#endif  /*_Stroika_Foundation_Database_SQLite_inl_*/
<commit_msg>ifdef qHasFeature_sqlite missing<commit_after>
/*
 ********************************************************************************
 ***************************** Implementation Details ***************************
 ********************************************************************************
 */
#ifndef _Stroika_Foundation_Database_SQLite_inl_
#define _Stroika_Foundation_Database_SQLite_inl_    1

namespace   Stroika {
    namespace   Foundation {
        namespace   Database {
            namespace   SQLite {

                /*
                 ********************************************************************************
                 *********************************** SQLite::DB *********************************
                 ********************************************************************************
                 */
#if     qHasFeature_sqlite
                inline  sqlite3*    DB::Peek ()
                {
                    return fDB_;
                }
#endif

            }
        }
    }
}
#endif  /*_Stroika_Foundation_Database_SQLite_inl_*/
<|endoftext|>


<commit_before>#include "MacauPrior.h"

#include <SmurffCpp/IO/MatrixIO.h>
#include <SmurffCpp/IO/GenericIO.h>

#include <SmurffCpp/Utils/Distribution.h>
#include <SmurffCpp/Utils/Error.h>
#include <SmurffCpp/Utils/counters.h>

#include <SmurffCpp/Utils/linop.h>

#include <ios>

using namespace smurff;

MacauPrior::MacauPrior()
   : NormalPrior()
{
}

MacauPrior::MacauPrior(std::shared_ptr<Session> session, uint32_t mode)
   : NormalPrior(session, mode, "MacauPrior")
{
   beta_precision = SideInfoConfig::BETA_PRECISION_DEFAULT_VALUE;
   tol = SideInfoConfig::TOL_DEFAULT_VALUE;

   enable_beta_precision_sampling = Config::ENABLE_BETA_PRECISION_SAMPLING_DEFAULT_VALUE;
}

MacauPrior::~MacauPrior()
{
}

void MacauPrior::init()
{
   NormalPrior::init();

   THROWERROR_ASSERT_MSG(Features->rows() == num_item(), "Number of rows in train must be equal to number of rows in features");

   if (use_FtF)
   {
      std::uint64_t dim = Features->cols();
      FtF_plus_precision.resize(dim, dim);
      Features->At_mul_A(FtF_plus_precision);
      FtF_plus_precision.diagonal().array() += beta_precision;
   }

   Uhat.resize(num_latent(), Features->rows());
   Uhat.setZero();

   m_beta = std::make_shared<Eigen::MatrixXd>(num_latent(), Features->cols());
   beta().setZero();

   m_session->model().setLinkMatrix(m_mode, m_beta);
}

void MacauPrior::update_prior()
{
    /*
>> compute_uhat:             0.5012     (12%) in        110
>> main:             4.1396     (100%) in       1
>> rest of update_prior:             0.1684     (4%) in 110
>> sample hyper mu/Lambda:           0.3804     (9%) in 110
>> sample_beta:      1.4927     (36%) in        110
>> sample_latents:           3.8824     (94%) in        220
>> step:             3.9824     (96%) in        111
>> update_prior:             2.5436     (61%) in        110
*/
    COUNTER("update_prior");
    {
        COUNTER("rest of update_prior");
        // residual (Uhat is later overwritten):
        //uses: U, Uhat
        //writes: Uhat
        Udelta = U() - Uhat;
        // BBt = beta * beta'
        //uses: beta
        BBt = smurff::linop::A_mul_At_combo(beta());
    }

    // sampling Gaussian
    {
        // Uses, Udelta
        COUNTER("sample hyper mu/Lambda");
        std::tie(mu, Lambda) = CondNormalWishart(Udelta, mu0, b0,
            WI + beta_precision * BBt, df + beta().cols());
    }

    // uses: U, F
    // writes: Ft_y
    compute_Ft_y_omp(Ft_y);

    {
        COUNTER("sample_beta");
        if (use_FtF)
        {
            // uses: FtF, Ft_y,
            // writes: beta
            beta() = FtF_plus_precision.llt().solve(Ft_y.transpose()).transpose();
        }
        else
        {
            // uses: Features, beta_precision, Ft_y,
            // writes: beta
            blockcg_iter = Features->solve_blockcg(beta(), beta_precision, Ft_y, tol, 32, 8, throw_on_cholesky_error);
        }
    }

    {
        COUNTER("compute_uhat");
        // Uhat = beta * F
        // uses: beta, F
        // output: Uhat
        Features->compute_uhat(Uhat, beta());
    }

    if (enable_beta_precision_sampling)
    {
        // uses: beta
        // writes: FtF
        COUNTER("sample_beta_precision");
        double old_beta = beta_precision;
        beta_precision = sample_beta_precision(beta(), Lambda, beta_precision_nu0, beta_precision_mu0);
        FtF_plus_precision.diagonal().array() += beta_precision - old_beta;
   }
}

const Eigen::VectorXd MacauPrior::getMu(int n) const
{
   return mu + Uhat.col(n);
}

void MacauPrior::compute_Ft_y_omp(Eigen::MatrixXd& Ft_y)
{
   //-- input
   // mu, Lambda (small)
   // U
   // F
   //-- output
   // Ft_y
   const int num_feat = beta().cols();

   // Ft_y = (U .- mu + Normal(0, Lambda^-1)) * F + std::sqrt(beta_precision) * Normal(0, Lambda^-1)
   // Ft_y is [ D x F ] matrix

   //HyperU: num_latent x num_item
   HyperU = (U() + MvNormal_prec(Lambda, num_item())).colwise() - mu;
   Ft_y = Features->A_mul_B(HyperU); // num_latent x num_feat

   //--  add beta_precision

   HyperU2 = MvNormal_prec(Lambda, num_feat); // num_latent x num_feat

   #pragma omp parallel for schedule(static)
   for (int f = 0; f < num_feat; f++)
   {
      for (int d = 0; d < num_latent(); d++)
      {
         Ft_y(d, f) += std::sqrt(beta_precision) * HyperU2(d, f);
      }
   }
}

void MacauPrior::addSideInfo(const std::shared_ptr<ISideInfo>& side_info_a, double beta_precision_a, double tolerance_a, bool direct_a, bool enable_beta_precision_sampling_a, bool throw_on_cholesky_error_a)
{
   //FIXME: remove old code

   // old code

   // side information
   Features = side_info_a;
   beta_precision = beta_precision_a;
   tol = tolerance_a;
   use_FtF = direct_a;
   enable_beta_precision_sampling = enable_beta_precision_sampling_a;
   throw_on_cholesky_error = throw_on_cholesky_error_a;

   // new code

   // side information
   side_info_values.push_back(side_info_a);
   beta_precision_values.push_back(beta_precision_a);
   tol_values.push_back(tolerance_a);
   direct_values.push_back(direct_a);
   enable_beta_precision_sampling_values.push_back(enable_beta_precision_sampling_a);
   throw_on_cholesky_error_values.push_back(throw_on_cholesky_error_a);

   // other code

   // Hyper-prior for beta_precision (mean 1.0, var of 1e+3):
   beta_precision_mu0 = 1.0;
   beta_precision_nu0 = 1e-3;
}

bool MacauPrior::save(std::shared_ptr<const StepFile> sf) const
{
   NormalPrior::save(sf);

   std::string path = sf->makeLinkMatrixFileName(m_mode);
   smurff::matrix_io::eigen::write_matrix(path, beta());

   return true;
}

void MacauPrior::restore(std::shared_ptr<const StepFile> sf)
{
   NormalPrior::restore(sf);

   std::string path = sf->getLinkMatrixFileName(m_mode);

   THROWERROR_FILE_NOT_EXIST(path);

   smurff::matrix_io::eigen::read_matrix(path, beta());
}

std::ostream& MacauPrior::info(std::ostream &os, std::string indent)
{
   NormalPrior::info(os, indent);
   os << indent << " SideInfo: ";
   Features->print(os);
   os << indent << " Method: ";
   if (use_FtF)
   {
      os << "Cholesky Decomposition";
      double needs_gb = (double)Features->cols() / 1024. * (double)Features->cols() / 1024. / 1024.;
      if (needs_gb > 1.0) os << " (needing " << needs_gb << " GB of memory)";
      os << std::endl;
   } else {
      os << "CG Solver with tolerance: " << std::scientific << tol << std::fixed << std::endl;
   }
   os << indent << " BetaPrecision: ";
   if (enable_beta_precision_sampling)
   {
       os << "sampled around ";
   }
   else
   {
       os << "fixed at ";
   }
   os << beta_precision << std::endl;
   return os;
}

std::ostream& MacauPrior::status(std::ostream &os, std::string indent) const
{
   os << indent << m_name << ": " << std::endl;
   indent += "  ";
   os << indent << "blockcg iter = " << blockcg_iter << std::endl;
   os << indent << "FtF_plus_precision= " << FtF_plus_precision.norm() << std::endl;
   os << indent << "HyperU       = " << HyperU.norm() << std::endl;
   os << indent << "HyperU2      = " << HyperU2.norm() << std::endl;
   os << indent << "Beta         = " << beta().norm() << std::endl;
   os << indent << "beta_precision  = " << beta_precision << std::endl;
   os << indent << "Ft_y         = " << Ft_y.norm() << std::endl;
   return os;
}

std::pair<double, double> MacauPrior::posterior_beta_precision(Eigen::MatrixXd & beta, Eigen::MatrixXd & Lambda_u, double nu, double mu)
{
   const int D = beta.rows(); // num feat
   Eigen::MatrixXd BB(D, D);
   smurff::linop::A_mul_At_combo(BB, beta);
   double nux = nu + beta.rows() * beta.cols();
   double mux = mu * nux / (nu + mu * (BB.selfadjointView<Eigen::Lower>() * Lambda_u).trace());
   double b = nux / 2;
   double c = 2 * mux / nux;
   return std::make_pair(b, c);
}

double MacauPrior::sample_beta_precision(Eigen::MatrixXd & beta, Eigen::MatrixXd & Lambda_u, double nu, double mu)
{
   auto gamma_post = posterior_beta_precision(beta, Lambda_u, nu, mu);
   return rgamma(gamma_post.first, gamma_post.second);
}
<commit_msg>ENH: beta().cols() -> num_feat()<commit_after>#include "MacauPrior.h"

#include <SmurffCpp/IO/MatrixIO.h>
#include <SmurffCpp/IO/GenericIO.h>

#include <SmurffCpp/Utils/Distribution.h>
#include <SmurffCpp/Utils/Error.h>
#include <SmurffCpp/Utils/counters.h>

#include <SmurffCpp/Utils/linop.h>

#include <ios>

using namespace smurff;

MacauPrior::MacauPrior()
   : NormalPrior()
{
}

MacauPrior::MacauPrior(std::shared_ptr<Session> session, uint32_t mode)
   : NormalPrior(session, mode, "MacauPrior")
{
   beta_precision = SideInfoConfig::BETA_PRECISION_DEFAULT_VALUE;
   tol = SideInfoConfig::TOL_DEFAULT_VALUE;

   enable_beta_precision_sampling = Config::ENABLE_BETA_PRECISION_SAMPLING_DEFAULT_VALUE;
}

MacauPrior::~MacauPrior()
{
}

void MacauPrior::init()
{
   NormalPrior::init();

   THROWERROR_ASSERT_MSG(Features->rows() == num_item(), "Number of rows in train must be equal to number of rows in features");

   if (use_FtF)
   {
      std::uint64_t dim = num_feat();
      FtF_plus_precision.resize(dim, dim);
      Features->At_mul_A(FtF_plus_precision);
      FtF_plus_precision.diagonal().array() += beta_precision;
   }

   Uhat.resize(num_latent(), Features->rows());
   Uhat.setZero();

   m_beta = std::make_shared<Eigen::MatrixXd>(num_latent(), num_feat());
   beta().setZero();

   m_session->model().setLinkMatrix(m_mode, m_beta);
}

void MacauPrior::update_prior()
{
    /*
>> compute_uhat:             0.5012     (12%) in        110
>> main:             4.1396     (100%) in       1
>> rest of update_prior:             0.1684     (4%) in 110
>> sample hyper mu/Lambda:           0.3804     (9%) in 110
>> sample_beta:      1.4927     (36%) in        110
>> sample_latents:           3.8824     (94%) in        220
>> step:             3.9824     (96%) in        111
>> update_prior:             2.5436     (61%) in        110
*/
    COUNTER("update_prior");
    {
        COUNTER("rest of update_prior");
        // residual (Uhat is later overwritten):
        //uses: U, Uhat
        //writes: Uhat
        Udelta = U() - Uhat;
        // BBt = beta * beta'
        //uses: beta
        BBt = smurff::linop::A_mul_At_combo(beta());
    }

    // sampling Gaussian
    {
        // Uses, Udelta
        COUNTER("sample hyper mu/Lambda");
        std::tie(mu, Lambda) = CondNormalWishart(Udelta, mu0, b0,
            WI + beta_precision * BBt, df + num_feat());
    }

    // uses: U, F
    // writes: Ft_y
    compute_Ft_y_omp(Ft_y);

    {
        COUNTER("sample_beta");
        if (use_FtF)
        {
            // uses: FtF, Ft_y,
            // writes: beta
            beta() = FtF_plus_precision.llt().solve(Ft_y.transpose()).transpose();
        }
        else
        {
            // uses: Features, beta_precision, Ft_y,
            // writes: beta
            blockcg_iter = Features->solve_blockcg(beta(), beta_precision, Ft_y, tol, 32, 8, throw_on_cholesky_error);
        }
    }

    {
        COUNTER("compute_uhat");
        // Uhat = beta * F
        // uses: beta, F
        // output: Uhat
        Features->compute_uhat(Uhat, beta());
    }

    if (enable_beta_precision_sampling)
    {
        // uses: beta
        // writes: FtF
        COUNTER("sample_beta_precision");
        double old_beta = beta_precision;
        beta_precision = sample_beta_precision(beta(), Lambda, beta_precision_nu0, beta_precision_mu0);
        FtF_plus_precision.diagonal().array() += beta_precision - old_beta;
   }
}

const Eigen::VectorXd MacauPrior::getMu(int n) const
{
   return mu + Uhat.col(n);
}

void MacauPrior::compute_Ft_y_omp(Eigen::MatrixXd& Ft_y)
{
   //-- input
   // mu, Lambda (small)
   // U
   // F
   //-- output
   // Ft_y
   // Ft_y = (U .- mu + Normal(0, Lambda^-1)) * F + std::sqrt(beta_precision) * Normal(0, Lambda^-1)
   // Ft_y is [ D x F ] matrix

   //HyperU: num_latent x num_item
   HyperU = (U() + MvNormal_prec(Lambda, num_item())).colwise() - mu;
   Ft_y = Features->A_mul_B(HyperU); // num_latent x num_feat

   //--  add beta_precision

   HyperU2 = MvNormal_prec(Lambda, num_feat()); // num_latent x num_feat

   #pragma omp parallel for schedule(static)
   for (int f = 0; f < num_feat(); f++)
   {
      for (int d = 0; d < num_latent(); d++)
      {
         Ft_y(d, f) += std::sqrt(beta_precision) * HyperU2(d, f);
      }
   }
}

void MacauPrior::addSideInfo(const std::shared_ptr<ISideInfo>& side_info_a, double beta_precision_a, double tolerance_a, bool direct_a, bool enable_beta_precision_sampling_a, bool throw_on_cholesky_error_a)
{
   //FIXME: remove old code

   // old code

   // side information
   Features = side_info_a;
   beta_precision = beta_precision_a;
   tol = tolerance_a;
   use_FtF = direct_a;
   enable_beta_precision_sampling = enable_beta_precision_sampling_a;
   throw_on_cholesky_error = throw_on_cholesky_error_a;

   // new code

   // side information
   side_info_values.push_back(side_info_a);
   beta_precision_values.push_back(beta_precision_a);
   tol_values.push_back(tolerance_a);
   direct_values.push_back(direct_a);
   enable_beta_precision_sampling_values.push_back(enable_beta_precision_sampling_a);
   throw_on_cholesky_error_values.push_back(throw_on_cholesky_error_a);

   // other code

   // Hyper-prior for beta_precision (mean 1.0, var of 1e+3):
   beta_precision_mu0 = 1.0;
   beta_precision_nu0 = 1e-3;
}

bool MacauPrior::save(std::shared_ptr<const StepFile> sf) const
{
   NormalPrior::save(sf);

   std::string path = sf->makeLinkMatrixFileName(m_mode);
   smurff::matrix_io::eigen::write_matrix(path, beta());

   return true;
}

void MacauPrior::restore(std::shared_ptr<const StepFile> sf)
{
   NormalPrior::restore(sf);

   std::string path = sf->getLinkMatrixFileName(m_mode);

   THROWERROR_FILE_NOT_EXIST(path);

   smurff::matrix_io::eigen::read_matrix(path, beta());
}

std::ostream& MacauPrior::info(std::ostream &os, std::string indent)
{
   NormalPrior::info(os, indent);
   os << indent << " SideInfo: ";
   Features->print(os);
   os << indent << " Method: ";
   if (use_FtF)
   {
      os << "Cholesky Decomposition";
      double needs_gb = (double)num_feat() / 1024. * (double)num_feat() / 1024. / 1024.;
      if (needs_gb > 1.0) os << " (needing " << needs_gb << " GB of memory)";
      os << std::endl;
   } else {
      os << "CG Solver with tolerance: " << std::scientific << tol << std::fixed << std::endl;
   }
   os << indent << " BetaPrecision: ";
   if (enable_beta_precision_sampling)
   {
       os << "sampled around ";
   }
   else
   {
       os << "fixed at ";
   }
   os << beta_precision << std::endl;
   return os;
}

std::ostream& MacauPrior::status(std::ostream &os, std::string indent) const
{
   os << indent << m_name << ": " << std::endl;
   indent += "  ";
   os << indent << "blockcg iter = " << blockcg_iter << std::endl;
   os << indent << "FtF_plus_precision= " << FtF_plus_precision.norm() << std::endl;
   os << indent << "HyperU       = " << HyperU.norm() << std::endl;
   os << indent << "HyperU2      = " << HyperU2.norm() << std::endl;
   os << indent << "Beta         = " << beta().norm() << std::endl;
   os << indent << "beta_precision  = " << beta_precision << std::endl;
   os << indent << "Ft_y         = " << Ft_y.norm() << std::endl;
   return os;
}

std::pair<double, double> MacauPrior::posterior_beta_precision(Eigen::MatrixXd & beta, Eigen::MatrixXd & Lambda_u, double nu, double mu)
{
   const int D = beta.rows(); // num feat
   Eigen::MatrixXd BB(D, D);
   smurff::linop::A_mul_At_combo(BB, beta);
   double nux = nu + beta.rows() * beta.cols();
   double mux = mu * nux / (nu + mu * (BB.selfadjointView<Eigen::Lower>() * Lambda_u).trace());
   double b = nux / 2;
   double c = 2 * mux / nux;
   return std::make_pair(b, c);
}

double MacauPrior::sample_beta_precision(Eigen::MatrixXd & beta, Eigen::MatrixXd & Lambda_u, double nu, double mu)
{
   auto gamma_post = posterior_beta_precision(beta, Lambda_u, nu, mu);
   return rgamma(gamma_post.first, gamma_post.second);
}
<|endoftext|>