<commit_before>#include "svg2sfml.hpp"

#include <iostream>
#include <fstream>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <string>
#include <set>
#include <exception>

#include <math.h>

#include <boost/cast.hpp>
#include <boost/lexical_cast.hpp>

#include <SFML/Graphics.hpp>

#include "color_table.hpp"
#include <sfml-utilities/sfml-utilities.hpp>
namespace svg2sfml{

static const std::string default_fill_color = "#FFFFFF";
static const std::string default_stroke_color = "#0000FF";

return_t readSVG( const std::string &path ){
    Loader l;
    return l.read( path );
}

sf::Color colorFromSVGColor( const std::string &name ){

	if( name[0] == '#' ){
		int r = stoi( name.substr(1,2), nullptr, 16 );
		int g = stoi( name.substr(3,2), nullptr, 16 );
		int b = stoi( name.substr(5,2), nullptr, 16 );
		return sf::Color( r, g, b, 255 );
	}
	auto iter = color_names.find( name );
	if( iter != color_names.end() ){
		std::cout << name << std::endl;
		return colorFromSVGColor( iter->second );
	}
	std::cout << "Warning: no color found.  defaults to white." << std::endl;
	return sf::Color(255,255,255,255);//TODO throw something
}

void Loader::applyColorAsShape( sf::Shape * shape ){
//color/stroke attributes shared by all shapes
    boost::optional<std::string> fillColorStr;
    boost::optional<std::string> strokeColorStr;
    boost::optional<std::string> thicknessStr;
    for( auto &e : m_tagStack ){
        auto tempFill = e->second.get_optional<std::string>( "<xmlattr>.fill" );
        if( tempFill )
            fillColorStr = std::move( tempFill );
        auto tempStroke = e->second.get_optional<std::string>( "<xmlattr>.stroke" );
        if( tempStroke )
            strokeColorStr = std::move( tempStroke );
        auto tempWidth = e->second.get_optional<std::string>( "<xmlattr>.stroke-width" );
        if( tempWidth )
            thicknessStr = std::move( tempWidth );
    }

    std::cout << "DICK " << fillColorStr.value_or( "SHIT FUCKER" ) << "\n";

    shape->setFillColor( colorFromSVGColor( fillColorStr.value_or( default_fill_color) ) );
    shape->setOutlineColor( colorFromSVGColor( strokeColorStr.value_or( default_stroke_color ) ) );
    shape->setOutlineThickness( boost::lexical_cast<float>( thicknessStr.value_or( "0" ) ) );
}

void Loader::applyColorAsLine( sf::Shape * shape ){
//color/stroke attributes shared by all shapes
	shape->setFillColor( colorFromSVGColor(
			m_tagStack.back()->second.get<std::string>("<xmlattr>.stroke" , default_fill_color) ) );
	shape->setOutlineThickness( 0.0f );
}

std::unique_ptr< sf::Drawable >
	Loader::readAsRect(){
	sf::RectangleShape *newRect = new sf::RectangleShape;
		newRect->setPosition(
			m_tagStack.back()->second.get<float>("<xmlattr>.x"),
			m_tagStack.back()->second.get<float>("<xmlattr>.y") );
		newRect->setSize( sf::Vector2f(
			m_tagStack.back()->second.get<float>("<xmlattr>.width"),
			m_tagStack.back()->second.get<float>("<xmlattr>.height") ) );
		//TODO support rounded rectangles
		//returnShape->setRoundedRectangles(
		//	m_tagStack.back()->second.get<float>("rx"),
		//	m_tagStack.back()->second.get<float>("ry") );
	applyColorAsShape( newRect );
	return std::unique_ptr< sf::Drawable >( newRect );
}

std::unique_ptr< sf::Drawable >
	Loader::readAsCircle(){
	sf::CircleShape * newCirc = new sf::CircleShape;
	newCirc->setPosition(
		m_tagStack.back()->second.get<float>("<xmlattr>.cx"),
		m_tagStack.back()->second.get<float>("<xmlattr>.cy") );
	newCirc->setOrigin(
		m_tagStack.back()->second.get<float>("<xmlattr>.r"),
		m_tagStack.back()->second.get<float>("<xmlattr>.r"));

	newCirc->setRadius(
		m_tagStack.back()->second.get<float>("<xmlattr>.r") );
	applyColorAsShape( newCirc );
	return std::unique_ptr< sf::Drawable >( newCirc );
}

std::unique_ptr< sf::Drawable >rectForLine(
		float x1,
		float y1,
		float x2,
		float y2,
		float width ){
	float length = sqrt( (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2) );
	sf::RectangleShape *newRect = new sf::RectangleShape;
	newRect->setPosition(x1, y1);
	newRect->setSize( sf::Vector2f( length+width, width ) );
	newRect->setOrigin( width/2.0f, width/2.0f );
	newRect->setRotation(
		180.0f/M_PI * sfu::angleOff0( sf::Vector2f( x2-x1, y2-y1 ) ) );
	return std::unique_ptr< sf::Drawable >( newRect );
}

std::unique_ptr< sf::Drawable > Loader::readAsLine(){
	float x1 = m_tagStack.back()->second.get<float>("<xmlattr>.x1");
	float y1 = m_tagStack.back()->second.get<float>("<xmlattr>.y1");
	float x2 = m_tagStack.back()->second.get<float>("<xmlattr>.x2");
	float y2 = m_tagStack.back()->second.get<float>("<xmlattr>.y2");
	float width = m_tagStack.back()->second.get<float>("<xmlattr>.stroke-width");
	auto retRect = rectForLine( x1, y1, x2, y2, width );
    applyColorAsLine( boost::polymorphic_downcast<sf::Shape*>(retRect.get()) );
	return retRect;
}

return_t Loader::readAsPolyline(){
    return_t returnPool;
    std::string points = m_tagStack.back()->second.get<std::string>("<xmlattr>.points");
    float width = m_tagStack.back()->second.get<float>("<xmlattr>.stroke-width");
    std::stringstream dStream( std::move(points) );
	float nX, nY, oX, oY;
    std::string pairString;

    //read first pair
    dStream >> pairString;
    size_t commaPos = pairString.find( "," );
    oX = boost::lexical_cast<float>( pairString.substr(0, commaPos) );
    oY = boost::lexical_cast<float>( pairString.substr(commaPos+1) );

    while( !dStream.eof() ){
        //the polyline path element is formed by pairs of numbers,
        //where each coordinate is separated by a comma, and each
        //pair is separated by a whitespace
		dStream >> pairString;
		size_t commaPos = pairString.find( "," );
        nX = boost::lexical_cast<float>( pairString.substr(0, commaPos) );
        nY = boost::lexical_cast<float>( pairString.substr(commaPos+1) );

        auto lineSegRect = rectForLine( oX, oY, nX, nY, width );
        applyColorAsLine( boost::polymorphic_downcast<sf::Shape*>(lineSegRect.get()) );
        returnPool.push_back( std::move( lineSegRect ) );

        oX = nX;
        oY = nY;
    }
    return returnPool;
}

return_t Loader::readAsPolygon(){
    return_t returnPool;
    std::string points = m_tagStack.back()->second.get<std::string>("<xmlattr>.points");
    std::stringstream dStream( std::move(points) );

    sf::ConvexShape * shape = new sf::ConvexShape;

    std::string pairString;
    float x, y;
    int pCount = 0;
    while( !dStream.eof() ){
        //the polyline path element is formed by pairs of numbers,
        //where each coordinate is separated by a comma, and each
        //pair is separated by a whitespace
        dStream >> pairString;
        size_t commaPos = pairString.find( "," );
        x = boost::lexical_cast<float>( pairString.substr(0, commaPos) );
        y = boost::lexical_cast<float>( pairString.substr(commaPos+1) );

        pCount++;
        shape->setPointCount( pCount );
        shape->setPoint( pCount-1, sf::Vector2f( x, y) );
    }
    applyColorAsShape( shape );

    returnPool.push_back(std::unique_ptr<sf::Drawable>( shape ));

    return std::move( returnPool );
}

return_t Loader::shapesFromSVGTag(){
    assert( !m_tagStack.empty() );
	return_t shapes;
	if( m_tagStack.back()->first == "rect" ){
		shapes.push_back( readAsRect() );
	} else if( m_tagStack.back()->first == "circle" ) {
		shapes.push_back( readAsCircle() );
	} else if( m_tagStack.back()->first == "ellipse" ) {
		//shapes.push_back( readAsEllipse() );
	} else if( m_tagStack.back()->first == "line" ) {
		shapes.push_back( readAsLine() );
	} else if( m_tagStack.back()->first == "polyline" ) {
		shapes = readAsPolyline();
    } else if( m_tagStack.back()->first == "polygon" ) {
        shapes = readAsPolygon();
    }

	return std::move( shapes );
}

return_t Loader::read( const std::string &path ){

	return_t returnVector;

    pt::ptree tree;
    pt::read_xml(path, tree);

    for( auto &e : tree.get_child( "svg" ) )
        recursiveParse( e );

    return std::move( m_drawablePool );
}

void Loader::recursiveParse( pt::ptree::value_type &shapeNode ){
    std::cout << "parsing " << shapeNode.first << "\n";
    if( shapeNode.first == "<xmlattr>" ) //no need to worry about these
        return;
    if( shapeNode.first == "g" ){
        //group node
        //push it onto the stack so it's children can access it
        m_tagStack.push_back( &shapeNode );
        //send it's children through the parser
        for(pt::ptree::value_type &child : shapeNode.second ) {
            recursiveParse( child );
        }
        m_tagStack.pop_back(); // we're done with this group

    } else {
        //maybe some kind of shape node?
        try{

            m_tagStack.push_back( &shapeNode );
            auto shapes = shapesFromSVGTag();
            if( shapes.empty() )
                std::cout << "parsing tag " << shapeNode.first << " didn't produce anything.\n";
            for (auto &shape : shapes) {
                if( shape.get() != nullptr )
                    m_drawablePool.push_back( std::move( shape ) );
            }
            m_tagStack.pop_back();
        } catch( pt::ptree_bad_path e ){
            std::cout << "bad path = " << e.what()<< std::endl;
        }
    }
}

}//end of svg2sfml namespace
<commit_msg>added applyTransformable.<commit_after>#include "svg2sfml.hpp"

#include <iostream>
#include <fstream>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <string>
#include <set>
#include <exception>

#include <math.h>

#include <boost/cast.hpp>
#include <boost/lexical_cast.hpp>

#include <SFML/Graphics.hpp>

#include "color_table.hpp"
#include "shapes.hpp"
#include <sfml-utilities/sfml-utilities.hpp>
namespace svg2sfml{

static const std::string default_fill_color = "#FFFFFF";
static const std::string default_stroke_color = "#0000FF";

return_t readSVG( const std::string &path ){
    Loader l;
    return l.read( path );
}

sf::Color colorFromSVGColor( const std::string &name ){

	if( name[0] == '#' ){
		int r = stoi( name.substr(1,2), nullptr, 16 );
		int g = stoi( name.substr(3,2), nullptr, 16 );
		int b = stoi( name.substr(5,2), nullptr, 16 );
		return sf::Color( r, g, b, 255 );
	}
	auto iter = color_names.find( name );
	if( iter != color_names.end() ){
		std::cout << name << std::endl;
		return colorFromSVGColor( iter->second );
	}
	std::cout << "Warning: no color found.  defaults to white." << std::endl;
	return sf::Color(255,255,255,255);//TODO throw something
}

void Loader::applyColorAsShape( sf::Shape * shape ){
//color/stroke attributes shared by all shapes
    boost::optional<std::string> fillColorStr;
    boost::optional<std::string> strokeColorStr;
    boost::optional<std::string> thicknessStr;
    for( auto &e : m_tagStack ){
        auto tempFill = e->second.get_optional<std::string>( "<xmlattr>.fill" );
        if( tempFill )
            fillColorStr = std::move( tempFill );
        auto tempStroke = e->second.get_optional<std::string>( "<xmlattr>.stroke" );
        if( tempStroke )
            strokeColorStr = std::move( tempStroke );
        auto tempWidth = e->second.get_optional<std::string>( "<xmlattr>.stroke-width" );
        if( tempWidth )
            thicknessStr = std::move( tempWidth );
    }

    std::cout << "DICK " << fillColorStr.value_or( "SHIT FUCKER" ) << "\n";

    shape->setFillColor( colorFromSVGColor( fillColorStr.value_or( default_fill_color) ) );
    shape->setOutlineColor( colorFromSVGColor( strokeColorStr.value_or( default_stroke_color ) ) );
    shape->setOutlineThickness( boost::lexical_cast<float>( thicknessStr.value_or( "0" ) ) );
}

void Loader::applyColorAsLine( sf::Shape * shape ){
//color/stroke attributes shared by all shapes
	shape->setFillColor( colorFromSVGColor(
			m_tagStack.back()->second.get<std::string>("<xmlattr>.stroke" , default_fill_color) ) );
	shape->setOutlineThickness( 0.0f );
}

void Loader::applyTransformable( sf::Shape * shape ){
    for( auto &e : m_tagStack ){
        auto transString = e->second.get_optional<std::string>( "<xmlattr>.transform" );
        if( transString ){
            std::stringstream tStream( transString.value() );
            std::string command;
            while( !tStream.eof() ){
                tStream >> command;
                //find what comes before the (, that's the command
                size_t openParan = command.find( "(" );
                std::string functionName = command.substr( 0, openParan );
                std::string argument = command.substr( openParan+1, command.find( ")" ) );
                if( functionName == "translate" ){
                    //this one has two coords
                    size_t commaPos = argument.find( "," );
                    float x = boost::lexical_cast<float>( argument.substr(0, commaPos) );
                    float y = boost::lexical_cast<float>( argument.substr(commaPos+1) );
                    shape->move( x, y );
                } else if( functionName == "scale"){
                    float s = boost::lexical_cast<float>( argument );
                    shape->scale( s, s );
                } else if( functionName == "rotate"){
                    float r = boost::lexical_cast<float>( argument );
                    shape->rotate( r );
                } else {
                    std::cout << "Don't know what to do with \"" << functionName << "\"\n";
                }
            }
        }
    }
}

std::unique_ptr< sf::Drawable >
	Loader::readAsRect(){
	sf::RectangleShape *newRect = new sf::RectangleShape;
		newRect->setPosition(
			m_tagStack.back()->second.get<float>("<xmlattr>.x"),
			m_tagStack.back()->second.get<float>("<xmlattr>.y") );
		newRect->setSize( sf::Vector2f(
			m_tagStack.back()->second.get<float>("<xmlattr>.width"),
			m_tagStack.back()->second.get<float>("<xmlattr>.height") ) );
		//TODO support rounded rectangles
		//returnShape->setRoundedRectangles(
		//	m_tagStack.back()->second.get<float>("rx"),
		//	m_tagStack.back()->second.get<float>("ry") );
	applyColorAsShape( newRect );
	return std::unique_ptr< sf::Drawable >( newRect );
}

std::unique_ptr< sf::Drawable >
	Loader::readAsCircle(){
        sf::CircleShape * newCirc = new sf::CircleShape;
        newCirc->setPosition(
                             m_tagStack.back()->second.get<float>("<xmlattr>.cx"),
                             m_tagStack.back()->second.get<float>("<xmlattr>.cy") );
        newCirc->setOrigin(
                           m_tagStack.back()->second.get<float>("<xmlattr>.r"),
                           m_tagStack.back()->second.get<float>("<xmlattr>.r"));

        newCirc->setRadius(
                           m_tagStack.back()->second.get<float>("<xmlattr>.r") );
        applyColorAsShape( newCirc );
        return std::unique_ptr< sf::Drawable >( newCirc );
}

std::unique_ptr< sf::Drawable >
    Loader::readAsEllipse(){
    EllipseShape * newEllipse = new EllipseShape;
    newEllipse->setPosition(
                         m_tagStack.back()->second.get<float>("<xmlattr>.cx"),
                         m_tagStack.back()->second.get<float>("<xmlattr>.cy") );
    newEllipse->setPosition(
                       m_tagStack.back()->second.get<float>("<xmlattr>.cx"),
                       m_tagStack.back()->second.get<float>("<xmlattr>.cy"));

    applyColorAsShape( newEllipse );
    return std::unique_ptr< sf::Drawable >( newEllipse );

}

std::unique_ptr< sf::Drawable >rectForLine(
		float x1,
		float y1,
		float x2,
		float y2,
		float width ){
	float length = sqrt( (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2) );
	sf::RectangleShape *newRect = new sf::RectangleShape;
	newRect->setPosition(x1, y1);
	newRect->setSize( sf::Vector2f( length+width, width ) );
	newRect->setOrigin( width/2.0f, width/2.0f );
	newRect->setRotation(
		180.0f/M_PI * sfu::angleOff0( sf::Vector2f( x2-x1, y2-y1 ) ) );
	return std::unique_ptr< sf::Drawable >( newRect );
}

std::unique_ptr< sf::Drawable > Loader::readAsLine(){
	float x1 = m_tagStack.back()->second.get<float>("<xmlattr>.x1");
	float y1 = m_tagStack.back()->second.get<float>("<xmlattr>.y1");
	float x2 = m_tagStack.back()->second.get<float>("<xmlattr>.x2");
	float y2 = m_tagStack.back()->second.get<float>("<xmlattr>.y2");
	float width = m_tagStack.back()->second.get<float>("<xmlattr>.stroke-width");
	auto retRect = rectForLine( x1, y1, x2, y2, width );
    applyColorAsLine( boost::polymorphic_downcast<sf::Shape*>(retRect.get()) );
	return retRect;
}

return_t Loader::readAsPolyline(){
    return_t returnPool;
    std::string points = m_tagStack.back()->second.get<std::string>("<xmlattr>.points");
    float width = m_tagStack.back()->second.get<float>("<xmlattr>.stroke-width");
    std::stringstream dStream( std::move(points) );
	float nX, nY, oX, oY;
    std::string pairString;

    //read first pair
    dStream >> pairString;
    size_t commaPos = pairString.find( "," );
    oX = boost::lexical_cast<float>( pairString.substr(0, commaPos) );
    oY = boost::lexical_cast<float>( pairString.substr(commaPos+1) );

    while( !dStream.eof() ){
        //the polyline path element is formed by pairs of numbers,
        //where each coordinate is separated by a comma, and each
        //pair is separated by a whitespace
		dStream >> pairString;
		size_t commaPos = pairString.find( "," );
        nX = boost::lexical_cast<float>( pairString.substr(0, commaPos) );
        nY = boost::lexical_cast<float>( pairString.substr(commaPos+1) );

        auto lineSegRect = rectForLine( oX, oY, nX, nY, width );
        applyColorAsLine( boost::polymorphic_downcast<sf::Shape*>(lineSegRect.get()) );
        returnPool.push_back( std::move( lineSegRect ) );

        oX = nX;
        oY = nY;
    }
    return returnPool;
}

return_t Loader::readAsPolygon(){
    return_t returnPool;
    std::string points = m_tagStack.back()->second.get<std::string>("<xmlattr>.points");
    std::stringstream dStream( std::move(points) );

    sf::ConvexShape * shape = new sf::ConvexShape;

    std::string pairString;
    float x, y;
    int pCount = 0;
    while( !dStream.eof() ){
        //the polyline path element is formed by pairs of numbers,
        //where each coordinate is separated by a comma, and each
        //pair is separated by a whitespace
        dStream >> pairString;
        size_t commaPos = pairString.find( "," );
        x = boost::lexical_cast<float>( pairString.substr(0, commaPos) );
        y = boost::lexical_cast<float>( pairString.substr(commaPos+1) );

        pCount++;
        shape->setPointCount( pCount );
        shape->setPoint( pCount-1, sf::Vector2f( x, y) );
    }
    applyColorAsShape( shape );

    returnPool.push_back(std::unique_ptr<sf::Drawable>( shape ));

    return std::move( returnPool );
}

return_t Loader::shapesFromSVGTag(){
    assert( !m_tagStack.empty() );
	return_t shapes;
	if( m_tagStack.back()->first == "rect" ){
		shapes.push_back( readAsRect() );
	} else if( m_tagStack.back()->first == "circle" ) {
		shapes.push_back( readAsCircle() );
	} else if( m_tagStack.back()->first == "ellipse" ) {
		shapes.push_back( readAsEllipse() );
	} else if( m_tagStack.back()->first == "line" ) {
		shapes.push_back( readAsLine() );
	} else if( m_tagStack.back()->first == "polyline" ) {
		shapes = readAsPolyline();
    } else if( m_tagStack.back()->first == "polygon" ) {
        shapes = readAsPolygon();
    }

	return std::move( shapes );
}

return_t Loader::read( const std::string &path ){

	return_t returnVector;

    pt::ptree tree;
    pt::read_xml(path, tree);

    for( auto &e : tree.get_child( "svg" ) )
        recursiveParse( e );

    return std::move( m_drawablePool );
}

void Loader::recursiveParse( pt::ptree::value_type &shapeNode ){
    std::cout << "parsing " << shapeNode.first << "\n";
    if( shapeNode.first == "<xmlattr>" ) //no need to worry about these
        return;
    if( shapeNode.first == "g" ){
        //group node
        //push it onto the stack so it's children can access it
        m_tagStack.push_back( &shapeNode );
        //send it's children through the parser
        for(pt::ptree::value_type &child : shapeNode.second ) {
            recursiveParse( child );
        }
        m_tagStack.pop_back(); // we're done with this group

    } else {
        //maybe some kind of shape node?
        try{

            m_tagStack.push_back( &shapeNode );
            auto shapes = shapesFromSVGTag();
            if( shapes.empty() )
                std::cout << "parsing tag " << shapeNode.first << " didn't produce anything.\n";
            for (auto &shape : shapes) {
                if( shape.get() != nullptr )
                    m_drawablePool.push_back( std::move( shape ) );
            }
            m_tagStack.pop_back();
        } catch( pt::ptree_bad_path e ){
            std::cout << "bad path = " << e.what()<< std::endl;
        }
    }
}

}//end of svg2sfml namespace
<|endoftext|>


<commit_before>/*
  Copyright (C) 2005-2020 Steven L. Scott

  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., 51
  Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/

#include "Models/Impute/MvRegCopulaDataImputer.hpp"
#include "Models/PosteriorSamplers/MultinomialDirichletSampler.hpp"
#include "distributions.hpp"

namespace BOOM {

  namespace {
    using CICM = ConditionallyIndependentCategoryModel;
  }  // namespace
  //===========================================================================
  namespace Imputer {
    CompleteData::CompleteData(const Ptr<MvRegData> &observed)
        : observed_data_(observed),
          y_true_(observed->y()),
          y_numeric_(observed->y())
    {}

    CompleteData *CompleteData::clone() const {
      return new CompleteData(*this);
    }

    std::ostream &CompleteData::display(std::ostream &out) const {
      out << *observed_data_ << "\n"
          << "true: " << y_true_ << "\n"
          << "numeric: " << y_numeric_ << std::endl;
      return out;
    }

  }  // namespace Imputer
  //===========================================================================
  ErrorCorrectionModel::ErrorCorrectionModel(const Vector &atoms)
      : atoms_(atoms),
        marginal_of_true_data_(new MultinomialModel(atoms.size() + 1)),
        joint_distribution_(atoms.size() + 1, atoms.size() + 2),
        observed_log_probability_table_(atoms.size() + 2),
        workspace_is_current_(false)
  {
    marginal_of_true_data_->Pi_prm()->add_observer(
        [this]() {
          this->workspace_is_current_ = false;
        });

    for (int i = 0; i <= atoms.size(); ++i) {
      NEW(MultinomialModel, conditional_model)(atoms.size() + 2);
      conditional_model->Pi_prm()->add_observer(
          [this]() {
            this->workspace_is_current_ = false;
          });
      conditional_observed_given_true_.push_back(conditional_model);
    }
  }

  ErrorCorrectionModel *ErrorCorrectionModel::clone() const {
    return new ErrorCorrectionModel(*this);
  }

  double ErrorCorrectionModel::logp(double y) const {
    ensure_workspace_current();
    return observed_log_probability_table_[category_map(y)];
  }

  int ErrorCorrectionModel::category_map(double y) const {
    if (std::isnan(y)) {
      return observed_log_probability_table_.size() - 1;
    } else {
      for (int i = 0; i < atoms_.size(); ++i) {
        if (fabs(y - atoms_[i]) < 1e-6) {
          return i;
        }
      }
    }
    return observed_log_probability_table_.size() - 2;
  }

  void ErrorCorrectionModel::ensure_workspace_current() const {
    if (workspace_is_current_) {
      return;
    }

    int true_dim = atoms_.size() + 1;
    int obs_dim = true_dim + 1;
    for (int truth = 0; truth < true_dim; ++truth) {
      for (int obs = 0; obs < obs_dim; ++obs) {
        joint_distribution_(truth, obs) =
            marginal_of_true_data_->pi(truth)
            * conditional_observed_given_true_[truth]->pi(obs);
      }
    }
    observed_log_probability_table_ = log(joint_distribution_.col_sums());
    workspace_is_current_ = true;
  }

  void ErrorCorrectionModel::set_conjugate_prior_for_true_categories(
      const Vector &prior_counts) {
    marginal_of_true_data_->clear_methods();
    NEW(ConstrainedMultinomialDirichletSampler, sampler)(
        marginal_of_true_data_.get(), prior_counts);
    marginal_of_true_data_->set_method(sampler);
  }

  void ErrorCorrectionModel::set_conjugate_prior_for_observation_categories(
      const Matrix &prior_counts) {
    for (int i = 0; i < conditional_observed_given_true_.size(); ++i) {
      conditional_observed_given_true_[i]->clear_methods();
      NEW(ConstrainedMultinomialDirichletSampler, sampler)(
          conditional_observed_given_true_[i].get(),
          prior_counts.row(i));
      conditional_observed_given_true_[i]->set_method(sampler);
    }
  }

  void ErrorCorrectionModel::sample_posterior() {
    marginal_of_true_data_->sample_posterior();
    for (size_t i = 0; i < conditional_observed_given_true_.size(); ++i) {
      conditional_observed_given_true_[i]->sample_posterior();
    }
  }

  double ErrorCorrectionModel::logpri() const {
    double ans = marginal_of_true_data_->logpri();
    for (const auto &el : conditional_observed_given_true_) {
      ans += el->logpri();
    }
    return ans;
  }

  void ErrorCorrectionModel::clear_data() {
    marginal_of_true_data_->clear_data();
    for (int i = 0; i < conditional_observed_given_true_.size(); ++i) {
      conditional_observed_given_true_[i]->clear_data();
    }
  }

  int ErrorCorrectionModel::impute_atom(double observed, RNG &rng,
                                         bool update) {
    ensure_workspace_current();
    int observed_atom = category_map(observed);
    wsp_ = joint_distribution_.col(observed_atom);
    wsp_.normalize_prob();
    int true_atom = rmulti_mt(rng, wsp_);
    if (update) {
      marginal_of_true_data_->suf()->update_raw(true_atom);
      conditional_observed_given_true_[true_atom]->suf()->update_raw(observed_atom);
    }
    return true_atom;
  }

  double ErrorCorrectionModel::true_value(int true_atom,
                                          double observed_value) const {
    if (true_atom < atoms_.size()) {
      return atoms_[true_atom];
    } else {
      return observed_value;
    }
  }

  double ErrorCorrectionModel::numeric_value(int true_atom,
                                             double observed_value) const {
    if (true_atom == atoms_.size()) {
      return observed_value;
    } else {
      return std::numeric_limits<double>::quiet_NaN();
    }
  }

  //===========================================================================
  CICM::ConditionallyIndependentCategoryModel(const std::vector<Vector> &atoms)
  {
    for (int i = 0; i < atoms.size(); ++i) {
      NEW(ErrorCorrectionModel, model)(atoms[i]);
      observed_data_models_.push_back(model);
    }
  }

  double CICM::logp(const Vector &observed) const {
    double ans = 0;
    for (int i = 0; i < observed.size(); ++i) {
      ans += observed_data_models_[i]->logp(observed[i]);
    }
    return ans;
  }

  void CICM::clear_data() {
    DataPolicy::clear_data();
    for (size_t i = 0; i < observed_data_models_.size(); ++i) {
      observed_data_models_[i]->clear_data();
    }
  }

  void CICM::impute_atoms(Imputer::CompleteData &data, RNG &rng,
                          bool update_complete_data_suf) {
    const Vector &observed(data.y_observed());
    for (int i = 0; i < observed.size(); ++i) {
      // True atom is the atom responsible for the true value.
      int true_atom = observed_data_models_[i]->impute_atom(
          observed[i], rng, update_complete_data_suf);

      data.set_y_true(i, observed_data_models_[i]->true_value(
          true_atom, observed[i]));
      data.set_y_numeric(i, observed_data_models_[i]->numeric_value(
          true_atom, observed[i]));
    }
  }

  //===========================================================================
  MvRegCopulaDataImputer::MvRegCopulaDataImputer(
      int num_clusters, const std::vector<Vector> &atoms, int xdim, RNG &seeding_rng)
      : cluster_mixing_distribution_(new MultinomialModel(num_clusters)),
        complete_data_model_(new MultivariateRegressionModel(xdim, atoms.size())),
        rng_(seed_rng(seeding_rng)),
        swept_sigma_(SpdMatrix(0))
  {
    for (int s = 0; s < num_clusters; ++s) {
      NEW(ConditionallyIndependentCategoryModel, component)(atoms);
      cluster_mixture_components_.push_back(component);
    }
  }

  void MvRegCopulaDataImputer::initialize_empirical_distributions(int ydim) {
    Vector probs(99);
    for (int i = 0; i < probs.size(); ++i) {
      probs[i] = (i + 1.0) / 100.0;
    }
    for (int i = 0; i < ydim; ++i) {
      empirical_distributions_.push_back(IQagent(probs, uint(1e+6)));
    }
  }

  //---------------------------------------------------------------------------
  MvRegCopulaDataImputer *MvRegCopulaDataImputer::clone() const {
    return new MvRegCopulaDataImputer(*this);
  }

  //---------------------------------------------------------------------------
  void MvRegCopulaDataImputer::clear_data() {
    DataPolicy::clear_data();
    complete_data_.clear();
    clear_client_data();
  }
  //---------------------------------------------------------------------------
  void MvRegCopulaDataImputer::clear_client_data() {
    cluster_mixing_distribution_->clear_data();
    for (size_t s = 0; s < cluster_mixture_components_.size(); ++s) {
      cluster_mixture_components_[s]->clear_data();
    }
    complete_data_model_->clear_data();
  }
  //---------------------------------------------------------------------------
  void MvRegCopulaDataImputer::add_data(const Ptr<MvRegData> &data) {
    NEW(Imputer::CompleteData, complete)(data);
    DataPolicy::add_data(data);

    if (empirical_distributions_.empty()) {
      initialize_empirical_distributions(data->y().size());
    }

    const Vector &y(data->y());
    for (size_t i = 0; i < y.size(); ++i) {
      const auto &model = cluster_mixture_components_[0]->model(i);
      int atom = model.category_map(y[i]);
      if (atom == model.number_of_atoms()) {
        empirical_distributions_[i].add(y[i]);
      }
    }

    complete_data_.push_back(complete);
  }
  //---------------------------------------------------------------------------
  void MvRegCopulaDataImputer::remove_data(const Ptr<Data> &data) {
    DataPolicy::remove_data(data);
    for (auto it = complete_data_.begin(); it != complete_data_.end(); ++it) {
      const Ptr<Imputer::CompleteData> &data_point(*it);
      if (data_point->observed_data() == data.get()) {
        complete_data_.erase(it);
      }
    }
  }
  //---------------------------------------------------------------------------
  double MvRegCopulaDataImputer::logpri() const {
    return negative_infinity();
  }

  //---------------------------------------------------------------------------
  int MvRegCopulaDataImputer::impute_cluster(
      Ptr<Imputer::CompleteData> &data, RNG &rng) const {
    int S = cluster_mixture_components_.size();
    wsp_ = cluster_mixing_distribution_->logpi();
    for (uint s = 0; s < S; ++s) {
      wsp_[s] += cluster_mixture_components_[s]->logp(data->y_observed());
    }
    wsp_.normalize_logprob();
    int component = rmulti_mt(rng, wsp_);
    return component;
  }
  //---------------------------------------------------------------------------
  int MvRegCopulaDataImputer::impute_cluster(
      Ptr<Imputer::CompleteData> &data,
      RNG &rng,
      bool update_complete_data_suf) {

    int component = impute_cluster(data, rng);
    if (update_complete_data_suf) {
      cluster_mixing_distribution_->suf()->update_raw(component);
    }
    return component;
  }

  //---------------------------------------------------------------------------
  void MvRegCopulaDataImputer::impute_row(Ptr<Imputer::CompleteData> &data,
                                          RNG &rng,
                                          bool update_complete_data_suf) {
    int component = impute_cluster(data, rng, update_complete_data_suf);
    cluster_mixture_components_[component]->impute_atoms(
        *data, rng, update_complete_data_suf);

    Vector numeric = data->y_numeric();
    Selector observed(numeric.size(), true);
    for (int i = 0; i < numeric.size(); ++i) {
      if (std::isnan(numeric[i])) {
        observed.drop(i);
      } else {
        numeric[i] = qnorm(empirical_distributions_[i].cdf(numeric[i]));
      }
    }

    if (observed.nvars() < observed.nvars_possible()) {
      Vector mean = complete_data_model_->predict(data->x());
      Vector imputed_numeric;
      if (observed.nvars() == 0) {
        imputed_numeric = rmvn_mt(rng, mean, complete_data_model_->Sigma());
      } else {
        swept_sigma_.SWP(observed);
        Vector conditional_mean = swept_sigma_.conditional_mean(
            observed.select(numeric), mean);
        Vector imputed_values = rmvn_mt(rng, conditional_mean, swept_sigma_.residual_variance());

        observed.fill_missing_elements(numeric, imputed_values);

        // TODO: update the empirical CDF.

        // transform back.
        for (int i = 0; i < numeric.size(); ++i) {
          if (observed[i]) {
            numeric[i] = data->y_observed()[i];
          } else {
            numeric[i] = empirical_distributions_[i].quantile(pnorm(numeric[i]));
          }
        }
        data->set_y_numeric(numeric);
      }
    }
  }

  //---------------------------------------------------------------------------
  void MvRegCopulaDataImputer::sample_posterior() {
    for (int i = 0; i < empirical_distributions_.size(); ++i) {
      empirical_distributions_[i].update_cdf();
    }
    clear_client_data();
    swept_sigma_ = SweptVarianceMatrix(complete_data_model_->Sigma());
    for (int i = 0; i < complete_data_.size(); ++i) {
      impute_row(complete_data_[i], rng_, true);
    }
    cluster_mixing_distribution_->sample_posterior();
    for (int s = 0; s < cluster_mixture_components_.size(); ++s) {
      cluster_mixture_components_[s]->sample_posterior();
    }
    complete_data_model_->sample_posterior();
  }

}  // namespace BOOMx
<commit_msg>Add a comment.<commit_after>/*
  Copyright (C) 2005-2020 Steven L. Scott

  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., 51
  Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/

#include "Models/Impute/MvRegCopulaDataImputer.hpp"
#include "Models/PosteriorSamplers/MultinomialDirichletSampler.hpp"
#include "distributions.hpp"

namespace BOOM {

  namespace {
    using CICM = ConditionallyIndependentCategoryModel;
  }  // namespace
  //===========================================================================
  namespace Imputer {
    CompleteData::CompleteData(const Ptr<MvRegData> &observed)
        : observed_data_(observed),
          y_true_(observed->y()),
          y_numeric_(observed->y())
    {}

    CompleteData *CompleteData::clone() const {
      return new CompleteData(*this);
    }

    std::ostream &CompleteData::display(std::ostream &out) const {
      out << *observed_data_ << "\n"
          << "true: " << y_true_ << "\n"
          << "numeric: " << y_numeric_ << std::endl;
      return out;
    }

  }  // namespace Imputer
  //===========================================================================
  ErrorCorrectionModel::ErrorCorrectionModel(const Vector &atoms)
      : atoms_(atoms),
        marginal_of_true_data_(new MultinomialModel(atoms.size() + 1)),
        joint_distribution_(atoms.size() + 1, atoms.size() + 2),
        observed_log_probability_table_(atoms.size() + 2),
        workspace_is_current_(false)
  {
    marginal_of_true_data_->Pi_prm()->add_observer(
        [this]() {
          this->workspace_is_current_ = false;
        });

    for (int i = 0; i <= atoms.size(); ++i) {
      NEW(MultinomialModel, conditional_model)(atoms.size() + 2);
      conditional_model->Pi_prm()->add_observer(
          [this]() {
            this->workspace_is_current_ = false;
          });
      conditional_observed_given_true_.push_back(conditional_model);
    }
  }

  ErrorCorrectionModel *ErrorCorrectionModel::clone() const {
    return new ErrorCorrectionModel(*this);
  }

  double ErrorCorrectionModel::logp(double y) const {
    ensure_workspace_current();
    return observed_log_probability_table_[category_map(y)];
  }

  // If there are 3 atoms, this function returns 0, 1, or 2 if y is one of the
  // atomic values.  Otherwise it returns 3 if y is not NaN, and 4 if it is NaN.
  int ErrorCorrectionModel::category_map(double y) const {
    if (std::isnan(y)) {
      return observed_log_probability_table_.size() - 1;
    } else {
      for (int i = 0; i < atoms_.size(); ++i) {
        if (fabs(y - atoms_[i]) < 1e-6) {
          return i;
        }
      }
    }
    return observed_log_probability_table_.size() - 2;
  }

  void ErrorCorrectionModel::ensure_workspace_current() const {
    if (workspace_is_current_) {
      return;
    }

    int true_dim = atoms_.size() + 1;
    int obs_dim = true_dim + 1;
    for (int truth = 0; truth < true_dim; ++truth) {
      for (int obs = 0; obs < obs_dim; ++obs) {
        joint_distribution_(truth, obs) =
            marginal_of_true_data_->pi(truth)
            * conditional_observed_given_true_[truth]->pi(obs);
      }
    }
    observed_log_probability_table_ = log(joint_distribution_.col_sums());
    workspace_is_current_ = true;
  }

  void ErrorCorrectionModel::set_conjugate_prior_for_true_categories(
      const Vector &prior_counts) {
    marginal_of_true_data_->clear_methods();
    NEW(ConstrainedMultinomialDirichletSampler, sampler)(
        marginal_of_true_data_.get(), prior_counts);
    marginal_of_true_data_->set_method(sampler);
  }

  void ErrorCorrectionModel::set_conjugate_prior_for_observation_categories(
      const Matrix &prior_counts) {
    for (int i = 0; i < conditional_observed_given_true_.size(); ++i) {
      conditional_observed_given_true_[i]->clear_methods();
      NEW(ConstrainedMultinomialDirichletSampler, sampler)(
          conditional_observed_given_true_[i].get(),
          prior_counts.row(i));
      conditional_observed_given_true_[i]->set_method(sampler);
    }
  }

  void ErrorCorrectionModel::sample_posterior() {
    marginal_of_true_data_->sample_posterior();
    for (size_t i = 0; i < conditional_observed_given_true_.size(); ++i) {
      conditional_observed_given_true_[i]->sample_posterior();
    }
  }

  double ErrorCorrectionModel::logpri() const {
    double ans = marginal_of_true_data_->logpri();
    for (const auto &el : conditional_observed_given_true_) {
      ans += el->logpri();
    }
    return ans;
  }

  void ErrorCorrectionModel::clear_data() {
    marginal_of_true_data_->clear_data();
    for (int i = 0; i < conditional_observed_given_true_.size(); ++i) {
      conditional_observed_given_true_[i]->clear_data();
    }
  }

  int ErrorCorrectionModel::impute_atom(double observed, RNG &rng,
                                         bool update) {
    ensure_workspace_current();
    int observed_atom = category_map(observed);
    wsp_ = joint_distribution_.col(observed_atom);
    wsp_.normalize_prob();
    int true_atom = rmulti_mt(rng, wsp_);
    if (update) {
      marginal_of_true_data_->suf()->update_raw(true_atom);
      conditional_observed_given_true_[true_atom]->suf()->update_raw(observed_atom);
    }
    return true_atom;
  }

  double ErrorCorrectionModel::true_value(int true_atom,
                                          double observed_value) const {
    if (true_atom < atoms_.size()) {
      return atoms_[true_atom];
    } else {
      return observed_value;
    }
  }

  double ErrorCorrectionModel::numeric_value(int true_atom,
                                             double observed_value) const {
    if (true_atom == atoms_.size()) {
      return observed_value;
    } else {
      return std::numeric_limits<double>::quiet_NaN();
    }
  }

  //===========================================================================
  CICM::ConditionallyIndependentCategoryModel(const std::vector<Vector> &atoms)
  {
    for (int i = 0; i < atoms.size(); ++i) {
      NEW(ErrorCorrectionModel, model)(atoms[i]);
      observed_data_models_.push_back(model);
    }
  }

  double CICM::logp(const Vector &observed) const {
    double ans = 0;
    for (int i = 0; i < observed.size(); ++i) {
      ans += observed_data_models_[i]->logp(observed[i]);
    }
    return ans;
  }

  void CICM::clear_data() {
    DataPolicy::clear_data();
    for (size_t i = 0; i < observed_data_models_.size(); ++i) {
      observed_data_models_[i]->clear_data();
    }
  }

  void CICM::impute_atoms(Imputer::CompleteData &data, RNG &rng,
                          bool update_complete_data_suf) {
    const Vector &observed(data.y_observed());
    for (int i = 0; i < observed.size(); ++i) {
      // True atom is the atom responsible for the true value.
      int true_atom = observed_data_models_[i]->impute_atom(
          observed[i], rng, update_complete_data_suf);

      data.set_y_true(i, observed_data_models_[i]->true_value(
          true_atom, observed[i]));
      data.set_y_numeric(i, observed_data_models_[i]->numeric_value(
          true_atom, observed[i]));
    }
  }

  //===========================================================================
  MvRegCopulaDataImputer::MvRegCopulaDataImputer(
      int num_clusters, const std::vector<Vector> &atoms, int xdim, RNG &seeding_rng)
      : cluster_mixing_distribution_(new MultinomialModel(num_clusters)),
        complete_data_model_(new MultivariateRegressionModel(xdim, atoms.size())),
        rng_(seed_rng(seeding_rng)),
        swept_sigma_(SpdMatrix(0))
  {
    for (int s = 0; s < num_clusters; ++s) {
      NEW(ConditionallyIndependentCategoryModel, component)(atoms);
      cluster_mixture_components_.push_back(component);
    }
  }

  void MvRegCopulaDataImputer::initialize_empirical_distributions(int ydim) {
    Vector probs(99);
    for (int i = 0; i < probs.size(); ++i) {
      probs[i] = (i + 1.0) / 100.0;
    }
    for (int i = 0; i < ydim; ++i) {
      empirical_distributions_.push_back(IQagent(probs, uint(1e+6)));
    }
  }

  //---------------------------------------------------------------------------
  MvRegCopulaDataImputer *MvRegCopulaDataImputer::clone() const {
    return new MvRegCopulaDataImputer(*this);
  }

  //---------------------------------------------------------------------------
  void MvRegCopulaDataImputer::clear_data() {
    DataPolicy::clear_data();
    complete_data_.clear();
    clear_client_data();
  }
  //---------------------------------------------------------------------------
  void MvRegCopulaDataImputer::clear_client_data() {
    cluster_mixing_distribution_->clear_data();
    for (size_t s = 0; s < cluster_mixture_components_.size(); ++s) {
      cluster_mixture_components_[s]->clear_data();
    }
    complete_data_model_->clear_data();
  }
  //---------------------------------------------------------------------------
  void MvRegCopulaDataImputer::add_data(const Ptr<MvRegData> &data) {
    NEW(Imputer::CompleteData, complete)(data);
    DataPolicy::add_data(data);

    if (empirical_distributions_.empty()) {
      initialize_empirical_distributions(data->y().size());
    }

    const Vector &y(data->y());
    for (size_t i = 0; i < y.size(); ++i) {
      const auto &model = cluster_mixture_components_[0]->model(i);
      int atom = model.category_map(y[i]);
      if (atom == model.number_of_atoms()) {
        empirical_distributions_[i].add(y[i]);
      }
    }

    complete_data_.push_back(complete);
  }
  //---------------------------------------------------------------------------
  void MvRegCopulaDataImputer::remove_data(const Ptr<Data> &data) {
    DataPolicy::remove_data(data);
    for (auto it = complete_data_.begin(); it != complete_data_.end(); ++it) {
      const Ptr<Imputer::CompleteData> &data_point(*it);
      if (data_point->observed_data() == data.get()) {
        complete_data_.erase(it);
      }
    }
  }
  //---------------------------------------------------------------------------
  double MvRegCopulaDataImputer::logpri() const {
    return negative_infinity();
  }

  //---------------------------------------------------------------------------
  int MvRegCopulaDataImputer::impute_cluster(
      Ptr<Imputer::CompleteData> &data, RNG &rng) const {
    int S = cluster_mixture_components_.size();
    wsp_ = cluster_mixing_distribution_->logpi();
    for (uint s = 0; s < S; ++s) {
      wsp_[s] += cluster_mixture_components_[s]->logp(data->y_observed());
    }
    wsp_.normalize_logprob();
    int component = rmulti_mt(rng, wsp_);
    return component;
  }
  //---------------------------------------------------------------------------
  int MvRegCopulaDataImputer::impute_cluster(
      Ptr<Imputer::CompleteData> &data,
      RNG &rng,
      bool update_complete_data_suf) {

    int component = impute_cluster(data, rng);
    if (update_complete_data_suf) {
      cluster_mixing_distribution_->suf()->update_raw(component);
    }
    return component;
  }

  //---------------------------------------------------------------------------
  void MvRegCopulaDataImputer::impute_row(Ptr<Imputer::CompleteData> &data,
                                          RNG &rng,
                                          bool update_complete_data_suf) {
    int component = impute_cluster(data, rng, update_complete_data_suf);
    cluster_mixture_components_[component]->impute_atoms(
        *data, rng, update_complete_data_suf);

    Vector numeric = data->y_numeric();
    Selector observed(numeric.size(), true);
    for (int i = 0; i < numeric.size(); ++i) {
      if (std::isnan(numeric[i])) {
        observed.drop(i);
      } else {
        numeric[i] = qnorm(empirical_distributions_[i].cdf(numeric[i]));
      }
    }

    if (observed.nvars() < observed.nvars_possible()) {
      Vector mean = complete_data_model_->predict(data->x());
      Vector imputed_numeric;
      if (observed.nvars() == 0) {
        imputed_numeric = rmvn_mt(rng, mean, complete_data_model_->Sigma());
      } else {
        swept_sigma_.SWP(observed);
        Vector conditional_mean = swept_sigma_.conditional_mean(
            observed.select(numeric), mean);
        Vector imputed_values = rmvn_mt(rng, conditional_mean, swept_sigma_.residual_variance());

        observed.fill_missing_elements(numeric, imputed_values);

        // TODO: update the empirical CDF.

        // transform back.
        for (int i = 0; i < numeric.size(); ++i) {
          if (observed[i]) {
            numeric[i] = data->y_observed()[i];
          } else {
            numeric[i] = empirical_distributions_[i].quantile(pnorm(numeric[i]));
          }
        }
        data->set_y_numeric(numeric);
      }
    }
  }

  //---------------------------------------------------------------------------
  void MvRegCopulaDataImputer::sample_posterior() {
    for (int i = 0; i < empirical_distributions_.size(); ++i) {
      empirical_distributions_[i].update_cdf();
    }
    clear_client_data();
    swept_sigma_ = SweptVarianceMatrix(complete_data_model_->Sigma());
    for (int i = 0; i < complete_data_.size(); ++i) {
      impute_row(complete_data_[i], rng_, true);
    }
    cluster_mixing_distribution_->sample_posterior();
    for (int s = 0; s < cluster_mixture_components_.size(); ++s) {
      cluster_mixture_components_[s]->sample_posterior();
    }
    complete_data_model_->sample_posterior();
  }

}  // namespace BOOMx
<|endoftext|>


<commit_before>#include "geysa.h"
#include "ast.h"
#include "if1.h"
#include "fa.h"
#include "builtin.h"

char *type_kind_string[] = {
  "NONE", "UNKNOWN", "LUB", "GLB", "PRODUCT", "RECORD", "VECTOR",
  "FUN", "REF", "TAGGED", "PRIMITIVE", "APPLICATION", "VARIABLE", "ALIAS"};

BasicSym::BasicSym(void) :
  name(NULL),
  in(NULL),
  type(NULL),
  aspect(NULL),
  must_specialize(NULL),
  must_implement(NULL),
  ast(NULL),
  var(NULL),
  asymbol(NULL),
  nesting_depth(0),
  cg_string(NULL),
  is_builtin(0),
  is_read_only(0),
  is_constant(0),
  is_lvalue(0),
  is_var(0),
  is_default_arg(0),
  is_exact_match(0),
  is_module(0),
  is_fun(0),
  is_symbol(0),
  is_pattern(0),
  is_rest(0),
  is_generic(0),
  is_external(0),
  intent(0),
  global_scope(0),
  function_scope(0),
  is_structure(0),
  is_meta_type(0),
  is_value_class(0),
  is_union_class(0),
  fun_returns_value(0),
  live(0),
  incomplete(0),
  type_kind(0),
  num_kind(0),
  num_index(0),
  clone_for_constants(0)
{}

Sym *
meta_apply(Sym *fn, Sym *arg) {
  if (fn->type_kind != Type_APPLICATION)
    return 0;
  assert(0);
  return 0;
}

Sym::Sym() :
  destruct_name(NULL),
  arg_name(NULL),
  constant(NULL),
  size(0),
  scope(NULL),
  labelmap(NULL),
  fun(NULL),
  code(NULL),
  self(NULL),
  ret(NULL),
  cont(NULL),
  instantiates(NULL),
  match_type(NULL),
  abstract_type(NULL),
  alias(NULL),
  init(NULL),
  meta_type(NULL),
  element(NULL),
  domain(NULL),
  temp(NULL)
{}

char *
Sym::pathname() {
  char *p = 0;
  if (asymbol)
    p = asymbol->pathname();
  if (!p && ast)
    p = ast->pathname();
  if (p)
    return p;
  return "<unknown>";
}

char *
Sym::filename() {
  char *fn = pathname();
  char *r = strrchr(fn, '/');
  if (r) return r+1; else return fn;
}

int
Sym::line() {
  int l = 0;
  if (asymbol)
    l = asymbol->line();
  if (!l && ast)
    l = ast->line();
  return l;
}

int
Sym::ast_id() {
  if (asymbol)
    return asymbol->ast_id();
  return id;
}

int
Sym::log_line() {
  if (asymbol)
    return asymbol->log_line();
  if (strstr(filename(), "prelude"))
    return 0;
  return line();
}

void
Sym::copy_values(Sym *s) {
  int temp_id = id;
  *this = *s;
  id = temp_id;
}

Sym *
Sym::clone() {
  if (asymbol)
    return asymbol->clone();
  Sym *new_sym = copy();
  return new_sym;
}

Sym *
Sym::copy() {
  Sym *s = new_Sym();
  s->copy_values(this);
  return s;
}

int
compar_syms(const void *ai, const void *aj) {
  uint32 i = (*(Sym**)ai)->id;
  uint32 j = (*(Sym**)aj)->id;
  return (i > j) ? 1 : ((i < j) ? -1 : 0);
}

int
Sym::imm_int(int *result) {
  int i = 0;
  switch (type->num_kind) {
    default: return -1;
    case IF1_NUM_KIND_UINT: {
      switch (type->num_index) {
        case IF1_INT_TYPE_8: i = imm.v_uint8; break;
        case IF1_INT_TYPE_16: i = imm.v_uint16; break;
        case IF1_INT_TYPE_32: i = imm.v_uint32; break;
        case IF1_INT_TYPE_64: i = imm.v_uint64; break;
        default: return -1;
      }
      break;
    }
    case IF1_NUM_KIND_INT: {
      switch (type->num_index) {
        case IF1_INT_TYPE_8: i = imm.v_int8; break;
        case IF1_INT_TYPE_16: i = imm.v_int16; break;
        case IF1_INT_TYPE_32: i = imm.v_int32; break;
        case IF1_INT_TYPE_64: i = imm.v_int64; break;
        default: return -1;
      }
      break;
    }
  }
  *result = i;
  return 0;
}

Sym *
unalias_type(Sym *s) {
  if (!s)
    return s;
  if (s->type_kind == Type_ALIAS) {
    Vec<Sym *> aliases;
    do {
      if (!s->alias)
        return 0;
      Sym *ss = s->alias;
      if (aliases.set_in(ss))
        fail("circular type alias");
      aliases.set_add(ss);
      s = ss;
    } while (s->type_kind == Type_ALIAS);
  }
  return s;
}

static int sprint_float_val(char* str, double val) {
  int numchars = sprintf(str, "%g", val);
  if (strchr(str, '.') == NULL && strchr(str, 'e') == NULL) {
    strcat(str, ".0");
    return numchars + 2;
  } else {
    return numchars;
  }
}

static int sprint_complex_val(char* str, double real, double imm) {
  int numchars = 0;
  numchars += sprintf(str+numchars, "(");
  numchars += sprint_float_val(str+numchars, real);
  numchars += sprintf(str+numchars, ",");
  numchars += sprint_float_val(str+numchars, imm);
  numchars += sprintf(str+numchars, ")");
  return numchars;
}

int
sprint_imm(char *str, Immediate &imm) {
  int res = -1;
  switch (imm.const_kind) {
    case IF1_NUM_KIND_NONE:
      break;
    case IF1_NUM_KIND_UINT: {
      switch (imm.num_index) {
        case IF1_INT_TYPE_1:
          res = sprintf(str, "%u", imm.v_bool); break;
        case IF1_INT_TYPE_8:
          res = sprintf(str, "%u", imm.v_uint8); break;
        case IF1_INT_TYPE_16:
          res = sprintf(str, "%u", imm.v_uint16); break;
        case IF1_INT_TYPE_32:
          res = sprintf(str, "%u", imm.v_uint32); break;
        case IF1_INT_TYPE_64:
          res = sprintf(str, "%llu", imm.v_uint64); break;
        default: assert(!"case");
      }
      break;
    }
    case IF1_NUM_KIND_INT: {
      switch (imm.num_index) {
        case IF1_INT_TYPE_8:
          res = sprintf(str, "%d", imm.v_int8); break;
        case IF1_INT_TYPE_16:
          res = sprintf(str, "%d", imm.v_int16); break;
        case IF1_INT_TYPE_32:
          res = sprintf(str, "%d", imm.v_int32); break;
        case IF1_INT_TYPE_64:
          res = sprintf(str, "%lld", imm.v_int64); break;
        default: assert(!"case");
      }
      break;
    }
    case IF1_NUM_KIND_FLOAT:
      switch (imm.num_index) {
        case IF1_FLOAT_TYPE_32:
          res = sprint_float_val(str, imm.v_float32); break;
        case IF1_FLOAT_TYPE_64:
          res = sprint_float_val(str, imm.v_float64); break;
        default: assert(!"case");
      }
      break;
    case IF1_NUM_KIND_COMPLEX:
      switch (imm.num_index) {
        case IF1_FLOAT_TYPE_32:
          res = sprint_complex_val(str, imm.v_complex32.r, imm.v_complex32.i); break;
        case IF1_FLOAT_TYPE_64:
          res = sprint_complex_val(str, imm.v_complex64.r, imm.v_complex64.i); break;
        default: assert(!"case");
      }
      break;
    case IF1_CONST_KIND_STRING:
      res = sprintf(str, "%s", imm.v_string); break;
      break;
  }
  return res;
}

int
fprint_imm(FILE *fp, Immediate &imm) {
  char str[80];
  int res;
  if ((res = sprint_imm(str, imm) >= 0))
    fputs(str, fp);
  return res;
}

void
if1_set_int_type(IF1 *p, Sym *t, int signd, int size) {
  int ss = 0;
  size >>= 3;
  while (size) { ss++; size >>= 1; }
  p->int_types[ss][signd] = t;
  t->num_kind = signd ? IF1_NUM_KIND_INT : IF1_NUM_KIND_UINT;
  t->num_index = ss;
}

void
if1_set_float_type(IF1 *p, Sym *t, int size) {
  int ss = 0;
  size >>= 4;
  ss = size - 1;
  p->float_types[ss] = t;
  t->num_kind = IF1_NUM_KIND_FLOAT;
  t->num_index = ss;
}

void
if1_set_complex_type(IF1 *p, Sym *t, int size) {
  int ss = 0;
  size >>= 4;
  ss = size - 1;
  p->complex_types[ss] = t;
  t->num_kind = IF1_NUM_KIND_COMPLEX;
  t->num_index = ss;
}

int
if1_numeric_size(IF1 *p, Sym *t) {
  switch (t->num_kind) {
    case IF1_NUM_KIND_NONE: assert(!"bad case"); break;
    case IF1_NUM_KIND_INT:
    case IF1_NUM_KIND_UINT:
      return 1 << (t->num_index ? t->num_index : 1) - 1; // bool takes 1 byte
    case IF1_NUM_KIND_FLOAT:
      return 2 + (2 * t->num_index);
    case IF1_NUM_KIND_COMPLEX:
      return 2 * (2 + (2 * t->num_index));
  }
  return 0;
}

void
Sym::inherits_add(Sym *s) {
  implements.add(s);
  specializes.add(s);
  includes.add(s);
}

void
Sym::must_implement_and_specialize(Sym *s) {
  assert(!must_implement && !must_specialize);
  must_implement = s;
  must_specialize = s;
}

Sym *
Sym::scalar_type() {
  if (type && type->num_kind)
    return type;
  forv_Sym(ss, dispatch_order)
    if (ss->type && ss->type->num_kind)
      return ss->type;
  return 0;
}

Sym *
Sym::coerce_to(Sym *to) {
  if (this == to)
    return this;
  Sym *s1 = this->scalar_type(), *s2 = to->scalar_type();
  if (s1 && s2) {
    Sym *t = coerce_num(s1, s2);
    if (t == s2)
      return s2;
    return NULL;
  }
  if (element) {
    Sym *s1 = element->scalar_type(), *s2 = to->scalar_type();
    if (s1 && s2) {
      Sym *t = coerce_num(s1, s2);
      if (t == s2)
        return s2;
      return NULL;
    }
  }
  if (s1) {
    if (to == sym_string)
      return to;
  }
  return NULL;
}

<commit_msg>Permit arbitrary size string constants to be printed out.<commit_after>#include "geysa.h"
#include "ast.h"
#include "if1.h"
#include "fa.h"
#include "builtin.h"

char *type_kind_string[] = {
  "NONE", "UNKNOWN", "LUB", "GLB", "PRODUCT", "RECORD", "VECTOR",
  "FUN", "REF", "TAGGED", "PRIMITIVE", "APPLICATION", "VARIABLE", "ALIAS"};

BasicSym::BasicSym(void) :
  name(NULL),
  in(NULL),
  type(NULL),
  aspect(NULL),
  must_specialize(NULL),
  must_implement(NULL),
  ast(NULL),
  var(NULL),
  asymbol(NULL),
  nesting_depth(0),
  cg_string(NULL),
  is_builtin(0),
  is_read_only(0),
  is_constant(0),
  is_lvalue(0),
  is_var(0),
  is_default_arg(0),
  is_exact_match(0),
  is_module(0),
  is_fun(0),
  is_symbol(0),
  is_pattern(0),
  is_rest(0),
  is_generic(0),
  is_external(0),
  intent(0),
  global_scope(0),
  function_scope(0),
  is_structure(0),
  is_meta_type(0),
  is_value_class(0),
  is_union_class(0),
  fun_returns_value(0),
  live(0),
  incomplete(0),
  type_kind(0),
  num_kind(0),
  num_index(0),
  clone_for_constants(0)
{}

Sym *
meta_apply(Sym *fn, Sym *arg) {
  if (fn->type_kind != Type_APPLICATION)
    return 0;
  assert(0);
  return 0;
}

Sym::Sym() :
  destruct_name(NULL),
  arg_name(NULL),
  constant(NULL),
  size(0),
  scope(NULL),
  labelmap(NULL),
  fun(NULL),
  code(NULL),
  self(NULL),
  ret(NULL),
  cont(NULL),
  instantiates(NULL),
  match_type(NULL),
  abstract_type(NULL),
  alias(NULL),
  init(NULL),
  meta_type(NULL),
  element(NULL),
  domain(NULL),
  temp(NULL)
{}

char *
Sym::pathname() {
  char *p = 0;
  if (asymbol)
    p = asymbol->pathname();
  if (!p && ast)
    p = ast->pathname();
  if (p)
    return p;
  return "<unknown>";
}

char *
Sym::filename() {
  char *fn = pathname();
  char *r = strrchr(fn, '/');
  if (r) return r+1; else return fn;
}

int
Sym::line() {
  int l = 0;
  if (asymbol)
    l = asymbol->line();
  if (!l && ast)
    l = ast->line();
  return l;
}

int
Sym::ast_id() {
  if (asymbol)
    return asymbol->ast_id();
  return id;
}

int
Sym::log_line() {
  if (asymbol)
    return asymbol->log_line();
  if (strstr(filename(), "prelude"))
    return 0;
  return line();
}

void
Sym::copy_values(Sym *s) {
  int temp_id = id;
  *this = *s;
  id = temp_id;
}

Sym *
Sym::clone() {
  if (asymbol)
    return asymbol->clone();
  Sym *new_sym = copy();
  return new_sym;
}

Sym *
Sym::copy() {
  Sym *s = new_Sym();
  s->copy_values(this);
  return s;
}

int
compar_syms(const void *ai, const void *aj) {
  uint32 i = (*(Sym**)ai)->id;
  uint32 j = (*(Sym**)aj)->id;
  return (i > j) ? 1 : ((i < j) ? -1 : 0);
}

int
Sym::imm_int(int *result) {
  int i = 0;
  switch (type->num_kind) {
    default: return -1;
    case IF1_NUM_KIND_UINT: {
      switch (type->num_index) {
        case IF1_INT_TYPE_8: i = imm.v_uint8; break;
        case IF1_INT_TYPE_16: i = imm.v_uint16; break;
        case IF1_INT_TYPE_32: i = imm.v_uint32; break;
        case IF1_INT_TYPE_64: i = imm.v_uint64; break;
        default: return -1;
      }
      break;
    }
    case IF1_NUM_KIND_INT: {
      switch (type->num_index) {
        case IF1_INT_TYPE_8: i = imm.v_int8; break;
        case IF1_INT_TYPE_16: i = imm.v_int16; break;
        case IF1_INT_TYPE_32: i = imm.v_int32; break;
        case IF1_INT_TYPE_64: i = imm.v_int64; break;
        default: return -1;
      }
      break;
    }
  }
  *result = i;
  return 0;
}

Sym *
unalias_type(Sym *s) {
  if (!s)
    return s;
  if (s->type_kind == Type_ALIAS) {
    Vec<Sym *> aliases;
    do {
      if (!s->alias)
        return 0;
      Sym *ss = s->alias;
      if (aliases.set_in(ss))
        fail("circular type alias");
      aliases.set_add(ss);
      s = ss;
    } while (s->type_kind == Type_ALIAS);
  }
  return s;
}

static int
sprint_float_val(char* str, double val) {
  int numchars = sprintf(str, "%g", val);
  if (strchr(str, '.') == NULL && strchr(str, 'e') == NULL) {
    strcat(str, ".0");
    return numchars + 2;
  } else {
    return numchars;
  }
}

static int
sprint_complex_val(char* str, double real, double imm) {
  int numchars = 0;
  numchars += sprintf(str+numchars, "(");
  numchars += sprint_float_val(str+numchars, real);
  numchars += sprintf(str+numchars, ",");
  numchars += sprint_float_val(str+numchars, imm);
  numchars += sprintf(str+numchars, ")");
  return numchars;
}

int
sprint_imm(char *str, Immediate &imm) {
  int res = -1;
  switch (imm.const_kind) {
    case IF1_NUM_KIND_NONE:
      break;
    case IF1_NUM_KIND_UINT: {
      switch (imm.num_index) {
        case IF1_INT_TYPE_1:
          res = sprintf(str, "%u", imm.v_bool); break;
        case IF1_INT_TYPE_8:
          res = sprintf(str, "%u", imm.v_uint8); break;
        case IF1_INT_TYPE_16:
          res = sprintf(str, "%u", imm.v_uint16); break;
        case IF1_INT_TYPE_32:
          res = sprintf(str, "%u", imm.v_uint32); break;
        case IF1_INT_TYPE_64:
          res = sprintf(str, "%llu", imm.v_uint64); break;
        default: assert(!"case");
      }
      break;
    }
    case IF1_NUM_KIND_INT: {
      switch (imm.num_index) {
        case IF1_INT_TYPE_8:
          res = sprintf(str, "%d", imm.v_int8); break;
        case IF1_INT_TYPE_16:
          res = sprintf(str, "%d", imm.v_int16); break;
        case IF1_INT_TYPE_32:
          res = sprintf(str, "%d", imm.v_int32); break;
        case IF1_INT_TYPE_64:
          res = sprintf(str, "%lld", imm.v_int64); break;
        default: assert(!"case");
      }
      break;
    }
    case IF1_NUM_KIND_FLOAT:
      switch (imm.num_index) {
        case IF1_FLOAT_TYPE_32:
          res = sprint_float_val(str, imm.v_float32); break;
        case IF1_FLOAT_TYPE_64:
          res = sprint_float_val(str, imm.v_float64); break;
        default: assert(!"case");
      }
      break;
    case IF1_NUM_KIND_COMPLEX:
      switch (imm.num_index) {
        case IF1_FLOAT_TYPE_32:
          res = sprint_complex_val(str, imm.v_complex32.r, imm.v_complex32.i); break;
        case IF1_FLOAT_TYPE_64:
          res = sprint_complex_val(str, imm.v_complex64.r, imm.v_complex64.i); break;
        default: assert(!"case");
      }
      break;
    case IF1_CONST_KIND_STRING:
      res = sprintf(str, "%s", imm.v_string); break;
      break;
  }
  return res;
}

int
fprint_imm(FILE *fp, Immediate &imm) {
  int res = -1;
  switch (imm.const_kind) {
    case IF1_NUM_KIND_NONE:
      break;
    case IF1_NUM_KIND_UINT: {
      switch (imm.num_index) {
        case IF1_INT_TYPE_1:
          res = fprintf(fp, "%u", imm.v_bool); break;
        case IF1_INT_TYPE_8:
          res = fprintf(fp, "%u", imm.v_uint8); break;
        case IF1_INT_TYPE_16:
          res = fprintf(fp, "%u", imm.v_uint16); break;
        case IF1_INT_TYPE_32:
          res = fprintf(fp, "%u", imm.v_uint32); break;
        case IF1_INT_TYPE_64:
          res = fprintf(fp, "%llu", imm.v_uint64); break;
        default: assert(!"case");
      }
      break;
    }
    case IF1_NUM_KIND_INT: {
      switch (imm.num_index) {
        case IF1_INT_TYPE_8:
          res = fprintf(fp, "%d", imm.v_int8); break;
        case IF1_INT_TYPE_16:
          res = fprintf(fp, "%d", imm.v_int16); break;
        case IF1_INT_TYPE_32:
          res = fprintf(fp, "%d", imm.v_int32); break;
        case IF1_INT_TYPE_64:
          res = fprintf(fp, "%lld", imm.v_int64); break;
        default: assert(!"case");
      }
      break;
    }
    case IF1_NUM_KIND_FLOAT:
      switch (imm.num_index) {
        case IF1_FLOAT_TYPE_32: {
          char str[80];
          res = sprint_float_val(str, imm.v_float32);
          fputs(str, fp);
          break;
        }
        case IF1_FLOAT_TYPE_64: {
          char str[80];
          res = sprint_float_val(str, imm.v_float64);
          fputs(str, fp);
          break;
        }
        default: assert(!"case");
      }
      break;
    case IF1_NUM_KIND_COMPLEX:
      switch (imm.num_index) {
        case IF1_FLOAT_TYPE_32: {
          char str[80];
          res = sprint_complex_val(str, imm.v_complex32.r, imm.v_complex32.i);
          fputs(str, fp);
          break;
        }
        case IF1_FLOAT_TYPE_64: {
          char str[80];
          res = sprint_complex_val(str, imm.v_complex64.r, imm.v_complex64.i);
          fputs(str, fp);
          break;
        }
        default: assert(!"case");
      }
      break;
    case IF1_CONST_KIND_STRING:
      res = fprintf(fp, "%s", imm.v_string); break;
      break;
  }
  return res;
}

void
if1_set_int_type(IF1 *p, Sym *t, int signd, int size) {
  int ss = 0;
  size >>= 3;
  while (size) { ss++; size >>= 1; }
  p->int_types[ss][signd] = t;
  t->num_kind = signd ? IF1_NUM_KIND_INT : IF1_NUM_KIND_UINT;
  t->num_index = ss;
}

void
if1_set_float_type(IF1 *p, Sym *t, int size) {
  int ss = 0;
  size >>= 4;
  ss = size - 1;
  p->float_types[ss] = t;
  t->num_kind = IF1_NUM_KIND_FLOAT;
  t->num_index = ss;
}

void
if1_set_complex_type(IF1 *p, Sym *t, int size) {
  int ss = 0;
  size >>= 4;
  ss = size - 1;
  p->complex_types[ss] = t;
  t->num_kind = IF1_NUM_KIND_COMPLEX;
  t->num_index = ss;
}

int
if1_numeric_size(IF1 *p, Sym *t) {
  switch (t->num_kind) {
    case IF1_NUM_KIND_NONE: assert(!"bad case"); break;
    case IF1_NUM_KIND_INT:
    case IF1_NUM_KIND_UINT:
      return 1 << (t->num_index ? t->num_index : 1) - 1; // bool takes 1 byte
    case IF1_NUM_KIND_FLOAT:
      return 2 + (2 * t->num_index);
    case IF1_NUM_KIND_COMPLEX:
      return 2 * (2 + (2 * t->num_index));
  }
  return 0;
}

void
Sym::inherits_add(Sym *s) {
  implements.add(s);
  specializes.add(s);
  includes.add(s);
}

void
Sym::must_implement_and_specialize(Sym *s) {
  assert(!must_implement && !must_specialize);
  must_implement = s;
  must_specialize = s;
}

Sym *
Sym::scalar_type() {
  if (type && type->num_kind)
    return type;
  forv_Sym(ss, dispatch_order)
    if (ss->type && ss->type->num_kind)
      return ss->type;
  return 0;
}

Sym *
Sym::coerce_to(Sym *to) {
  if (this == to)
    return this;
  Sym *s1 = this->scalar_type(), *s2 = to->scalar_type();
  if (s1 && s2) {
    Sym *t = coerce_num(s1, s2);
    if (t == s2)
      return s2;
    return NULL;
  }
  if (element) {
    Sym *s1 = element->scalar_type(), *s2 = to->scalar_type();
    if (s1 && s2) {
      Sym *t = coerce_num(s1, s2);
      if (t == s2)
        return s2;
      return NULL;
    }
  }
  if (s1) {
    if (to == sym_string)
      return to;
  }
  return NULL;
}

<|endoftext|>


<commit_before>/*
This file is part of Bohrium and copyright (c) 2012 the Bohrium team:
http://bohrium.bitbucket.org

Bohrium 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 3
of the License, or (at your option) any later version.

Bohrium 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 General Public License for more details.

You should have received a copy of the
GNU Lesser General Public License along with Bohrium.

If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __BOHRIUM_BRIDGE_CPP_RUNTIME
#define __BOHRIUM_BRIDGE_CPP_RUNTIME
#include <iostream>
#include <sstream>
#include <boost/ptr_container/ptr_map.hpp>

namespace bh {

typedef boost::ptr_map<unsigned int, bh_array> storage_type;
storage_type storage;
unsigned int keys = 1;

// Runtime : Definition

Runtime* Runtime::pInstance = 0;

Runtime* Runtime::instance()
{
    if (pInstance == 0) {
        pInstance = new Runtime;
    }
    return pInstance;
}

void stop()
{
    delete Runtime::instance();
}

Runtime::Runtime()
{
    queue_size = 0;
    ext_in_queue = 0;

    bh_error err;
    char err_msg[100];

    self_component = bh_component_setup(NULL);
    bh_component_children( self_component, &children_count, &components );

    if(children_count != 1 || components[0]->type != BH_VEM) {
        fprintf(stderr, "Error in the configuration: the bridge must "
                        "have exactly one child of type VEM\n");
        exit(-1);
    }
    vem_component   = components[0];

    vem_init        = vem_component->init;
    vem_execute     = vem_component->execute;
    vem_shutdown    = vem_component->shutdown;

    vem_reg_func    = vem_component->reg_func;
    free(components);

    err = vem_init(vem_component);
    if (err) {
        fprintf(stderr, "Error in vem_init()\n");
        exit(-1);
    }

    //
    // Register extensions
    //
    err = vem_reg_func("bh_random", &random_id);
    if (err != BH_SUCCESS) {
        sprintf(err_msg, "Fatal error in the initialization of the user"
                        "-defined random operation: %s.\n",
                        bh_error_text(err));
        throw std::runtime_error(err_msg);
    }
    if (random_id <= 0) {
        sprintf(err_msg, "Fatal error in the initialization of the user"
                        "-defined random operation: invalid ID returned"
                        " (%ld).\n", (long)random_id);
        throw std::runtime_error(err_msg);
    }
}

Runtime::~Runtime()
{
    // Deconstructor is not called in a timely fashion.
    flush();
    vem_shutdown();
    bh_component_free(self_component);
    bh_component_free(vem_component);
}

/**
 * Flush the instruction-queue.
 * This will force the runtime system to execute the queued up instructions.
 *
 * @return The number of instructions flushed.
 */
inline
bh_intp Runtime::flush()
{
    bh_error status;
    bh_intp cur_size = queue_size;

    if (queue_size > 0) {
        status = vem_execute(queue_size, queue);
        queue_size = 0;

        if (ext_in_queue>0) {
            for(bh_intp i=0; i<ext_in_queue; i++) {
                if(ext_queue[i]->id == random_id) {
                    free((bh_random_type*)ext_queue[i]);
                } else {
                    throw std::runtime_error("Cannot de-allocate extension...");
                }
            }
            ext_in_queue = 0;
        }

        if (status != BH_SUCCESS) {
            std::stringstream err_msg;
            err_msg << "vem_execute(queue_size=" << cur_size << ") failed: " << bh_error_text(status) << std::endl;
            /*
            for(int i=0; i<cur_size; i++) {
                bh_pprint_instr( &queue[i] );
            }*/

            throw std::runtime_error(err_msg.str());
        }
    }
    return cur_size;
}

bh_intp Runtime::get_queue_size()
{
    return queue_size;
}

/**
 * Flush the instruction-queue if it is about to get overflowed.
 *
 * @return The number of instructions flushed.
 */
inline
bh_intp Runtime::guard()
{
    bh_intp cur_size = queue_size;
    if (queue_size >= BH_CPP_QUEUE_MAX) {
        vem_execute(queue_size, queue);
        queue_size = 0;

        if (ext_in_queue>0) {
            for(bh_intp i=0; i<ext_in_queue; i++) {
                if (ext_queue[i]->id == random_id) {
                    free((bh_random_type*)ext_queue[i]);
                } else {
                    throw std::runtime_error("Cannot de-allocate extension...");
                }
            }
            ext_in_queue = 0;
        }

    }

    return cur_size;
}

template <typename T>
inline
multi_array<T>& Runtime::op()
{
    multi_array<T>* operand = new multi_array<T>();

    return *operand;
}

/**
 * Create an intermediate operand.
 */
template <typename T>
inline
multi_array<T>& Runtime::temp()
{
    multi_array<T>* operand = new multi_array<T>();
    unsigned int key = keys++;
    operand->link(key);
    operand->setTemp(true);
    storage.insert(key, new bh_array);
    assign_array_type<T>(&storage[key]);

    return *operand;
}

template <typename T>
inline
multi_array<T>& Runtime::temp(size_t n)
{
    multi_array<T>* operand = new multi_array<T>(n);
    operand->setTemp(true);
    return *operand;
}

/**
 * Create an intermediate operand based on another operand.
 */
template <typename T>
inline
multi_array<T>& Runtime::temp(multi_array<T>& input)
{
    multi_array<T>* operand = new multi_array<T>(input);
    operand->setTemp(true);
    return *operand;
}

/**
 * Create an alias/segment/view of the supplied base operand.
 */
template <typename T>
inline
multi_array<T>& Runtime::view(multi_array<T>& base)
{
    multi_array<T>* operand = new multi_array<T>();
    storage[operand->getKey()].base = bh_base_array(&storage[base.getKey()]);
    return *operand;
}

/**
 * Create an intermediate alias/segment/view of the supplied base operand.
 */
template <typename T>
inline
multi_array<T>& Runtime::temp_view(multi_array<T>& base)
{
    multi_array<T>* operand = new multi_array<T>();
    storage[operand->getKey()].base = bh_base_array(&storage[base.getKey()]);
    operand->setTemp(true);
    return *operand;
}

template <typename T>
inline
void Runtime::enqueue(bh_opcode opcode, multi_array<T>& op0, multi_array<T>& op1, multi_array<T>& op2)
{
    bh_instruction* instr;

    guard();

    instr = &queue[queue_size++];
    instr->opcode = opcode;
    instr->operand[0] = &storage[op0.getKey()];
    instr->operand[1] = &storage[op1.getKey()];
    instr->operand[2] = &storage[op2.getKey()];

    if (op1.getTemp()) { delete &op1; }
    if (op2.getTemp()) { delete &op2; }
}

template <typename T>
inline
void Runtime::enqueue(bh_opcode opcode, multi_array<T>& op0, multi_array<T>& op1, const T& op2)
{
    bh_instruction* instr;

    guard();

    instr = &queue[queue_size++];
    instr->opcode = opcode;
    instr->operand[0] = &storage[op0.getKey()];
    instr->operand[1] = &storage[op1.getKey()];
    instr->operand[2] = NULL;
    assign_const_type( &instr->constant, op2 );

    if (op1.getTemp()) { delete &op1; }
}

template <typename T>
inline
void Runtime::enqueue(bh_opcode opcode, multi_array<T>& op0, const T& op1, multi_array<T>& op2)
{
    bh_instruction* instr;

    guard();

    instr = &queue[queue_size++];
    instr->opcode = opcode;
    instr->operand[0] = &storage[op0.getKey()];
    instr->operand[1] = NULL;
    instr->operand[2] = &storage[op2.getKey()];
    assign_const_type( &instr->constant, op1 );

    if (op2.getTemp()) { delete &op2; }
}

template <typename T>
inline
void Runtime::enqueue(bh_opcode opcode, multi_array<T>& op0, multi_array<T>& op1)
{
    bh_instruction* instr;

    guard();

    instr = &queue[queue_size++];
    instr->opcode = opcode;
    instr->operand[0] = &storage[op0.getKey()];
    instr->operand[1] = &storage[op1.getKey()];
    instr->operand[2] = NULL;

    if (op1.getTemp()) { delete &op1; }
}

template <typename T>
inline
void Runtime::enqueue(bh_opcode opcode, multi_array<T>& op0, const T& op1)
{
    bh_instruction* instr;

    guard();

    instr = &queue[queue_size++];
    instr->opcode = opcode;
    instr->operand[0] = &storage[op0.getKey()];
    instr->operand[1] = NULL;
    instr->operand[2] = NULL;
    assign_const_type( &instr->constant, op1 );
}

template <typename T>
inline
void Runtime::enqueue(bh_opcode opcode, multi_array<T>& op0)
{
    bh_instruction* instr;

    guard();

    instr = &queue[queue_size++];
    instr->opcode = opcode;
    instr->operand[0] = &storage[op0.getKey()];
    instr->operand[1] = NULL;
    instr->operand[2] = NULL;
}

template <typename Ret, typename In>    // x = y
inline
void Runtime::enqueue(bh_opcode opcode, multi_array<Ret>& op0, multi_array<In>& op1)
{
    bh_instruction* instr;

    guard();

    instr = &queue[queue_size++];
    instr->opcode = opcode;
    instr->operand[0] = &storage[op0.getKey()];
    instr->operand[1] = &storage[op1.getKey()];
    instr->operand[2] = NULL;

    if (op1.getTemp()) { delete &op1; }
}

template <typename Ret, typename In>    // x = y < z
inline
void Runtime::enqueue(bh_opcode opcode, multi_array<Ret>& op0, multi_array<In>& op1, multi_array<In>& op2)
{
    bh_instruction* instr;

    guard();

    instr = &queue[queue_size++];
    instr->opcode = opcode;
    instr->operand[0] = &storage[op0.getKey()];
    instr->operand[1] = &storage[op1.getKey()];
    instr->operand[2] = &storage[op2.getKey()];
    assign_const_type( &instr->constant, op2 );

    if (op1.getTemp()) { delete &op1; }
    if (op2.getTemp()) { delete &op2; }
}

template <typename Ret, typename In>    // x = y < 1
inline
void Runtime::enqueue(bh_opcode opcode, multi_array<Ret>& op0, multi_array<In>& op1, const In& op2)
{
    bh_instruction* instr;

    guard();
    instr = &queue[queue_size++];
    instr->opcode = opcode;
    instr->operand[0] = &storage[op0.getKey()];
    instr->operand[1] = &storage[op1.getKey()];
    instr->operand[2] = NULL;
    assign_const_type( &instr->constant, op2 );

    if (op1.getTemp()) { delete &op1; }
}

template <typename Ret, typename In>    // reduce(), pow()
inline
void Runtime::enqueue(bh_opcode opcode, multi_array<Ret>& op0, multi_array<Ret>& op1, const In& op2)
{
    bh_instruction* instr;

    guard();

    instr = &queue[queue_size++];
    instr->opcode = opcode;
    instr->operand[0] = &storage[op0.getKey()];
    instr->operand[1] = &storage[op1.getKey()];
    instr->operand[2] = NULL;
    assign_const_type( &instr->constant, op2 );

    if (op1.getTemp()) { delete &op1; }
}

template <typename Ret, typename In>    // x = 1 < y
inline
void Runtime::enqueue(bh_opcode opcode, multi_array<Ret>& op0, const In& op1, multi_array<In>& op2)
{
    bh_instruction* instr;

    guard();

    instr = &queue[queue_size++];
    instr->opcode = opcode;
    instr->operand[0] = &storage[op0.getKey()];
    instr->operand[1] = NULL;
    instr->operand[2] = &storage[op2.getKey()];
    assign_const_type( &instr->constant, op1 );

    if (op2.getTemp()) { delete &op2; }
}

template <typename T>           // Userfunc / extensions
inline
void Runtime::enqueue(bh_userfunc* rinstr)
{
    bh_instruction* instr;

    guard();

    instr = &queue[queue_size++];
    instr->opcode        = BH_USERFUNC;
    instr->userfunc      = (bh_userfunc *) rinstr;

    ext_queue[ext_in_queue++] = instr->userfunc;
}

//
//  Copy... properties
//
template <typename Ret, typename In>
void equiv(multi_array<Ret>& ret, multi_array<In>& in)
{
    bh_array *ret_a, *in_a;

    ret_a   = &storage[ret.getKey()];
    in_a    = &storage[in.getKey()];

    ret_a->base        = NULL;
    ret_a->ndim        = in_a->ndim;
    ret_a->start       = in_a->start;
    for(bh_index i=0; i< in_a->ndim; i++) {
        ret_a->shape[i] = in_a->shape[i];
    }
    for(bh_index i=0; i< in_a->ndim; i++) {
        ret_a->stride[i] = in_a->stride[i];
    }
    ret_a->data        = NULL;

    assign_array_type<Ret>(ret_a);
}

}
#endif

<commit_msg>cppb: Fixed inial value of random-id in runtime.<commit_after>/*
This file is part of Bohrium and copyright (c) 2012 the Bohrium team:
http://bohrium.bitbucket.org

Bohrium 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 3
of the License, or (at your option) any later version.

Bohrium 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 General Public License for more details.

You should have received a copy of the
GNU Lesser General Public License along with Bohrium.

If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __BOHRIUM_BRIDGE_CPP_RUNTIME
#define __BOHRIUM_BRIDGE_CPP_RUNTIME
#include <iostream>
#include <sstream>
#include <boost/ptr_container/ptr_map.hpp>

namespace bh {

typedef boost::ptr_map<unsigned int, bh_array> storage_type;
storage_type storage;
unsigned int keys = 1;

// Runtime : Definition

Runtime* Runtime::pInstance = 0;

Runtime* Runtime::instance()
{
    if (pInstance == 0) {
        pInstance = new Runtime;
    }
    return pInstance;
}

void stop()
{
    delete Runtime::instance();
}

Runtime::Runtime() : random_id(0), ext_in_queue(0), queue_size(0)
{
    bh_error err;
    char err_msg[100];

    self_component = bh_component_setup(NULL);
    bh_component_children( self_component, &children_count, &components );

    if(children_count != 1 || components[0]->type != BH_VEM) {
        fprintf(stderr, "Error in the configuration: the bridge must "
                        "have exactly one child of type VEM\n");
        exit(-1);
    }
    vem_component   = components[0];

    vem_init        = vem_component->init;
    vem_execute     = vem_component->execute;
    vem_shutdown    = vem_component->shutdown;

    vem_reg_func    = vem_component->reg_func;
    free(components);

    err = vem_init(vem_component);
    if (err) {
        fprintf(stderr, "Error in vem_init()\n");
        exit(-1);
    }

    //
    // Register extensions
    //
    err = vem_reg_func("bh_random", &random_id);
    if (err != BH_SUCCESS) {
        sprintf(err_msg, "Fatal error in the initialization of the user"
                        "-defined random operation: %s.\n",
                        bh_error_text(err));
        throw std::runtime_error(err_msg);
    }
    if (random_id <= 0) {
        sprintf(err_msg, "Fatal error in the initialization of the user"
                        "-defined random operation: invalid ID returned"
                        " (%ld).\n", (long)random_id);
        throw std::runtime_error(err_msg);
    }
}

Runtime::~Runtime()
{
    // Deconstructor is not called in a timely fashion.
    flush();
    vem_shutdown();
    bh_component_free(self_component);
    bh_component_free(vem_component);
}

/**
 * Flush the instruction-queue.
 * This will force the runtime system to execute the queued up instructions.
 *
 * @return The number of instructions flushed.
 */
inline
bh_intp Runtime::flush()
{
    bh_error status;
    bh_intp cur_size = queue_size;

    if (queue_size > 0) {
        status = vem_execute(queue_size, queue);
        queue_size = 0;

        if (ext_in_queue>0) {
            for(bh_intp i=0; i<ext_in_queue; i++) {
                if(ext_queue[i]->id == random_id) {
                    free((bh_random_type*)ext_queue[i]);
                } else {
                    throw std::runtime_error("Cannot de-allocate extension...");
                }
            }
            ext_in_queue = 0;
        }

        if (status != BH_SUCCESS) {
            std::stringstream err_msg;
            err_msg << "vem_execute(queue_size=" << cur_size << ") failed: " << bh_error_text(status) << std::endl;
            /*
            for(int i=0; i<cur_size; i++) {
                bh_pprint_instr( &queue[i] );
            }*/

            throw std::runtime_error(err_msg.str());
        }
    }
    return cur_size;
}

bh_intp Runtime::get_queue_size()
{
    return queue_size;
}

/**
 * Flush the instruction-queue if it is about to get overflowed.
 *
 * @return The number of instructions flushed.
 */
inline
bh_intp Runtime::guard()
{
    bh_intp cur_size = queue_size;
    if (queue_size >= BH_CPP_QUEUE_MAX) {
        vem_execute(queue_size, queue);
        queue_size = 0;

        if (ext_in_queue>0) {
            for(bh_intp i=0; i<ext_in_queue; i++) {
                if (ext_queue[i]->id == random_id) {
                    free((bh_random_type*)ext_queue[i]);
                } else {
                    throw std::runtime_error("Cannot de-allocate extension...");
                }
            }
            ext_in_queue = 0;
        }

    }

    return cur_size;
}

template <typename T>
inline
multi_array<T>& Runtime::op()
{
    multi_array<T>* operand = new multi_array<T>();

    return *operand;
}

/**
 * Create an intermediate operand.
 */
template <typename T>
inline
multi_array<T>& Runtime::temp()
{
    multi_array<T>* operand = new multi_array<T>();
    unsigned int key = keys++;
    operand->link(key);
    operand->setTemp(true);
    storage.insert(key, new bh_array);
    assign_array_type<T>(&storage[key]);

    return *operand;
}

template <typename T>
inline
multi_array<T>& Runtime::temp(size_t n)
{
    multi_array<T>* operand = new multi_array<T>(n);
    operand->setTemp(true);
    return *operand;
}

/**
 * Create an intermediate operand based on another operand.
 */
template <typename T>
inline
multi_array<T>& Runtime::temp(multi_array<T>& input)
{
    multi_array<T>* operand = new multi_array<T>(input);
    operand->setTemp(true);
    return *operand;
}

/**
 * Create an alias/segment/view of the supplied base operand.
 */
template <typename T>
inline
multi_array<T>& Runtime::view(multi_array<T>& base)
{
    multi_array<T>* operand = new multi_array<T>();
    storage[operand->getKey()].base = bh_base_array(&storage[base.getKey()]);
    return *operand;
}

/**
 * Create an intermediate alias/segment/view of the supplied base operand.
 */
template <typename T>
inline
multi_array<T>& Runtime::temp_view(multi_array<T>& base)
{
    multi_array<T>* operand = new multi_array<T>();
    storage[operand->getKey()].base = bh_base_array(&storage[base.getKey()]);
    operand->setTemp(true);
    return *operand;
}

template <typename T>
inline
void Runtime::enqueue(bh_opcode opcode, multi_array<T>& op0, multi_array<T>& op1, multi_array<T>& op2)
{
    bh_instruction* instr;

    guard();

    instr = &queue[queue_size++];
    instr->opcode = opcode;
    instr->operand[0] = &storage[op0.getKey()];
    instr->operand[1] = &storage[op1.getKey()];
    instr->operand[2] = &storage[op2.getKey()];

    if (op1.getTemp()) { delete &op1; }
    if (op2.getTemp()) { delete &op2; }
}

template <typename T>
inline
void Runtime::enqueue(bh_opcode opcode, multi_array<T>& op0, multi_array<T>& op1, const T& op2)
{
    bh_instruction* instr;

    guard();

    instr = &queue[queue_size++];
    instr->opcode = opcode;
    instr->operand[0] = &storage[op0.getKey()];
    instr->operand[1] = &storage[op1.getKey()];
    instr->operand[2] = NULL;
    assign_const_type( &instr->constant, op2 );

    if (op1.getTemp()) { delete &op1; }
}

template <typename T>
inline
void Runtime::enqueue(bh_opcode opcode, multi_array<T>& op0, const T& op1, multi_array<T>& op2)
{
    bh_instruction* instr;

    guard();

    instr = &queue[queue_size++];
    instr->opcode = opcode;
    instr->operand[0] = &storage[op0.getKey()];
    instr->operand[1] = NULL;
    instr->operand[2] = &storage[op2.getKey()];
    assign_const_type( &instr->constant, op1 );

    if (op2.getTemp()) { delete &op2; }
}

template <typename T>
inline
void Runtime::enqueue(bh_opcode opcode, multi_array<T>& op0, multi_array<T>& op1)
{
    bh_instruction* instr;

    guard();

    instr = &queue[queue_size++];
    instr->opcode = opcode;
    instr->operand[0] = &storage[op0.getKey()];
    instr->operand[1] = &storage[op1.getKey()];
    instr->operand[2] = NULL;

    if (op1.getTemp()) { delete &op1; }
}

template <typename T>
inline
void Runtime::enqueue(bh_opcode opcode, multi_array<T>& op0, const T& op1)
{
    bh_instruction* instr;

    guard();

    instr = &queue[queue_size++];
    instr->opcode = opcode;
    instr->operand[0] = &storage[op0.getKey()];
    instr->operand[1] = NULL;
    instr->operand[2] = NULL;
    assign_const_type( &instr->constant, op1 );
}

template <typename T>
inline
void Runtime::enqueue(bh_opcode opcode, multi_array<T>& op0)
{
    bh_instruction* instr;

    guard();

    instr = &queue[queue_size++];
    instr->opcode = opcode;
    instr->operand[0] = &storage[op0.getKey()];
    instr->operand[1] = NULL;
    instr->operand[2] = NULL;
}

template <typename Ret, typename In>    // x = y
inline
void Runtime::enqueue(bh_opcode opcode, multi_array<Ret>& op0, multi_array<In>& op1)
{
    bh_instruction* instr;

    guard();

    instr = &queue[queue_size++];
    instr->opcode = opcode;
    instr->operand[0] = &storage[op0.getKey()];
    instr->operand[1] = &storage[op1.getKey()];
    instr->operand[2] = NULL;

    if (op1.getTemp()) { delete &op1; }
}

template <typename Ret, typename In>    // x = y < z
inline
void Runtime::enqueue(bh_opcode opcode, multi_array<Ret>& op0, multi_array<In>& op1, multi_array<In>& op2)
{
    bh_instruction* instr;

    guard();

    instr = &queue[queue_size++];
    instr->opcode = opcode;
    instr->operand[0] = &storage[op0.getKey()];
    instr->operand[1] = &storage[op1.getKey()];
    instr->operand[2] = &storage[op2.getKey()];
    assign_const_type( &instr->constant, op2 );

    if (op1.getTemp()) { delete &op1; }
    if (op2.getTemp()) { delete &op2; }
}

template <typename Ret, typename In>    // x = y < 1
inline
void Runtime::enqueue(bh_opcode opcode, multi_array<Ret>& op0, multi_array<In>& op1, const In& op2)
{
    bh_instruction* instr;

    guard();
    instr = &queue[queue_size++];
    instr->opcode = opcode;
    instr->operand[0] = &storage[op0.getKey()];
    instr->operand[1] = &storage[op1.getKey()];
    instr->operand[2] = NULL;
    assign_const_type( &instr->constant, op2 );

    if (op1.getTemp()) { delete &op1; }
}

template <typename Ret, typename In>    // reduce(), pow()
inline
void Runtime::enqueue(bh_opcode opcode, multi_array<Ret>& op0, multi_array<Ret>& op1, const In& op2)
{
    bh_instruction* instr;

    guard();

    instr = &queue[queue_size++];
    instr->opcode = opcode;
    instr->operand[0] = &storage[op0.getKey()];
    instr->operand[1] = &storage[op1.getKey()];
    instr->operand[2] = NULL;
    assign_const_type( &instr->constant, op2 );

    if (op1.getTemp()) { delete &op1; }
}

template <typename Ret, typename In>    // x = 1 < y
inline
void Runtime::enqueue(bh_opcode opcode, multi_array<Ret>& op0, const In& op1, multi_array<In>& op2)
{
    bh_instruction* instr;

    guard();

    instr = &queue[queue_size++];
    instr->opcode = opcode;
    instr->operand[0] = &storage[op0.getKey()];
    instr->operand[1] = NULL;
    instr->operand[2] = &storage[op2.getKey()];
    assign_const_type( &instr->constant, op1 );

    if (op2.getTemp()) { delete &op2; }
}

template <typename T>           // Userfunc / extensions
inline
void Runtime::enqueue(bh_userfunc* rinstr)
{
    bh_instruction* instr;

    guard();

    instr = &queue[queue_size++];
    instr->opcode        = BH_USERFUNC;
    instr->userfunc      = (bh_userfunc *) rinstr;

    ext_queue[ext_in_queue++] = instr->userfunc;
}

//
//  Copy... properties
//
template <typename Ret, typename In>
void equiv(multi_array<Ret>& ret, multi_array<In>& in)
{
    bh_array *ret_a, *in_a;

    ret_a   = &storage[ret.getKey()];
    in_a    = &storage[in.getKey()];

    ret_a->base        = NULL;
    ret_a->ndim        = in_a->ndim;
    ret_a->start       = in_a->start;
    for(bh_index i=0; i< in_a->ndim; i++) {
        ret_a->shape[i] = in_a->shape[i];
    }
    for(bh_index i=0; i< in_a->ndim; i++) {
        ret_a->stride[i] = in_a->stride[i];
    }
    ret_a->data        = NULL;

    assign_array_type<Ret>(ret_a);
}

}
#endif

<|endoftext|>