<commit_before>/* Copyright 2013 Jeremie Roy. All rights reserved.
 * License: http://www.opensource.org/licenses/BSD-2-Clause
*/
#include "TrueTypeFont.h"
/*
#undef __FTERRORS_H__
#define FT_ERRORDEF( e, v, s )  { e, s },
#define FT_ERROR_START_LIST     {
#define FT_ERROR_END_LIST       { 0, 0 } };
const struct {
    int          code;
    const char*  message;
} FT_Errors[] =
*/
#include "FreeType.h"
#include "edtaa3func.h"
//#include "SEDT.h"
#include <assert.h>
#include <math.h>

struct FTHolder
{
	FT_Library library;
	FT_Face face;
};

namespace bgfx_font
{

TrueTypeFont::TrueTypeFont(): m_font(NULL)
{
}

TrueTypeFont::~TrueTypeFont()
{
	if(m_font!=NULL)
	{
		FTHolder* holder = (FTHolder*) m_font;
		FT_Done_Face( holder->face );
        FT_Done_FreeType( holder->library );
		delete m_font;
		m_font = NULL;
	}
}

bool TrueTypeFont::init(const uint8_t* buffer, uint32_t bufferSize, int32_t fontIndex, uint32_t pixelHeight)
{
	assert((bufferSize > 256 && bufferSize < 100000000) && "TrueType buffer size is suspicious");
	assert((pixelHeight > 4 && pixelHeight < 128) && "TrueType buffer size is suspicious");

	assert(m_font == NULL && "TrueTypeFont already initialized" );

	FTHolder* holder = new FTHolder();

	// Initialize Freetype library
	FT_Error error = FT_Init_FreeType( &holder->library );
	if( error)
	{
		delete holder;
		return false;
	}

	error = FT_New_Memory_Face( holder->library, buffer, bufferSize, fontIndex, &holder->face );
	if ( error == FT_Err_Unknown_File_Format )
	{
		// the font file could be opened and read, but it appears
		//that its font format is unsupported
		FT_Done_FreeType( holder->library );
		delete holder;
		return false;
	}
	else if ( error )
	{
		// another error code means that the font file could not
		// be opened or read, or simply that it is broken...
		FT_Done_FreeType( holder->library );
		delete holder;
		return false;
	}

    // Select unicode charmap
    error = FT_Select_Charmap( holder->face, FT_ENCODING_UNICODE );
    if( error )
    {
		FT_Done_Face( holder->face );
		FT_Done_FreeType( holder->library );
        return false;
    }
	//set size in pixels
	error = FT_Set_Pixel_Sizes( holder->face, 0, pixelHeight );
	if( error )
    {
		FT_Done_Face( holder->face );
		FT_Done_FreeType( holder->library );
        return false;
    }

	m_font = holder;
	return true;
}

FontInfo TrueTypeFont::getFontInfo()
{
	assert(m_font != NULL && "TrueTypeFont not initialized" );
	FTHolder* holder = (FTHolder*) m_font;

	assert(FT_IS_SCALABLE (holder->face));

	FT_Size_Metrics metrics = holder->face->size->metrics;

	//todo manage unscalable font
	FontInfo outFontInfo;
	outFontInfo.scale = 1.0f;
	outFontInfo.ascender = metrics.ascender /64.0f;
	outFontInfo.descender = metrics.descender /64.0f;
	outFontInfo.lineGap = (metrics.height - metrics.ascender + metrics.descender) /64.0f;

	outFontInfo.underline_position = FT_MulFix(holder->face->underline_position, metrics.y_scale) /64.0f;
	outFontInfo.underline_thickness= FT_MulFix(holder->face->underline_thickness,metrics.y_scale) /64.0f;
	return outFontInfo;
}

bool TrueTypeFont::bakeGlyphAlpha(const FontInfo& fontInfo,CodePoint_t codePoint, GlyphInfo& glyphInfo, uint8_t* outBuffer)
{
	assert(m_font != NULL && "TrueTypeFont not initialized" );
	FTHolder* holder = (FTHolder*) m_font;

	glyphInfo.glyphIndex = FT_Get_Char_Index( holder->face, codePoint );

	FT_GlyphSlot slot = holder->face->glyph;
	FT_Error error = FT_Load_Glyph(  holder->face, glyphInfo.glyphIndex, FT_LOAD_DEFAULT );
	if(error) { return false; }

	FT_Glyph glyph;
	error = FT_Get_Glyph( slot, &glyph );
	if ( error ) { return false; }

	error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 );
	if(error){ return false; }

	FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyph;

	int x = bitmap->left;
	int y = -bitmap->top;
	int w = bitmap->bitmap.width;
	int h = bitmap->bitmap.rows;

	glyphInfo.offset_x = (float) x;
	glyphInfo.offset_y = (float) y;
	glyphInfo.width = (float) w;
	glyphInfo.height = (float) h;
	glyphInfo.advance_x = (float)slot->advance.x /64.0f;
	glyphInfo.advance_y = (float)slot->advance.y /64.0f;

	int charsize = 1;
	int depth=1;
	int stride = bitmap->bitmap.pitch;
	for( int i=0; i<h; ++i )
    {
        memcpy(outBuffer+(i*w) * charsize * depth,
			bitmap->bitmap.buffer + (i*stride) * charsize, w * charsize * depth  );
    }
	FT_Done_Glyph(glyph);
	return true;
}

bool TrueTypeFont::bakeGlyphSubpixel(const FontInfo& fontInfo,CodePoint_t codePoint, GlyphInfo& glyphInfo, uint8_t* outBuffer)
{
	assert(m_font != NULL && "TrueTypeFont not initialized" );
	FTHolder* holder = (FTHolder*) m_font;

	glyphInfo.glyphIndex = FT_Get_Char_Index( holder->face, codePoint );

	FT_GlyphSlot slot = holder->face->glyph;
	FT_Error error = FT_Load_Glyph(  holder->face, glyphInfo.glyphIndex, FT_LOAD_DEFAULT );
	if(error) { return false; }

	FT_Glyph glyph;
	error = FT_Get_Glyph( slot, &glyph );
	if ( error ) { return false; }

	error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_LCD, 0, 1 );
	if(error){ return false; }

	FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyph;
	int x = bitmap->left;
	int y = -bitmap->top;
	int w = bitmap->bitmap.width;
	int h = bitmap->bitmap.rows;

	glyphInfo.offset_x = (float) x;
	glyphInfo.offset_y = (float) y;
	glyphInfo.width = (float) w;
	glyphInfo.height = (float) h;
	glyphInfo.advance_x = (float)slot->advance.x /64.0f;
	glyphInfo.advance_y = (float)slot->advance.y /64.0f;
	int charsize = 1;
	int depth=3;
	int stride = bitmap->bitmap.pitch;
	for( int i=0; i<h; ++i )
    {
        memcpy(outBuffer+(i*w) * charsize * depth,
			bitmap->bitmap.buffer + (i*stride) * charsize, w * charsize * depth  );
    }
	FT_Done_Glyph(glyph);
	return true;
}

void make_distance_map( unsigned char *img, unsigned char *outImg, unsigned int width, unsigned int height )
{
    short * xdist = (short *)  malloc( width * height * sizeof(short) );
    short * ydist = (short *)  malloc( width * height * sizeof(short) );
    double * gx   = (double *) calloc( width * height, sizeof(double) );
    double * gy      = (double *) calloc( width * height, sizeof(double) );
    double * data    = (double *) calloc( width * height, sizeof(double) );
    double * outside = (double *) calloc( width * height, sizeof(double) );
    double * inside  = (double *) calloc( width * height, sizeof(double) );
    uint32_t i;

    // Convert img into double (data)
    double img_min = 255, img_max = -255;
    for( i=0; i<width*height; ++i)
    {
        double v = img[i];
        data[i] = v;
        if (v > img_max) img_max = v;
        if (v < img_min) img_min = v;
    }
    // Rescale image levels between 0 and 1
    for( i=0; i<width*height; ++i)
    {
        data[i] = (img[i]-img_min)/(img_max-img_min);
    }

    // Compute outside = edtaa3(bitmap); % Transform background (0's)
    computegradient( data, width, height, gx, gy);
    edtaa3(data, gx, gy, width, height, xdist, ydist, outside);
    for( i=0; i<width*height; ++i)
        if( outside[i] < 0 )
            outside[i] = 0.0;

    // Compute inside = edtaa3(1-bitmap); % Transform foreground (1's)
    memset(gx, 0, sizeof(double)*width*height );
    memset(gy, 0, sizeof(double)*width*height );
    for( i=0; i<width*height; ++i)
        data[i] = 1.0 - data[i];
    computegradient( data, width, height, gx, gy);
    edtaa3(data, gx, gy, width, height, xdist, ydist, inside);
    for( i=0; i<width*height; ++i)
        if( inside[i] < 0 )
            inside[i] = 0.0;

    // distmap = outside - inside; % Bipolar distance field
    unsigned char *out = outImg;//(unsigned char *) malloc( width * height * sizeof(unsigned char) );
    for( i=0; i<width*height; ++i)
    {
		//out[i] = 127 - outside[i]*8;
		//if(out[i]<0) out[i] = 0;
		//out[i] += inside[i]*16;
		//if(out[i]>255) out[i] = 255;

		outside[i] -= inside[i];
        outside[i] = 128 + outside[i]*16;

		//if(outside[i] > 8) outside[i] = 8;
		//if(inside[i] > 8) outside[i] = 8;

		//outside[i] = 128 - inside[i]*8 + outside[i]*8;

        if( outside[i] < 0 ) outside[i] = 0;
        if( outside[i] > 255 ) outside[i] = 255;
        out[i] = 255 - (unsigned char) outside[i];
        //out[i] = (unsigned char) outside[i];
    }

    free( xdist );
    free( ydist );
    free( gx );
    free( gy );
    free( data );
    free( outside );
    free( inside );
}

bool TrueTypeFont::bakeGlyphDistance(const FontInfo& fontInfo, CodePoint_t codePoint, GlyphInfo& glyphInfo, uint8_t* outBuffer)
{
	assert(m_font != NULL && "TrueTypeFont not initialized" );
	FTHolder* holder = (FTHolder*) m_font;

	glyphInfo.glyphIndex = FT_Get_Char_Index( holder->face, codePoint );

	FT_Int32 loadMode = FT_LOAD_DEFAULT|FT_LOAD_NO_HINTING; //FT_LOAD_TARGET_MONO;
	FT_Render_Mode renderMode = FT_RENDER_MODE_NORMAL;//FT_RENDER_MODE_MONO

	FT_GlyphSlot slot = holder->face->glyph;
	FT_Error error = FT_Load_Glyph(  holder->face, glyphInfo.glyphIndex, loadMode );
	if(error) { return false; }

	FT_Glyph glyph;
	error = FT_Get_Glyph( slot, &glyph );
	if ( error ) { return false; }

	error = FT_Glyph_To_Bitmap( &glyph, renderMode, 0, 1 );
	if(error){ return false; }

	FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyph;

	int x = bitmap->left;
	int y = -bitmap->top;
	int w = bitmap->bitmap.width;
	int h = bitmap->bitmap.rows;

	glyphInfo.offset_x = (float) x;
	glyphInfo.offset_y = (float) y;
	glyphInfo.width = (float) w;
	glyphInfo.height = (float) h;
	glyphInfo.advance_x = (float)slot->advance.x /64.0f;
	glyphInfo.advance_y = (float)slot->advance.y /64.0f;

	int charsize = 1;
	int depth=1;
	int stride = bitmap->bitmap.pitch;

	/*
	const uint8_t* src = bitmap->bitmap.buffer;
	for( int y=0; y<h; ++y )
	{
		for( int x=0; x<w; ++x )
		{
			uint32_t idx = y*w+x;
			outBuffer[idx] = ((src[x / 8]) & (1 << (7 - (x % 8)))) ? 255 : 0;
		}
		src+=stride;
	}*/

	for( int i=0; i<h; ++i )
    {

        memcpy(outBuffer+(i*w) * charsize * depth,
			bitmap->bitmap.buffer + (i*stride) * charsize, w * charsize * depth  );
    }
	FT_Done_Glyph(glyph);

	if(w*h >0)
	{
		uint32_t dw = 6;
		uint32_t dh = 6;
		if(dw<2) dw = 2;
		if(dh<2) dh = 2;

		uint32_t nw = w + dw*2;
		uint32_t nh = h + dh*2;
		assert(nw*nh < 128*128);
		uint32_t buffSize = nw*nh*sizeof(uint8_t);

		uint8_t * alphaImg = (uint8_t *)  malloc( buffSize );
		memset(alphaImg, 0, nw*nh*sizeof(uint8_t));

		//copy the original buffer to the temp one
		for(uint32_t  i= dh; i< nh-dh; ++i)
		{
			memcpy(alphaImg+i*nw+dw, outBuffer+(i-dh)*w, w);
		}

		make_distance_map(alphaImg, outBuffer, nw, nh);
		free(alphaImg);

		glyphInfo.offset_x -= (float) dw;
		glyphInfo.offset_y -= (float) dh;
		glyphInfo.width = (float) nw ;
		glyphInfo.height = (float) nh;
	}

	return true;
}

}
<commit_msg>cleaning dead code<commit_after>/* Copyright 2013 Jeremie Roy. All rights reserved.
 * License: http://www.opensource.org/licenses/BSD-2-Clause
*/
#include "TrueTypeFont.h"
/*
#undef __FTERRORS_H__
#define FT_ERRORDEF( e, v, s )  { e, s },
#define FT_ERROR_START_LIST     {
#define FT_ERROR_END_LIST       { 0, 0 } };
const struct {
    int          code;
    const char*  message;
} FT_Errors[] =
*/
#include "FreeType.h"
#include "edtaa3func.h"
//#include "SEDT.h"
#include <assert.h>
#include <math.h>

struct FTHolder
{
	FT_Library library;
	FT_Face face;
};

namespace bgfx_font
{

TrueTypeFont::TrueTypeFont(): m_font(NULL)
{
}

TrueTypeFont::~TrueTypeFont()
{
	if(m_font!=NULL)
	{
		FTHolder* holder = (FTHolder*) m_font;
		FT_Done_Face( holder->face );
        FT_Done_FreeType( holder->library );
		delete m_font;
		m_font = NULL;
	}
}

bool TrueTypeFont::init(const uint8_t* buffer, uint32_t bufferSize, int32_t fontIndex, uint32_t pixelHeight)
{
	assert((bufferSize > 256 && bufferSize < 100000000) && "TrueType buffer size is suspicious");
	assert((pixelHeight > 4 && pixelHeight < 128) && "TrueType buffer size is suspicious");

	assert(m_font == NULL && "TrueTypeFont already initialized" );

	FTHolder* holder = new FTHolder();

	// Initialize Freetype library
	FT_Error error = FT_Init_FreeType( &holder->library );
	if( error)
	{
		delete holder;
		return false;
	}

	error = FT_New_Memory_Face( holder->library, buffer, bufferSize, fontIndex, &holder->face );
	if ( error == FT_Err_Unknown_File_Format )
	{
		// the font file could be opened and read, but it appears
		//that its font format is unsupported
		FT_Done_FreeType( holder->library );
		delete holder;
		return false;
	}
	else if ( error )
	{
		// another error code means that the font file could not
		// be opened or read, or simply that it is broken...
		FT_Done_FreeType( holder->library );
		delete holder;
		return false;
	}

    // Select unicode charmap
    error = FT_Select_Charmap( holder->face, FT_ENCODING_UNICODE );
    if( error )
    {
		FT_Done_Face( holder->face );
		FT_Done_FreeType( holder->library );
        return false;
    }
	//set size in pixels
	error = FT_Set_Pixel_Sizes( holder->face, 0, pixelHeight );
	if( error )
    {
		FT_Done_Face( holder->face );
		FT_Done_FreeType( holder->library );
        return false;
    }

	m_font = holder;
	return true;
}

FontInfo TrueTypeFont::getFontInfo()
{
	assert(m_font != NULL && "TrueTypeFont not initialized" );
	FTHolder* holder = (FTHolder*) m_font;

	assert(FT_IS_SCALABLE (holder->face));

	FT_Size_Metrics metrics = holder->face->size->metrics;

	//todo manage unscalable font
	FontInfo outFontInfo;
	outFontInfo.scale = 1.0f;
	outFontInfo.ascender = metrics.ascender /64.0f;
	outFontInfo.descender = metrics.descender /64.0f;
	outFontInfo.lineGap = (metrics.height - metrics.ascender + metrics.descender) /64.0f;

	outFontInfo.underline_position = FT_MulFix(holder->face->underline_position, metrics.y_scale) /64.0f;
	outFontInfo.underline_thickness= FT_MulFix(holder->face->underline_thickness,metrics.y_scale) /64.0f;
	return outFontInfo;
}

bool TrueTypeFont::bakeGlyphAlpha(const FontInfo& fontInfo,CodePoint_t codePoint, GlyphInfo& glyphInfo, uint8_t* outBuffer)
{
	assert(m_font != NULL && "TrueTypeFont not initialized" );
	FTHolder* holder = (FTHolder*) m_font;

	glyphInfo.glyphIndex = FT_Get_Char_Index( holder->face, codePoint );

	FT_GlyphSlot slot = holder->face->glyph;
	FT_Error error = FT_Load_Glyph(  holder->face, glyphInfo.glyphIndex, FT_LOAD_DEFAULT );
	if(error) { return false; }

	FT_Glyph glyph;
	error = FT_Get_Glyph( slot, &glyph );
	if ( error ) { return false; }

	error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 );
	if(error){ return false; }

	FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyph;

	int x = bitmap->left;
	int y = -bitmap->top;
	int w = bitmap->bitmap.width;
	int h = bitmap->bitmap.rows;

	glyphInfo.offset_x = (float) x;
	glyphInfo.offset_y = (float) y;
	glyphInfo.width = (float) w;
	glyphInfo.height = (float) h;
	glyphInfo.advance_x = (float)slot->advance.x /64.0f;
	glyphInfo.advance_y = (float)slot->advance.y /64.0f;

	int charsize = 1;
	int depth=1;
	int stride = bitmap->bitmap.pitch;
	for( int i=0; i<h; ++i )
    {
        memcpy(outBuffer+(i*w) * charsize * depth,
			bitmap->bitmap.buffer + (i*stride) * charsize, w * charsize * depth  );
    }
	FT_Done_Glyph(glyph);
	return true;
}

bool TrueTypeFont::bakeGlyphSubpixel(const FontInfo& fontInfo,CodePoint_t codePoint, GlyphInfo& glyphInfo, uint8_t* outBuffer)
{
	assert(m_font != NULL && "TrueTypeFont not initialized" );
	FTHolder* holder = (FTHolder*) m_font;

	glyphInfo.glyphIndex = FT_Get_Char_Index( holder->face, codePoint );

	FT_GlyphSlot slot = holder->face->glyph;
	FT_Error error = FT_Load_Glyph(  holder->face, glyphInfo.glyphIndex, FT_LOAD_DEFAULT );
	if(error) { return false; }

	FT_Glyph glyph;
	error = FT_Get_Glyph( slot, &glyph );
	if ( error ) { return false; }

	error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_LCD, 0, 1 );
	if(error){ return false; }

	FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyph;
	int x = bitmap->left;
	int y = -bitmap->top;
	int w = bitmap->bitmap.width;
	int h = bitmap->bitmap.rows;

	glyphInfo.offset_x = (float) x;
	glyphInfo.offset_y = (float) y;
	glyphInfo.width = (float) w;
	glyphInfo.height = (float) h;
	glyphInfo.advance_x = (float)slot->advance.x /64.0f;
	glyphInfo.advance_y = (float)slot->advance.y /64.0f;
	int charsize = 1;
	int depth=3;
	int stride = bitmap->bitmap.pitch;
	for( int i=0; i<h; ++i )
    {
        memcpy(outBuffer+(i*w) * charsize * depth,
			bitmap->bitmap.buffer + (i*stride) * charsize, w * charsize * depth  );
    }
	FT_Done_Glyph(glyph);
	return true;
}

//TODO optimize: remove dynamic allocation and convert double to float
void make_distance_map( unsigned char *img, unsigned char *outImg, unsigned int width, unsigned int height )
{
    short * xdist = (short *)  malloc( width * height * sizeof(short) );
    short * ydist = (short *)  malloc( width * height * sizeof(short) );
    double * gx   = (double *) calloc( width * height, sizeof(double) );
    double * gy      = (double *) calloc( width * height, sizeof(double) );
    double * data    = (double *) calloc( width * height, sizeof(double) );
    double * outside = (double *) calloc( width * height, sizeof(double) );
    double * inside  = (double *) calloc( width * height, sizeof(double) );
    uint32_t i;

    // Convert img into double (data)
    double img_min = 255, img_max = -255;
    for( i=0; i<width*height; ++i)
    {
        double v = img[i];
        data[i] = v;
        if (v > img_max) img_max = v;
        if (v < img_min) img_min = v;
    }
    // Rescale image levels between 0 and 1
    for( i=0; i<width*height; ++i)
    {
        data[i] = (img[i]-img_min)/(img_max-img_min);
    }

    // Compute outside = edtaa3(bitmap); % Transform background (0's)
    computegradient( data, width, height, gx, gy);
    edtaa3(data, gx, gy, width, height, xdist, ydist, outside);
    for( i=0; i<width*height; ++i)
        if( outside[i] < 0 )
            outside[i] = 0.0;

    // Compute inside = edtaa3(1-bitmap); % Transform foreground (1's)
    memset(gx, 0, sizeof(double)*width*height );
    memset(gy, 0, sizeof(double)*width*height );
    for( i=0; i<width*height; ++i)
        data[i] = 1.0 - data[i];
    computegradient( data, width, height, gx, gy);
    edtaa3(data, gx, gy, width, height, xdist, ydist, inside);
    for( i=0; i<width*height; ++i)
        if( inside[i] < 0 )
            inside[i] = 0.0;

    // distmap = outside - inside; % Bipolar distance field
    unsigned char *out = outImg;//(unsigned char *) malloc( width * height * sizeof(unsigned char) );
    for( i=0; i<width*height; ++i)
    {
		//out[i] = 127 - outside[i]*8;
		//if(out[i]<0) out[i] = 0;
		//out[i] += inside[i]*16;
		//if(out[i]>255) out[i] = 255;

		outside[i] -= inside[i];
        outside[i] = 128 + outside[i]*16;

		//if(outside[i] > 8) outside[i] = 8;
		//if(inside[i] > 8) outside[i] = 8;

		//outside[i] = 128 - inside[i]*8 + outside[i]*8;

        if( outside[i] < 0 ) outside[i] = 0;
        if( outside[i] > 255 ) outside[i] = 255;
        out[i] = 255 - (unsigned char) outside[i];
        //out[i] = (unsigned char) outside[i];
    }

    free( xdist );
    free( ydist );
    free( gx );
    free( gy );
    free( data );
    free( outside );
    free( inside );
}

bool TrueTypeFont::bakeGlyphDistance(const FontInfo& fontInfo, CodePoint_t codePoint, GlyphInfo& glyphInfo, uint8_t* outBuffer)
{
	assert(m_font != NULL && "TrueTypeFont not initialized" );
	FTHolder* holder = (FTHolder*) m_font;

	glyphInfo.glyphIndex = FT_Get_Char_Index( holder->face, codePoint );

	FT_Int32 loadMode = FT_LOAD_DEFAULT|FT_LOAD_NO_HINTING;
	FT_Render_Mode renderMode = FT_RENDER_MODE_NORMAL;

	FT_GlyphSlot slot = holder->face->glyph;
	FT_Error error = FT_Load_Glyph(  holder->face, glyphInfo.glyphIndex, loadMode );
	if(error) { return false; }

	FT_Glyph glyph;
	error = FT_Get_Glyph( slot, &glyph );
	if ( error ) { return false; }

	error = FT_Glyph_To_Bitmap( &glyph, renderMode, 0, 1 );
	if(error){ return false; }

	FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyph;

	int x = bitmap->left;
	int y = -bitmap->top;
	int w = bitmap->bitmap.width;
	int h = bitmap->bitmap.rows;

	glyphInfo.offset_x = (float) x;
	glyphInfo.offset_y = (float) y;
	glyphInfo.width = (float) w;
	glyphInfo.height = (float) h;
	glyphInfo.advance_x = (float)slot->advance.x /64.0f;
	glyphInfo.advance_y = (float)slot->advance.y /64.0f;

	int charsize = 1;
	int depth=1;
	int stride = bitmap->bitmap.pitch;

	for( int i=0; i<h; ++i )
    {

        memcpy(outBuffer+(i*w) * charsize * depth,
			bitmap->bitmap.buffer + (i*stride) * charsize, w * charsize * depth  );
    }
	FT_Done_Glyph(glyph);

	if(w*h >0)
	{
		uint32_t dw = 6;
		uint32_t dh = 6;
		if(dw<2) dw = 2;
		if(dh<2) dh = 2;

		uint32_t nw = w + dw*2;
		uint32_t nh = h + dh*2;
		assert(nw*nh < 128*128);
		uint32_t buffSize = nw*nh*sizeof(uint8_t);

		uint8_t * alphaImg = (uint8_t *)  malloc( buffSize );
		memset(alphaImg, 0, nw*nh*sizeof(uint8_t));

		//copy the original buffer to the temp one
		for(uint32_t  i= dh; i< nh-dh; ++i)
		{
			memcpy(alphaImg+i*nw+dw, outBuffer+(i-dh)*w, w);
		}

		make_distance_map(alphaImg, outBuffer, nw, nh);
		free(alphaImg);

		glyphInfo.offset_x -= (float) dw;
		glyphInfo.offset_y -= (float) dh;
		glyphInfo.width = (float) nw ;
		glyphInfo.height = (float) nh;
	}

	return true;
}

}
<|endoftext|>


<commit_before>#include "slist_eval.h"
#include "slist_parser.h"
#include "slist_log.h"

#include <istream>

namespace
{
    slist::node_ptr eval_list(slist::context& ctx, const slist::node_ptr& root);
    slist::node_ptr eval_name(slist::context& ctx, const slist::node_ptr& root);
}

namespace slist
{
    node_ptr eval(context& ctx, const node_ptr& root)
    {
        ctx.debug_dump_callstack();
        log_traceln("Eval: ", root);

        if (root == nullptr)
        {
            return nullptr;
        }

        node_ptr result;

        switch (root->type)
        {
            case node_type::empty:
                result = root;
                break;
            case node_type::pair:
                result = eval_list(ctx, root);
                break;
            case node_type::name:
                result = eval_name(ctx, root);
                break;
            case node_type::boolean:
            case node_type::integer:
            case node_type::number:
            case node_type::string:
                result = root;
            default:
                break;
        }

        log_trace("Result of ", root);
        log_traceln(" -> ", result);
        debug_print_environment(ctx, ctx.active_env);

        return result;
    }

    node_ptr eval_procedure(context& ctx, const node_ptr& proc_node, const node_ptr& args)
    {
        if (proc_node == nullptr)
        {
            return nullptr;
        }

        auto proc = proc_node->proc;

        if (proc == nullptr)
        {
            return nullptr;
        }

        context::callstack_item item;
        item.node = proc_node;

        ctx.callstack.push_back(item);

        struct auto_pop_callstack
        {
            auto_pop_callstack(context& ctx) : ctx(ctx) {}
            ~auto_pop_callstack() { ctx.callstack.pop_back(); }

            context& ctx;
        } auto_stack_popper(ctx);

        if (proc->is_native)
        {
            // Build a root node
            node_ptr name_node(std::make_shared<node>());
            name_node->type = node_type::name;
            name_node->value = proc->name;

            node_ptr root(std::make_shared<node>());
            root->type = node_type::pair;
            root->car = name_node;
            root->cdr = args;

            auto prev_env = ctx.active_env;
            ctx.active_env = proc->env;
            auto result = proc->native_func(ctx, root);
            ctx.active_env = prev_env;

            return result;
        }
        else
        {
            node_ptr result;

            while (proc != nullptr)
            {
                if (proc->is_tail)
                {
                    ctx.debug_dump_callstack();

                    log_traceln("Trying to unwind the stack:\n", proc->body);

                    // Try to unwind the call stack: tail-call elimination
                    int size = static_cast<int>(ctx.callstack.size());
                    int i = size-1;
                    while (i > 0)
                    {
                        //auto& item = ctx.callstack[i];
                        auto& prev_item = ctx.callstack[i-1];
                        log_traceln("    Prev: ", prev_item.node);
                        if (prev_item.node->is_tail)
                        {
                            if (prev_item.node->proc == proc)
                            {
                                prev_item.delayed_proc = proc;
                                prev_item.delayed_args = args;
                                return nullptr;
                            }
                            --i;
                        }
                        else
                        {
                            break;
                        }
                    }
                }

                log_traceln("Executing procedure:\n", proc->body);

                auto prev_env = ctx.active_env;
                ctx.active_env = proc->env;
                result = eval(ctx, proc->body);
                ctx.active_env = prev_env;

                auto& back_item = ctx.callstack.back();
                proc = back_item.delayed_proc;

                if (proc != nullptr)
                {
                    context::callstack_item item;
                    item.node = proc_node;
                    ctx.callstack.pop_back();
                    ctx.callstack.push_back(item);
                    log_traceln("STACK OPTIM!!");
                    // TODO: Merge environments??
                }
            }

            return result;
        }
    }

    node_ptr exec(context& ctx, const std::string& str)
    {
        node_ptr result;
        node_ptr parse_node = parse(str);
        if (parse_node != nullptr)
        {
            while (parse_node != nullptr)
            {
                result = eval(ctx, parse_node->car);
                parse_node = parse_node->cdr;
            }
        }
        return result;
    }

    node_ptr exec(context& ctx, std::istream& in)
    {
        std::string s;

        const size_t size = 1024;
        char buffer[1024];
        while (in.read(buffer, size))
        {
            s.append(buffer, size);
        }
        s.append(buffer, in.gcount());

        return exec(ctx, s);
    }

    node_ptr apply(context& ctx, const node_ptr& args, const node_ptr& proc_node)
    {
        auto& proc = proc_node->proc;

        // Create a new environement to make sure they are not shared between evals
        environment_ptr env(std::make_shared<environment>());
        env->parent = proc->env;
        proc->env = env;

        node_ptr var = proc->variables;
        node_ptr arg = args;

        if (var != nullptr && var->type == node_type::name)
        {
            // This is a variadic argument, grab all the args
            env->register_variable(var->value, args);
        }
        else
        {
            while (var != nullptr && arg != nullptr)
            {
                node_ptr var_name = var->car;
                if (var_name == nullptr || var_name->type != node_type::name)
                {
                    log_errorln("Invalid variable:\n", var_name);
                    return nullptr;
                }

                if (var_name->value == ".")
                {
                    // The next argument is a variadic one
                    var = var->cdr;
                    if (var == nullptr)
                    {
                        log_errorln("Missing variadic argument after '.'");
                        return nullptr;
                    }

                    var_name = var->car;
                    if (var_name == nullptr || var_name->type != node_type::name)
                    {
                        log_errorln("Invalid variable:\n", var_name);
                        return nullptr;
                    }

                    if (proc->is_macro)
                    {
                        // Do not evaluate macro arguments
                        env->register_variable(var_name->value, arg);
                    }
                    else
                    {
                        node_ptr list_arg(std::make_shared<node>());
                        list_arg->type = node_type::pair;
                        while (arg)
                        {
                            list_arg->append(eval(ctx, arg->car));
                            arg = arg->cdr;
                        }

                        env->register_variable(var_name->value, list_arg);
                    }
                    break;
                }

                if (proc->is_macro)
                {
                    // Do not evaluate macro arguments
                    env->register_variable(var_name->value, arg->car);
                }
                else
                {
                    env->register_variable(var_name->value, eval(ctx, arg->car));
                }

                arg = arg->cdr;
                var = var->cdr;
            }
        }

        // log_traceln("Evaluating Procedure from 'apply':\n", nullptr, proc);

        if (proc->is_macro)
        {
            // log_traceln("Macro root: ", nullptr, proc);
            node_ptr res = eval_procedure(ctx, proc_node, args);
            // log_traceln("Macro res: ", res);
            return eval(ctx, res);
        }
        else
        {
            return eval_procedure(ctx, proc_node, args);
        }
    }
}

namespace
{
    slist::node_ptr eval_list(slist::context& ctx, const slist::node_ptr& root)
    {
        using namespace slist;

        if (root->length() == 0)
        {
            log_errorln("List is empty", root);
            return nullptr;
        }

        node_ptr op_node = root->get(0);
        if (op_node == nullptr)
        {
            log_errorln("Cannot evaluate empty list.");
            return nullptr;
        }

        node_ptr proc_node = op_node;
        procedure_ptr proc = proc_node->proc;

        if (proc == nullptr && op_node->type == node_type::pair)
        {
            node_ptr eval_node = eval(ctx, op_node);
            if (eval_node == nullptr || eval_node->proc == nullptr)
            {
                log_errorln("Error: first argument is not a procedure", root);
                return nullptr;
            }
            proc_node = eval_node;
            proc = eval_node->proc;
        }
        else
        {
            // Look in environment
            node_ptr val = ctx.active_env->lookup_variable(op_node->value);
            if (val != nullptr && val->proc != nullptr)
            {
                proc_node = val;
                proc = val->proc;
                if (proc != nullptr && proc->is_native)
                {
                    return proc->native_func(ctx, root);
                }
            }
        }

        if (proc != nullptr)
        {
            return apply(ctx, root->cdr, proc_node);
        }

        log_errorln("Operator is not a procedure: ", op_node);

        return nullptr;
    }

    slist::node_ptr eval_name(slist::context& ctx, const slist::node_ptr& root)
    {
        using namespace slist;
        auto var_node = ctx.active_env->lookup_variable(root->value);
        if (var_node == nullptr)
        {
            log_errorln("Could not evaluate variable: ", root);
            return nullptr;
        }
        return var_node;
    }
}<commit_msg>Fixed environment merge for tail call optim.<commit_after>#include "slist_eval.h"
#include "slist_parser.h"
#include "slist_log.h"

#include <istream>

namespace
{
    slist::node_ptr eval_list(slist::context& ctx, const slist::node_ptr& root);
    slist::node_ptr eval_name(slist::context& ctx, const slist::node_ptr& root);
}

namespace slist
{
    node_ptr eval(context& ctx, const node_ptr& root)
    {
        ctx.debug_dump_callstack();
        log_traceln("Eval: ", root);

        if (root == nullptr)
        {
            return nullptr;
        }

        node_ptr result;

        switch (root->type)
        {
            case node_type::empty:
                result = root;
                break;
            case node_type::pair:
                result = eval_list(ctx, root);
                break;
            case node_type::name:
                result = eval_name(ctx, root);
                break;
            case node_type::boolean:
            case node_type::integer:
            case node_type::number:
            case node_type::string:
                result = root;
            default:
                break;
        }

        log_trace("Result of ", root);
        log_traceln(" -> ", result);
        debug_print_environment(ctx, ctx.active_env);

        return result;
    }

    node_ptr eval_procedure(context& ctx, const node_ptr& proc_node, const node_ptr& args)
    {
        if (proc_node == nullptr)
        {
            return nullptr;
        }

        auto proc = proc_node->proc;

        if (proc == nullptr)
        {
            return nullptr;
        }

        context::callstack_item item;
        item.node = proc_node;

        ctx.callstack.push_back(item);

        struct auto_pop_callstack
        {
            auto_pop_callstack(context& ctx) : ctx(ctx) {}
            ~auto_pop_callstack() { ctx.callstack.pop_back(); }

            context& ctx;
        } auto_stack_popper(ctx);

        if (proc->is_native)
        {
            // Build a root node
            node_ptr name_node(std::make_shared<node>());
            name_node->type = node_type::name;
            name_node->value = proc->name;

            node_ptr root(std::make_shared<node>());
            root->type = node_type::pair;
            root->car = name_node;
            root->cdr = args;

            auto prev_env = ctx.active_env;
            ctx.active_env = proc->env;
            auto result = proc->native_func(ctx, root);
            ctx.active_env = prev_env;

            return result;
        }
        else
        {
            node_ptr result;

            while (proc != nullptr)
            {
                if (proc->is_tail)
                {
                    ctx.debug_dump_callstack();

                    log_traceln("Trying to unwind the stack:\n", proc->body);

                    // Try to unwind the call stack: tail-call elimination
                    int size = static_cast<int>(ctx.callstack.size());
                    int i = size-1;
                    while (i > 0)
                    {
                        //auto& item = ctx.callstack[i];
                        auto& prev_item = ctx.callstack[i-1];
                        log_traceln("    Prev: ", prev_item.node);
                        if (prev_item.node->is_tail)
                        {
                            if (prev_item.node->proc == proc)
                            {
                                prev_item.delayed_proc = proc;
                                prev_item.delayed_args = args;
                                return nullptr;
                            }
                            --i;
                        }
                        else
                        {
                            break;
                        }
                    }
                }

                log_traceln("Executing procedure:\n", proc->body);

                auto prev_env = ctx.active_env;
                ctx.active_env = proc->env;
                result = eval(ctx, proc->body);
                ctx.active_env = prev_env;

                auto prev_proc = proc;

                auto& back_item = ctx.callstack.back();
                proc = back_item.delayed_proc;

                if (proc != nullptr)
                {
                    context::callstack_item item;
                    item.node = proc_node;
                    ctx.callstack.pop_back();
                    ctx.callstack.push_back(item);

                    proc->env->parent = prev_env;

//                    // TODO: Merge environments??
//                    log_traceln("Prev proc env:");
//                    debug_print_environment(ctx, prev_env);
//
//                    log_traceln("Proc env:");
//                    debug_print_environment(ctx, proc->env);

                    log_traceln("STACK OPTIM!!");
                }
            }

            return result;
        }
    }

    node_ptr exec(context& ctx, const std::string& str)
    {
        node_ptr result;
        node_ptr parse_node = parse(str);
        if (parse_node != nullptr)
        {
            while (parse_node != nullptr)
            {
                result = eval(ctx, parse_node->car);
                parse_node = parse_node->cdr;
            }
        }
        return result;
    }

    node_ptr exec(context& ctx, std::istream& in)
    {
        std::string s;

        const size_t size = 1024;
        char buffer[1024];
        while (in.read(buffer, size))
        {
            s.append(buffer, size);
        }
        s.append(buffer, in.gcount());

        return exec(ctx, s);
    }

    node_ptr apply(context& ctx, const node_ptr& args, const node_ptr& proc_node)
    {
        auto& proc = proc_node->proc;

        // Create a new environement to make sure they are not shared between evals
        environment_ptr env(std::make_shared<environment>());
        env->parent = proc->env;
        proc->env = env;

        node_ptr var = proc->variables;
        node_ptr arg = args;

        if (var != nullptr && var->type == node_type::name)
        {
            // This is a variadic argument, grab all the args
            env->register_variable(var->value, args);
        }
        else
        {
            while (var != nullptr && arg != nullptr)
            {
                node_ptr var_name = var->car;
                if (var_name == nullptr || var_name->type != node_type::name)
                {
                    log_errorln("Invalid variable:\n", var_name);
                    return nullptr;
                }

                if (var_name->value == ".")
                {
                    // The next argument is a variadic one
                    var = var->cdr;
                    if (var == nullptr)
                    {
                        log_errorln("Missing variadic argument after '.'");
                        return nullptr;
                    }

                    var_name = var->car;
                    if (var_name == nullptr || var_name->type != node_type::name)
                    {
                        log_errorln("Invalid variable:\n", var_name);
                        return nullptr;
                    }

                    if (proc->is_macro)
                    {
                        // Do not evaluate macro arguments
                        env->register_variable(var_name->value, arg);
                    }
                    else
                    {
                        node_ptr list_arg(std::make_shared<node>());
                        list_arg->type = node_type::pair;
                        while (arg)
                        {
                            list_arg->append(eval(ctx, arg->car));
                            arg = arg->cdr;
                        }

                        env->register_variable(var_name->value, list_arg);
                    }
                    break;
                }

                if (proc->is_macro)
                {
                    // Do not evaluate macro arguments
                    env->register_variable(var_name->value, arg->car);
                }
                else
                {
                    env->register_variable(var_name->value, eval(ctx, arg->car));
                }

                arg = arg->cdr;
                var = var->cdr;
            }
        }

        // log_traceln("Evaluating Procedure from 'apply':\n", nullptr, proc);

        if (proc->is_macro)
        {
            // log_traceln("Macro root: ", nullptr, proc);
            node_ptr res = eval_procedure(ctx, proc_node, args);
            // log_traceln("Macro res: ", res);
            return eval(ctx, res);
        }
        else
        {
            return eval_procedure(ctx, proc_node, args);
        }
    }
}

namespace
{
    slist::node_ptr eval_list(slist::context& ctx, const slist::node_ptr& root)
    {
        using namespace slist;

        if (root->length() == 0)
        {
            log_errorln("List is empty", root);
            return nullptr;
        }

        node_ptr op_node = root->get(0);
        if (op_node == nullptr)
        {
            log_errorln("Cannot evaluate empty list.");
            return nullptr;
        }

        node_ptr proc_node = op_node;
        procedure_ptr proc = proc_node->proc;

        if (proc == nullptr && op_node->type == node_type::pair)
        {
            node_ptr eval_node = eval(ctx, op_node);
            if (eval_node == nullptr || eval_node->proc == nullptr)
            {
                log_errorln("Error: first argument is not a procedure", root);
                return nullptr;
            }
            proc_node = eval_node;
            proc = eval_node->proc;
        }
        else
        {
            // Look in environment
            node_ptr val = ctx.active_env->lookup_variable(op_node->value);
            if (val != nullptr && val->proc != nullptr)
            {
                proc_node = val;
                proc = val->proc;
                if (proc != nullptr && proc->is_native)
                {
                    return proc->native_func(ctx, root);
                }
            }
        }

        if (proc != nullptr)
        {
            return apply(ctx, root->cdr, proc_node);
        }

        log_errorln("Operator is not a procedure: ", op_node);

        return nullptr;
    }

    slist::node_ptr eval_name(slist::context& ctx, const slist::node_ptr& root)
    {
        using namespace slist;
        auto var_node = ctx.active_env->lookup_variable(root->value);
        if (var_node == nullptr)
        {
            log_errorln("Could not evaluate variable: ", root);
            return nullptr;
        }
        return var_node;
    }
}<|endoftext|>


<commit_before>//  illarionserver - server for the game Illarion
//  Copyright 2011 Illarion e.V.
//
//  This file is part of illarionserver.
//
//  illarionserver is free software: you can redistribute it and/or modify
//  it under the terms of the GNU Affero General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  illarionserver 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 Affero General Public License for more details.
//
//  You should have received a copy of the GNU Affero General Public License
//  along with illarionserver.  If not, see <http://www.gnu.org/licenses/>.

#include "WaypointList.hpp"
#include "World.hpp"
#include "Field.hpp"
#include "Logger.hpp"

WaypointList::WaypointList(Character *movechar) : _movechar(movechar) {

}

const std::list<position> &WaypointList::getWaypoints() const {
    return positions;
}

void WaypointList::addWaypoint(const position &pos) {
    positions.push_back(pos);
}

bool WaypointList::getNextWaypoint(position &pos) const {
    if (positions.empty()) {
        return false;
    }

    pos = positions.front();
    return true;
}

void WaypointList::clear() {
    positions.clear();
}

bool WaypointList::checkPosition() {
    if (positions.empty()) {
        return false;
    }

    if (_movechar->getPosition() == positions.front()) {
        positions.pop_front();
    }

    return true;
}

bool WaypointList::recalcStepList() {
    if (!checkPosition()) {
        return false;
    }

    steplist.clear();
    _movechar->getStepList(positions.front(), steplist);
    return (!steplist.empty());
}

bool WaypointList::makeMove() {
    if (steplist.empty()) {
        if (!recalcStepList()) {
            return false;
        }
    }

    if (!_movechar->move(steplist.front())) {
        return recalcStepList();
    }

    steplist.pop_front();
    return true;
}
<commit_msg>Calc steps only if waypoint exists<commit_after>//  illarionserver - server for the game Illarion
//  Copyright 2011 Illarion e.V.
//
//  This file is part of illarionserver.
//
//  illarionserver is free software: you can redistribute it and/or modify
//  it under the terms of the GNU Affero General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  illarionserver 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 Affero General Public License for more details.
//
//  You should have received a copy of the GNU Affero General Public License
//  along with illarionserver.  If not, see <http://www.gnu.org/licenses/>.

#include "WaypointList.hpp"
#include "World.hpp"
#include "Field.hpp"
#include "Logger.hpp"

WaypointList::WaypointList(Character *movechar) : _movechar(movechar) {

}

const std::list<position> &WaypointList::getWaypoints() const {
    return positions;
}

void WaypointList::addWaypoint(const position &pos) {
    positions.push_back(pos);
}

bool WaypointList::getNextWaypoint(position &pos) const {
    if (positions.empty()) {
        return false;
    }

    pos = positions.front();
    return true;
}

void WaypointList::clear() {
    positions.clear();
}

bool WaypointList::checkPosition() {
    if (positions.empty()) {
        return false;
    }

    if (_movechar->getPosition() == positions.front()) {
        positions.pop_front();
    }

    return true;
}

bool WaypointList::recalcStepList() {
    if (!checkPosition()) {
        return false;
    }

    if (positions.empty()) {
        return false;
    }

    steplist.clear();
    _movechar->getStepList(positions.front(), steplist);
    return (!steplist.empty());
}

bool WaypointList::makeMove() {
    if (steplist.empty()) {
        if (!recalcStepList()) {
            return false;
        }
    }

    if (!_movechar->move(steplist.front())) {
        return recalcStepList();
    }

    steplist.pop_front();
    return true;
}
<|endoftext|>


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

#include "lpformat-consistency.hpp"
#include "lpformat-io.hpp"
#include "mitm.hpp"

#include <algorithm>
#include <fstream>
#include <lpcore>

#ifdef __unix__
#include <unistd.h>
#endif

namespace lp {

class standard_stream_logger : public context::logger
{
public:
    void write(int priority,
               const char* file,
               int line,
               const char* fn,
               const char* format,
               va_list args) noexcept override
    {
        if (priority > 5)
            vfprintf(stdout, format, args);
        else {
            fprintf(stderr,
                    "lp: %d at %d in function '%s' from file %s: ",
                    priority,
                    line,
                    fn,
                    file);
            vfprintf(stderr, format, args);
        }
    }

    void write(lp::context::message_type m,
               const char* format,
               va_list args) noexcept override
    {
#ifdef __unix__
        if (::isatty(STDOUT_FILENO)) {
            switch (m) {
            case context::message_type::emerg:
            case context::message_type::alert:
            case context::message_type::crit:
            case context::message_type::err:
                ::puts("\033[30m\033[2m");
                break;
            case context::message_type::warning:
                ::puts("\033[32m\033[1m");
                break;
            case context::message_type::notice:
                break;
            case context::message_type::info:
                break;
            case context::message_type::debug:
                ::puts("\033[33m\033[1m");
                break;
            }

            vfprintf(stdout, format, args);

            switch (m) {
            case context::message_type::emerg:
            case context::message_type::alert:
            case context::message_type::crit:
            case context::message_type::err:
                ::puts("\033[30m\033[0m");
                break;
            case context::message_type::warning:
                ::puts("\033[30m\033[0m");
                break;
            case context::message_type::notice:
                break;
            case context::message_type::info:
                break;
            case context::message_type::debug:
                ::puts("\033[30m\033[0m");
                break;
            }

        } else {
            vfprintf(stdout, format, args);
        }
#else
        vfprintf(stdout, format, args);
#endif
    }
};

void
context::set_log_priority(int priority) noexcept
{
    m_log_priority = priority < 0 ? 0 : 7 > priority ? 7 : priority;
}

int
context::get_log_priority() const noexcept
{
    return m_log_priority;
}

void
context::set_standard_stream_logger() noexcept
{
    set_logger(std::make_unique<standard_stream_logger>());
}

void
context::set_logger(std::unique_ptr<logger> function) noexcept
{
    m_logger = std::move(function);
}

#ifndef LP_DISABLE_LOGGING
//
// Default, the logging system is active and the call to the @c log function
// are send to the logger functor. Define LP_DISABLE_LOGGING as preprocessor
// value to hide all logging message..
//
void
context::log(message_type type, const char* format, ...) noexcept
{
    if (not m_logger)
        return;

    va_list args;

    va_start(args, format);
    m_logger->write(type, format, args);
    va_end(args);
}

void
context::log(int priority,
             const char* file,
             int line,
             const char* fn,
             const char* format,
             ...) noexcept
{
    if (not m_logger)
        return;

    va_list args;

    va_start(args, format);
    m_logger->write(priority, file, line, fn, format, args);
    va_end(args);
}

void
context::info(const char* format, ...) noexcept
{
    if (not m_logger)
        return;

    va_list args;

    va_start(args, format);
    m_logger->write(context::message_type::info, format, args);
    va_end(args);
}

void
context::debug(const char* format, ...) noexcept
{
    if (not m_logger)
        return;

    va_list args;

    va_start(args, format);
    m_logger->write(context::message_type::debug, format, args);
    va_end(args);
}

void
context::warning(const char* format, ...) noexcept
{
    if (not m_logger)
        return;

    va_list args;

    va_start(args, format);
    m_logger->write(context::message_type::warning, format, args);
    va_end(args);
}

void
context::error(const char* format, ...) noexcept
{
    if (not m_logger)
        return;

    va_list args;

    va_start(args, format);
    m_logger->write(context::message_type::err, format, args);
    va_end(args);
}
#else
void
context::log(message_type, const char*, va_list)
{
}

void
context::log(int, const char*, int, const char*, const char*, va_list)
{
}

void
context::info(const char*, va_list)
{
}

void
context::warning(const char*, va_list)
{
}

void
context::debug(const char*, va_list)
{
}

void
context::error(const char*, va_list)
{
}
#endif

problem
make_problem(std::shared_ptr<lp::context> ctx, const std::string& filename)
{
    ctx->info("problem read from file `%s'\n", filename.c_str());

    std::ifstream ifs;
    ifs.exceptions(std::ifstream::badbit);
    ifs.open(filename);

    return details::read_problem(ifs);
}

problem
make_problem(std::shared_ptr<lp::context> ctx, std::istream& is)
{
    ctx->info("problem read from stream\n");

    is.exceptions(std::ifstream::badbit);

    return details::read_problem(is);
}

std::ostream&
operator<<(std::ostream& os, const problem& p)
{
    details::problem_writer pw(p, os);

    return os;
}

result
solve(std::shared_ptr<lp::context> ctx, problem& pb)
{
    check(pb);

    std::map<std::string, parameter> params;

    return mitm_solve(ctx, pb, params);
}

result
solve(std::shared_ptr<lp::context> ctx,
      problem& pb,
      const std::map<std::string, parameter>& params)
{
    check(pb);

    return mitm_solve(ctx, pb, params);
}

result
optimize(std::shared_ptr<lp::context> ctx,
         problem& pb,
         const std::map<std::string, parameter>& params)
{
    check(pb);

    return mitm_optimize(ctx, pb, params);
}

result
optimize(std::shared_ptr<lp::context> ctx, problem& pb)
{
    check(pb);

    std::map<std::string, parameter> params;

    return mitm_optimize(ctx, pb, params);
}

template <typename functionT, typename variablesT>
int
compute_function(const functionT& fct, const variablesT& vars) noexcept
{
    int v{ 0 };

    for (auto& f : fct)
        v += f.factor * vars[f.variable_index];

    return v;
}

bool
is_valid_solution(const problem& pb, const std::vector<int>& variable_value)
{
    Expects(not variable_value.empty(), "variables vector empty");

    for (auto& cst : pb.equal_constraints) {
        if (compute_function(cst.elements, variable_value) != cst.value) {
            printf("constraint %s (=) fails\n", cst.label.c_str());
            return false;
        }
    }

    for (auto& cst : pb.greater_constraints) {
        if (compute_function(cst.elements, variable_value) <= cst.value) {
            printf("constraint %s (>) fails\n", cst.label.c_str());
            return false;
        }
    }

    for (auto& cst : pb.greater_equal_constraints) {
        if (compute_function(cst.elements, variable_value) < cst.value) {
            printf("constraint %s (>=) fails\n", cst.label.c_str());
            return false;
        }
    }

    for (auto& cst : pb.less_constraints) {
        if (compute_function(cst.elements, variable_value) >= cst.value) {
            printf("constraint %s (<) fails\n", cst.label.c_str());
            return false;
        }
    }

    for (auto& cst : pb.greater_constraints) {
        if (compute_function(cst.elements, variable_value) > cst.value) {
            printf("constraint %s (<=) fails\n", cst.label.c_str());
            return false;
        }
    }

    return true;
}

double
compute_solution(const problem& pb, const std::vector<int>& variable_value)
{
    Expects(not variable_value.empty(), "variables vector empty");

    double ret = pb.objective.constant;

    for (auto& elem : pb.objective.elements)
        ret += elem.factor * variable_value[elem.variable_index];

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

#include "lpformat-consistency.hpp"
#include "lpformat-io.hpp"
#include "mitm.hpp"

#include <algorithm>
#include <fstream>
#include <lpcore>

#ifdef __unix__
#include <unistd.h>
#endif

namespace lp {

class standard_stream_logger : public context::logger
{
public:
    void write(int priority,
               const char* file,
               int line,
               const char* fn,
               const char* format,
               va_list args) noexcept override
    {
        if (priority > 5)
            vfprintf(stdout, format, args);
        else {
            fprintf(stderr,
                    "lp: %d at %d in function '%s' from file %s: ",
                    priority,
                    line,
                    fn,
                    file);
            vfprintf(stderr, format, args);
        }
    }

    void write(lp::context::message_type m,
               const char* format,
               va_list args) noexcept override
    {
#ifdef __unix__
        if (::isatty(STDOUT_FILENO)) {
            switch (m) {
            case context::message_type::emerg:
            case context::message_type::alert:
            case context::message_type::crit:
            case context::message_type::err:
                ::puts("\033[30m\033[2m");
                break;
            case context::message_type::warning:
                ::puts("\033[32m\033[1m");
                break;
            case context::message_type::notice:
                break;
            case context::message_type::info:
                break;
            case context::message_type::debug:
                ::puts("\033[33m\033[1m");
                break;
            }

            vfprintf(stdout, format, args);

            switch (m) {
            case context::message_type::emerg:
            case context::message_type::alert:
            case context::message_type::crit:
            case context::message_type::err:
                ::puts("\033[30m\033[0m");
                break;
            case context::message_type::warning:
                ::puts("\033[30m\033[0m");
                break;
            case context::message_type::notice:
                break;
            case context::message_type::info:
                break;
            case context::message_type::debug:
                ::puts("\033[30m\033[0m");
                break;
            }

        } else {
            vfprintf(stdout, format, args);
        }
#else
        vfprintf(stdout, format, args);
#endif
    }
};

void
context::set_log_priority(int priority) noexcept
{
    m_log_priority = priority < 0 ? 0 : 7 < priority ? 7 : priority;
}

int
context::get_log_priority() const noexcept
{
    return m_log_priority;
}

void
context::set_standard_stream_logger() noexcept
{
    set_logger(std::make_unique<standard_stream_logger>());
}

void
context::set_logger(std::unique_ptr<logger> function) noexcept
{
    m_logger = std::move(function);
}

#ifndef LP_DISABLE_LOGGING
//
// Default, the logging system is active and the call to the @c log function
// are send to the logger functor. Define LP_DISABLE_LOGGING as preprocessor
// value to hide all logging message..
//
void
context::log(message_type type, const char* format, ...) noexcept
{
    if (not m_logger)
        return;

    switch (type) {
    case lp::context::message_type::emerg:
        break;
    case lp::context::message_type::alert:
        if (m_log_priority < 1)
            return;
        break;
    case lp::context::message_type::crit:
        if (m_log_priority < 2)
            return;
        break;
    case lp::context::message_type::err:
        if (m_log_priority < 3)
            return;
        break;
    case lp::context::message_type::warning:
        if (m_log_priority < 4)
            return;
        break;
    case lp::context::message_type::notice:
        if (m_log_priority < 5)
            return;
        break;
    case lp::context::message_type::info:
        if (m_log_priority < 6)
            return;
        break;
    case lp::context::message_type::debug:
        if (m_log_priority < 7)
            return;
        break;
    }

    va_list args;

    va_start(args, format);
    m_logger->write(type, format, args);
    va_end(args);
}

void
context::log(int priority,
             const char* file,
             int line,
             const char* fn,
             const char* format,
             ...) noexcept
{
    if (not m_logger and m_log_priority < priority)
        return;

    va_list args;

    va_start(args, format);
    m_logger->write(priority, file, line, fn, format, args);
    va_end(args);
}

void
context::info(const char* format, ...) noexcept
{
    if (not m_logger or m_log_priority < 6)
        return;

    va_list args;

    va_start(args, format);
    m_logger->write(context::message_type::info, format, args);
    va_end(args);
}

void
context::debug(const char* format, ...) noexcept
{
    if (not m_logger or m_log_priority < 7)
        return;

    va_list args;

    va_start(args, format);
    m_logger->write(context::message_type::debug, format, args);
    va_end(args);
}

void
context::warning(const char* format, ...) noexcept
{
    if (not m_logger and m_log_priority < 4)
        return;

    va_list args;

    va_start(args, format);
    m_logger->write(context::message_type::warning, format, args);
    va_end(args);
}

void
context::error(const char* format, ...) noexcept
{
    if (not m_logger and m_log_priority < 3)
        return;

    va_list args;

    va_start(args, format);
    m_logger->write(context::message_type::err, format, args);
    va_end(args);
}
#else
void
context::log(message_type, const char*, va_list)
{
}

void
context::log(int, const char*, int, const char*, const char*, va_list)
{
}

void
context::info(const char*, va_list)
{
}

void
context::warning(const char*, va_list)
{
}

void
context::debug(const char*, va_list)
{
}

void
context::error(const char*, va_list)
{
}
#endif

problem
make_problem(std::shared_ptr<lp::context> ctx, const std::string& filename)
{
    ctx->info("problem read from file `%s'\n", filename.c_str());

    std::ifstream ifs;
    ifs.exceptions(std::ifstream::badbit);
    ifs.open(filename);

    return details::read_problem(ifs);
}

problem
make_problem(std::shared_ptr<lp::context> ctx, std::istream& is)
{
    ctx->info("problem read from stream\n");

    is.exceptions(std::ifstream::badbit);

    return details::read_problem(is);
}

std::ostream&
operator<<(std::ostream& os, const problem& p)
{
    details::problem_writer pw(p, os);

    return os;
}

result
solve(std::shared_ptr<lp::context> ctx, problem& pb)
{
    check(pb);

    std::map<std::string, parameter> params;

    return mitm_solve(ctx, pb, params);
}

result
solve(std::shared_ptr<lp::context> ctx,
      problem& pb,
      const std::map<std::string, parameter>& params)
{
    check(pb);

    return mitm_solve(ctx, pb, params);
}

result
optimize(std::shared_ptr<lp::context> ctx,
         problem& pb,
         const std::map<std::string, parameter>& params)
{
    check(pb);

    return mitm_optimize(ctx, pb, params);
}

result
optimize(std::shared_ptr<lp::context> ctx, problem& pb)
{
    check(pb);

    std::map<std::string, parameter> params;

    return mitm_optimize(ctx, pb, params);
}

template <typename functionT, typename variablesT>
int
compute_function(const functionT& fct, const variablesT& vars) noexcept
{
    int v{ 0 };

    for (auto& f : fct)
        v += f.factor * vars[f.variable_index];

    return v;
}

bool
is_valid_solution(const problem& pb, const std::vector<int>& variable_value)
{
    Expects(not variable_value.empty(), "variables vector empty");

    for (auto& cst : pb.equal_constraints) {
        if (compute_function(cst.elements, variable_value) != cst.value) {
            printf("constraint %s (=) fails\n", cst.label.c_str());
            return false;
        }
    }

    for (auto& cst : pb.greater_constraints) {
        if (compute_function(cst.elements, variable_value) <= cst.value) {
            printf("constraint %s (>) fails\n", cst.label.c_str());
            return false;
        }
    }

    for (auto& cst : pb.greater_equal_constraints) {
        if (compute_function(cst.elements, variable_value) < cst.value) {
            printf("constraint %s (>=) fails\n", cst.label.c_str());
            return false;
        }
    }

    for (auto& cst : pb.less_constraints) {
        if (compute_function(cst.elements, variable_value) >= cst.value) {
            printf("constraint %s (<) fails\n", cst.label.c_str());
            return false;
        }
    }

    for (auto& cst : pb.greater_constraints) {
        if (compute_function(cst.elements, variable_value) > cst.value) {
            printf("constraint %s (<=) fails\n", cst.label.c_str());
            return false;
        }
    }

    return true;
}

double
compute_solution(const problem& pb, const std::vector<int>& variable_value)
{
    Expects(not variable_value.empty(), "variables vector empty");

    double ret = pb.objective.constant;

    for (auto& elem : pb.objective.elements)
        ret += elem.factor * variable_value[elem.variable_index];

    return ret;
}
}
<|endoftext|>


<commit_before>/*
 * aa_aafapprox.cpp -- Standart non-affine operations
 * Copyright (c) 2003 EPFL (Ecole Polytechnique Federale de Lausanne)
 * Copyright (c) 2004 LIRIS (University Claude Bernard Lyon 1)
 * Copyright (c) 2005 Nathan Hurst
 *
 * This file is part of libaa.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with libaa; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "aa.h"
#include <algorithm>
#include <cmath>

#include "aa_util.h"

// Operator  *

AAF AAF::operator * (const AAF & P) const {
    unsigned l1 = length;
    unsigned l2 = P.length;

    unsigned * id1 = indexes;
    unsigned * id2 = P.indexes;

    double * va1 = coefficients;
    double * va2 = P.coefficients;

    unsigned * pu1 = id1;
    unsigned * pu2 = id2;

    AAF Temp(cvalue*P.cvalue);  // Create our resulting AAF

    Temp.indexes = new unsigned [l1+l2+1];
    unsigned * idtemp=Temp.indexes;

    // Fill the indexes array

    unsigned * fin = std::set_union(id1,id1+l1,id2,id2+l2,idtemp);
    unsigned ltemp=fin-idtemp;

    Temp.coefficients = new double [ltemp+1];
    double * vatempg=Temp.coefficients;

    Temp.length = ltemp+1;

    // Fill the coefficients array

    for (unsigned i = 0; i < ltemp; i++)
    {
        unsigned a = pu1-id1;
        unsigned b = pu2-id2;

        if (a==l1 || id1[a]!=idtemp[i])
	{
            vatempg[i] = cvalue*va2[b];  // cvalue*va2[b]+(P.cvalue)*0
            pu2++;
            continue;
	}

        if (b==l2 || id2[b]!=idtemp[i])
	{
            vatempg[i] = (P.cvalue)*va1[a];  // cvalue*0+(P.cvalue)*va1[a]
            pu1++;
            continue;
	}

        vatempg[i] = cvalue*va2[b] + (P.cvalue)*va1[a];
        pu1++;
        pu2++;
    }

    // Compute the error
    // in a new noise symbol

    Temp.indexes[ltemp]=inclast();
    Temp.coefficients[ltemp]=rad()*(P.rad());

    Temp.special = binary_special(special, P.special);

    return Temp;

}

// Operator  /
// It's a non affine-operation
// We use the identity x/y = x * (1/y

AAF AAF::operator / (const AAF & P) const {
    return (*this)*inv(P);
}

// Square root operator
// It's a non affine-operation
// We use the Chebyshev approximation

AAF sqrt(const AAF & P) {
    handle_infinity(P);
    // sqrt(x) is approximated by f(x)=alpha*x+dzeta
    // delta is the maximum absolute error

    const double a = P.convert().left(); // [a,b] is our interval
    const double b = P.convert().right();
    AAF_TYPE type;
    if(a >= 0)
        type = AAF_TYPE_AFFINE;
    else if(b < 0)
        type = AAF_TYPE_NAN;
    else if(a < 0) // undefined, can we do better?
        type = (AAF_TYPE)(AAF_TYPE_AFFINE | AAF_TYPE_NAN);
    //type = (AAF_TYPE)(type | P.special);

    const double t = (sqrt(a)+sqrt(b));

    const double alpha = 1/t; // alpha is the slope of the line r(x) that
    // interpolate (a, sqrt(a)) and (b, f(b))

    // dzeta calculation:
    const double dzeta = (t/8)+0.5*(sqrt(a*b))/t;

    // Calculation of the error
    const double rdelta = (sqrt(b)-sqrt(a));
    const double delta = rdelta*rdelta/(8*t);

    return AAF(P, alpha, dzeta, delta, type);
}

// Inverse (1/x) operator
// It's a non-affine operation
// We use mini-range approximation
// cause undershoot can be high with Chebyshev here

AAF inv(const AAF & P) {
    handle_infinity(P);
    double a = P.convert().left();
    double b = P.convert().right();
    if(P.is_infinite() || (a <= 0) && (b >= 0)) {
        return AAF(interval(-INFINITY, INFINITY));
    }

    // a := min(abs(a), abs(b))
    // b := max(abs(a), abs(b))

    const double t1 = fabs(a);
    const double t2 = fabs(b);

    a= t1 <? t2;  // min(t1,t2)
    b= t1 >? t2;  // max(t1,t2)

    // Derivative of 1/x is -1/x*x

    const double alpha=-1/(b*b);

    interval i((1/a)-alpha*a, 2/b);//-alpha*b);
    double dzeta = i.mid();

    if ((P.convert().left()) < 0) dzeta = -dzeta;

    return AAF(P, alpha, dzeta, i.radius(), P.special);
}

AAF abs(const AAF & P) {
    if(P.strictly_neg())
        return -P;
    if(P.straddles_zero()) {
        AAF Temp(P);
        Temp.cvalue = fabs(Temp.cvalue)/2;
        Temp.special = P.special;

        for (unsigned i=0; i<P.length; i++)
            Temp.coefficients[i]=(Temp.coefficients[i])/2;
        return Temp;
    }
    return P;
}

AAF sqr(const AAF & P) {
    return P*P;
}

// Power function
// only for integer exponents

AAF pow(const AAF & P, int exp) {
    handle_infinity(P);
    if (exp == 0) {
        return 1;
    } else if (exp > 0) {
        if(exp & 1)
            return sqr(pow(P, exp>>1))*P;
        else
            return sqr(pow(P, exp>>1));
    } else {
        return inv(pow(P, -exp));
    }
}

AAF pow(const AAF & P, double xp) {
    return exp(xp*log(P));
}

// Exponential operator
// It's a non affine-operation

AAF exp(const AAF & P) {
    handle_infinity(P); // infinity maps to [0, infty) here
    // exp(x) is approximated by f(x)=alpha*x+dzeta
    // delta is the maximum absolute error

    const double a = P.convert().left(); // [a,b] is our interval
    const double b = P.convert().right();

    const double ea = exp(a);
    const double eb = exp(b);
    if(ea == INFINITY) {
        printf("infinity at %g, %g -> (%g, %g)\n", a, b, ea, eb);
    }

    const double alpha = (eb-ea)/(b-a);
// alpha is the slope of the line r(x) that
    // interpolate (a, exp(a)) and (b, exp(b))
    const double xs = log(alpha);// the x of the maximum error
    const double maxdelta = alpha*(xs - 1 - a)+ea;

    // dzeta calculation:
    const double dzeta = alpha*(1 - xs);

    // Calculation of the error
    const double delta = maxdelta/2;
    //printf("(%g, %g, %g) -> (%g, %g) @ (%g*x + %g) e = %g\n", a, xs, b, ea, eb, alpha, dzeta, delta);

    return AAF(P, alpha, dzeta, delta, P.special);
}

// Exponential operator
// It's a non affine-operation

AAF log(const AAF & P) {
    handle_infinity(P); // infinity maps to [0, infty) here
    // exp(x) is approximated by f(x)=alpha*x+dzeta
    // delta is the maximum absolute error

    const double a = P.convert().left(); // [a,b] is our interval
    const double b = P.convert().right();

    AAF_TYPE type;
    if(a > 0)
        type = AAF_TYPE_AFFINE;
    else if(b < 0) { // no point in continuing
        type = AAF_TYPE_NAN;
        return AAF(type);
    }
    else if(a <= 0) {// undefined, can we do better?
        type = (AAF_TYPE)(AAF_TYPE_AFFINE | AAF_TYPE_NAN);
        return AAF(type);
// perhaps we should make a = 0+eps and try to continue?
    }

    const double la = log(a);
    const double lb = log(b);

    const double alpha = (lb-la)/(b-a);
// alpha is the slope of the line r(x) that
    // interpolate (a, exp(a)) and (b, exp(b))
    const double xs = 1/(alpha);// the x of the maximum error
    const double ys = (alpha*(xs - a)+la);
    const double maxdelta = log(xs) - ys;

    // dzeta calculation:
    const double dzeta = alpha*(-xs)+(log(xs)+ys)/2;

    // Calculation of the error
    const double delta = maxdelta/2;
    //printf("(%g, %g, %g) -> (%g, %g, %g) @ (%g*x + %g) e = %g\n", a, xs, b, la, log(xs), lb, alpha, dzeta, delta);
    //printf("plot [%g:%g] log(x), (%g*x + %g)\n", a, b, alpha, dzeta);

    return AAF(P, alpha, dzeta, delta, type);
}

/*
  Local Variables:
  mode:c++
  c-file-style:"stroustrup"
  c-file-offsets:((innamespace . 0)(inline-open . 0))
  indent-tabs-mode:nil
  fill-column:99
  End:
*/

// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
<commit_msg>tidy up<commit_after>/*
 * aa_aafapprox.cpp -- Standart non-affine operations
 * Copyright (c) 2003 EPFL (Ecole Polytechnique Federale de Lausanne)
 * Copyright (c) 2004 LIRIS (University Claude Bernard Lyon 1)
 * Copyright (c) 2005 Nathan Hurst
 *
 * This file is part of libaa.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with libaa; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "aa.h"
#include <algorithm>
#include <cmath>

#include "aa_util.h"

// Operator  *

AAF AAF::operator * (const AAF & P) const {
    unsigned l1 = length;
    unsigned l2 = P.length;

    unsigned * id1 = indexes;
    unsigned * id2 = P.indexes;

    double * va1 = coefficients;
    double * va2 = P.coefficients;

    unsigned * pu1 = id1;
    unsigned * pu2 = id2;

    AAF Temp(cvalue*P.cvalue);  // Create our resulting AAF

    Temp.indexes = new unsigned [l1+l2+1];
    unsigned * idtemp=Temp.indexes;

    // Fill the indexes array

    unsigned * fin = std::set_union(id1,id1+l1,id2,id2+l2,idtemp);
    unsigned ltemp=fin-idtemp;

    Temp.coefficients = new double [ltemp+1];
    double * vatempg=Temp.coefficients;

    Temp.length = ltemp+1;

    // Fill the coefficients array

    for (unsigned i = 0; i < ltemp; i++)
    {
        unsigned a = pu1-id1;
        unsigned b = pu2-id2;

        if (a==l1 || id1[a]!=idtemp[i])
	{
            vatempg[i] = cvalue*va2[b];  // cvalue*va2[b]+(P.cvalue)*0
            pu2++;
            continue;
	}

        if (b==l2 || id2[b]!=idtemp[i])
	{
            vatempg[i] = (P.cvalue)*va1[a];  // cvalue*0+(P.cvalue)*va1[a]
            pu1++;
            continue;
	}

        vatempg[i] = cvalue*va2[b] + (P.cvalue)*va1[a];
        pu1++;
        pu2++;
    }

    // Compute the error
    // in a new noise symbol

    Temp.indexes[ltemp]=inclast();
    Temp.coefficients[ltemp]=rad()*(P.rad());

    Temp.special = binary_special(special, P.special);

    return Temp;

}

// Operator  /
// It's a non affine-operation
// We use the identity x/y = x * (1/y)

AAF AAF::operator / (const AAF & P) const {
    return (*this)*inv(P);
}

// Square root operator
// It's a non affine-operation
// We use the Chebyshev approximation

AAF sqrt(const AAF & P) {
    handle_infinity(P);
    // sqrt(x) is approximated by f(x)=alpha*x+dzeta
    // delta is the maximum absolute error

    const double a = P.convert().left(); // [a,b] is our interval
    const double b = P.convert().right();
    AAF_TYPE type;
    if(a >= 0)
        type = AAF_TYPE_AFFINE;
    else if(b < 0)
        type = AAF_TYPE_NAN;
    else if(a < 0) // undefined, can we do better?
        type = (AAF_TYPE)(AAF_TYPE_AFFINE | AAF_TYPE_NAN);
    //type = (AAF_TYPE)(type | P.special);

    const double t = (sqrt(a)+sqrt(b));

    const double alpha = 1/t; // alpha is the slope of the line r(x) that
    // interpolate (a, sqrt(a)) and (b, f(b))

    // dzeta calculation:
    const double dzeta = (t/8)+0.5*(sqrt(a*b))/t;

    // Calculation of the error
    const double rdelta = (sqrt(b)-sqrt(a));
    const double delta = rdelta*rdelta/(8*t);

    return AAF(P, alpha, dzeta, delta, type);
}

// Inverse (1/x) operator
// It's a non-affine operation
// We use mini-range approximation
// because undershoot can be high with Chebyshev here

AAF inv(const AAF & P) {
    handle_infinity(P);
    double a = P.convert().left();
    double b = P.convert().right();
    if(P.is_infinite() || (a <= 0) && (b >= 0)) {
        return AAF(interval(-INFINITY, INFINITY));
    }

    // a := min(abs(a), abs(b))
    // b := max(abs(a), abs(b))

    const double t1 = fabs(a);
    const double t2 = fabs(b);

    a= t1 <? t2;  // min(t1,t2)
    b= t1 >? t2;  // max(t1,t2)

    // Derivative of 1/x is -1/x*x

    const double alpha=-1/(b*b);

    interval i((1/a)-alpha*a, 2/b);//-alpha*b);
    double dzeta = i.mid();

    if ((P.convert().left()) < 0) dzeta = -dzeta;

    return AAF(P, alpha, dzeta, i.radius(), P.special);
}

AAF abs(const AAF & P) {
    if(P.strictly_neg())
        return -P;
    if(P.straddles_zero()) {
        AAF Temp(P);
        Temp.cvalue = fabs(Temp.cvalue)/2;
        Temp.special = P.special;

        for (unsigned i=0; i<P.length; i++)
            Temp.coefficients[i]=(Temp.coefficients[i])/2;
        return Temp;
    }
    return P;
}

AAF sqr(const AAF & P) {
    return P*P;
}

// Power function
// only for integer exponents

AAF pow(const AAF & P, int exp) {
    handle_infinity(P);
    if (exp == 0) {
        return 1;
    } else if (exp > 0) {
        if(exp & 1)
            return sqr(pow(P, exp>>1))*P;
        else
            return sqr(pow(P, exp>>1));
    } else {
        return inv(pow(P, -exp));
    }
}

AAF pow(const AAF & P, double xp) {
    return exp(xp*log(P));
}

// Exponential operator
// It's a non affine-operation

AAF exp(const AAF & P) {
    handle_infinity(P); // infinity maps to [0, infty) here
    // exp(x) is approximated by f(x)=alpha*x+dzeta
    // delta is the maximum absolute error

    const double a = P.convert().left(); // [a,b] is our interval
    const double b = P.convert().right();

    const double ea = exp(a);
    const double eb = exp(b);
    if((ea == INFINITY) || (eb == INFINITY)) {
        // Printing from a numeric library is generally frowned apon,
        // but what to do instead?  This corresponds to an essential
        // singularity.
        //printf("essential infinity at %g, %g -> (%g, %g)\n", a, b, ea, eb);
        return AAF(interval(-INFINITY, INFINITY));
    }

    const double alpha = (eb-ea)/(b-a);
    // alpha is the slope of the line r(x) that
    // interpolate (a, exp(a)) and (b, exp(b))
    const double xs = log(alpha);// the x of the maximum error
    const double maxdelta = alpha*(xs - 1 - a)+ea;

    // dzeta calculation:
    const double dzeta = alpha*(1 - xs);

    // Calculation of the error
    const double delta = maxdelta/2;

    return AAF(P, alpha, dzeta, delta, P.special);
}

// Logarithm operator
// It's a non affine-operation

AAF log(const AAF & P) {
    handle_infinity(P); // infinity needs to map to NaN here

    const double a = P.convert().left(); // [a,b] is our interval
    const double b = P.convert().right();

    AAF_TYPE type;
    if(a > 0)
        type = AAF_TYPE_AFFINE;
    else if(b < 0) { // no point in continuing
        type = AAF_TYPE_NAN;
        return AAF(type);
    }
    else if(a <= 0) { // undefined, can we do better?
        type = (AAF_TYPE)(AAF_TYPE_AFFINE | AAF_TYPE_NAN);
        return AAF(type);
        // perhaps we should make a = 0+eps and try to continue?
    }

    const double la = log(a);
    const double lb = log(b);

    const double alpha = (lb-la)/(b-a);
    // alpha is the slope of the line r(x) that
    // interpolate (a, exp(a)) and (b, exp(b))
    const double xs = 1/(alpha);// the x of the maximum error
    const double ys = (alpha*(xs - a)+la);
    const double maxdelta = log(xs) - ys;

    // dzeta calculation:
    const double dzeta = alpha*(-xs)+(log(xs)+ys)/2;

    // Calculation of the error
    const double delta = maxdelta/2;

    return AAF(P, alpha, dzeta, delta, type);
}

/*
  Local Variables:
  mode:c++
  c-file-style:"stroustrup"
  c-file-offsets:((innamespace . 0)(inline-open . 0))
  indent-tabs-mode:nil
  fill-column:80
  End:
*/

// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
<|endoftext|>