/////////////////////////////////////////////////////////////////////////
///@file datetime.cpp
///@brief	日期时间处理工具
///@copyright	上海信易信息科技股份有限公司 版权所有
/////////////////////////////////////////////////////////////////////////

#include "datetime.h"
#include <stdlib.h>
#include <stdio.h>
#include <cassert>
#include <algorithm>
#include <vector>

#include <boost/algorithm/string.hpp>

static const long _DAYS_IN_MONTH[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
static const long _DAYS_BEFORE_MONTH[13] = {0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
static const long MINYEAR = 1;
static const long MAXYEAR = 9999;
static const long _DI400Y = 146097;//    # number of days in 400 years
static const long _DI100Y = 36524;//    #    "    "   "   " 100   "
static const long _DI4Y   = 1461;//      #    "    "   "   "   4   "

void divmod_long(long x, long y, long* divv, long* mod)
{
    *mod = x % y;
    *divv = x / y;
    if (*mod < 0) {
        (*mod) += y;
        (*divv)--;
    }
}
void divmod_longlong(long long x, long long y, long long* div, long long* mod)
{
    *mod = x % y;
    *div = x / y;
    if (*mod < 0) {
        (*mod) += y;
        (*div)--;
    }
}
BOOL _is_leap(long year)
{
    //"year -> 1 if leap year, else 0."
    return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
}

long _days_before_year(long year)
{
    //"year -> number of days before January 1st of year."
    long y = year - 1;
    return y * 365 + y / 4 - y / 100 + y / 400;
}

long _days_in_month(long year, long month)
{
    //"year, month -> number of days in that month in that year."
    assert (1 <= month && month <= 12);
    if (month == 2 && _is_leap(year)) {
        return 29;
    }
    return _DAYS_IN_MONTH[month];
}

long _days_before_month(long year, long month)
{
    //"year, month -> number of days in year preceeding first day of month."
    assert (1 <= month && month <= 12);
    return _DAYS_BEFORE_MONTH[month] + (month > 2 && _is_leap(year) ? 1 : 0);
}

long _ymd2ord(long year, long month, long day)
{
    //"year, month, day -> ordinal, considering 01-Jan-0001 as day 1."
    long dim;
    assert (1 <= month && month <= 12);
    dim = _days_in_month(year, month);
    assert (1 <= day && day <= dim);
    return (_days_before_year(year) +
            _days_before_month(year, month) +
            day);
}

//# A 4-year cycle has an extra leap day over what we'd get from pasting
//# together 4 single years.
//	assert _DI4Y == 4 * 365 + 1
//
//# Similarly, a 400-year cycle has an extra leap day over what we'd get from
//# pasting together 4 100-year cycles.
//	assert _DI400Y == 4 * _DI100Y + 1
//
//# OTOH, a 100-year cycle has one fewer leap day than we'd get from
//# pasting together 25 4-year cycles.
//	assert _DI100Y == 25 * _DI4Y - 1
void _ord2ymd( long n, long* year, long* month, long* day )
{
    /*
    "ordinal -> (year, month, day), considering 01-Jan-0001 as day 1."

    # n is a 1-based index, starting at 1-Jan-1.  The pattern of leap years
    # repeats exactly every 400 years.  The basic strategy is to find the
    # closest 400-year boundary at or before n, then work with the offset
    # from that boundary to n.  Life is much clearer if we subtract 1 from
    # n first -- then the values of n at 400-year boundaries are exactly
    # those divisible by _DI400Y:
    #
    #     D  M   Y            n              n-1
    #     -- --- ----        ----------     ----------------
    #     31 Dec -400        -_DI400Y       -_DI400Y -1
    #      1 Jan -399         -_DI400Y +1   -_DI400Y      400-year boundary
    #     ...
    #     30 Dec  000        -1             -2
    #     31 Dec  000         0             -1
    #      1 Jan  001         1              0            400-year boundary
    #      2 Jan  001         2              1
    #      3 Jan  001         3              2
    #     ...
    #     31 Dec  400         _DI400Y        _DI400Y -1
    #      1 Jan  401         _DI400Y +1     _DI400Y      400-year boundary
    */
    long n400 = 0;
    long n100 = 0;
    long n4 = 0;
    long n1 = 0;
    long preceding = 0;
    BOOL leapyear = FALSE;
    n--;
    n400 = n / _DI400Y;
    n = n % _DI400Y;
    *year = n400 * 400 + 1;
    /*
    # Now n is the (non-negative) offset, in days, from January 1 of year, to
    # the desired date.  Now compute how many 100-year cycles precede n.
    # Note that it's possible for n100 to equal 4!  In that case 4 full
    # 100-year cycles precede the desired day, which implies the desired
    # day is December 31 at the end of a 400-year cycle.
    */
    n100 = n / _DI100Y;
    n = n % _DI100Y;
    //# Now compute how many 4-year cycles precede it.
    n4 = n / _DI4Y;
    n = n % _DI4Y;
    /*
    # And now how many single years.  Again n1 can be 4, and again meaning
    # that the desired day is December 31 at the end of the 4-year cycle.
    */
    n1 = n / 365;
    n = n % 365;
    *year += n100 * 100 + n4 * 4 + n1;
    if (n1 == 4 || n100 == 4) {
        assert (n == 0);
        (*year)--;
        *month = 12;
        *day = 31;
        return;
    }
    /*
    # Now the year is correct, and n is the offset from January 1.  We find
    # the month via an estimate that's either exact or one too large.
    */
    leapyear = (n1 == 3 && (n4 != 24 || n100 == 3));
    assert(leapyear == _is_leap(*year));
    *month = (n + 50) >> 5;
    preceding = _DAYS_BEFORE_MONTH[*month] + (*month > 2 && leapyear);
    if (preceding > n) {
        //# estimate is too large
        *month -= 1;
        preceding -= _DAYS_IN_MONTH[*month] + (*month == 2 && leapyear);
    }
    n -= preceding;
    assert (0 <= n && n < _days_in_month(*year, *month));
    /*
    # Now the year and month are correct, and n is the offset from the
    # start of that month:  we're done!
    */
    (*day) = n + 1;
}

BOOL _check_date_fields(long year, long month, long day)
{
    long dim;
    if (year < MINYEAR || year > MAXYEAR) {
        return FALSE;
    }
    if (month < 1 || month > 12) {
        return FALSE;
    }
    dim = _days_in_month(year, month);
    if ( day < 1 || day > dim) {
        return FALSE;
    }
    return TRUE;
}

BOOL _check_time_fields(long hour, long minute, long second, long microsecond)
{
    if (hour < 0 || hour > 23) {
        return FALSE;
    }
    if (minute < 0 || minute > 59) {
        return FALSE;
    }
    if (second < 0 || second > 59) {
        return FALSE;
    }
    if (microsecond < 0 || microsecond > 999999) {
        return FALSE;
    }
    return TRUE;
}

BOOL SetDate( struct Date* date, long year, long month, long day)
{
    if (!_check_date_fields(year, month, day) || !date) {
        return FALSE;
    }
    date->year = year;
    date->month = month;
    date->day = day;
    return TRUE;
}
BOOL SetTime( struct Time* targettime, long hour, long minute, long second, long microsecond)
{
    if (!_check_time_fields(hour, minute, second, microsecond) || !targettime) {
        return FALSE;
    }
    targettime->hour = hour;
    targettime->minute = minute;
    targettime->second = second;
    targettime->microsecond = microsecond;
    return TRUE;
}

BOOL SetTime2( struct Time* time, long second, long microsecond)
{
    long hour = second / 3600;
    long rem = second % 3600;
    long minute = rem / 60;
    long sec = rem % 60;
    return SetTime(time, hour, minute, sec, microsecond);
}

BOOL LongToDate(long orid, struct Date* date)
{
    long year, month, day;
    _ord2ymd(orid, &year, &month, &day);
    return SetDate(date, year, month, day);
}

BOOL LongLongToTime(long long orid, struct Time* time)
{
    time->microsecond = orid % 1000000;
    orid /= 1000000;
    time->second = orid % 60;
    orid /= 60;
    time->minute = orid % 60;
    orid /= 60;
    time->hour = (long)orid;
    if (!_check_time_fields(time->hour, time->minute, time->second, time->microsecond)) {
        return FALSE;
    }
    return TRUE;
}

BOOL DateToLong(const struct Date* date, long* n)
{
    if (!_check_date_fields(date->year, date->month, date->day)) {
        return FALSE;
    }
    *n = _ymd2ord(date->year, date->month, date->day);
    return TRUE;
}

BOOL TimeToLongLong(const struct Time* time, long long* n)
{
    *n = (((time->hour * 60 + time->minute) * 60) + time->second);
    *n = (*n) * 1000000 + time->microsecond;
    if (!_check_time_fields(time->hour, time->minute, time->second, time->microsecond)) {
        return FALSE;
    }
    return TRUE;
}

BOOL CreateTimeDelta(long days, long seconds, long long microseconds, struct TimeDelta* timedelta )
{
    if (!timedelta) {
        return FALSE;
    }
    if (microseconds != 0) {
        long long s;
        divmod_longlong(microseconds, 1000000, &s, &microseconds);
        seconds += (long)s;
    }
    if (seconds != 0) {
        long d;
        divmod_long(seconds, 24 * 3600, &d, &seconds);
        days += d;
    }
    timedelta->days = days;
    timedelta->seconds = seconds;
    timedelta->microseconds = (long)(microseconds);
    if (abs(timedelta->days) > 999999999) {
        return FALSE;
    }
    return TRUE;
}

BOOL AdjustDate( struct Date* date, const struct TimeDelta* delta )
{
    long ord;
    if (!DateToLong(date, &ord)) {
        return FALSE;
    }
    ord += delta->days;
    if (!LongToDate(ord, date)) {
        return FALSE;
    }
    return TRUE;
}

BOOL AddTimeDelta(struct TimeDelta* target, const struct TimeDelta* source)
{
    return CreateTimeDelta(
               target->days + source->days
               , target->seconds + source->seconds
               , target->microseconds + source->microseconds
               , target);
}

BOOL AdjustDateTime( struct DateTime* datetime, const struct TimeDelta* delta )
{
    long orddays;
    long long orduseconds;
    struct TimeDelta d2;
    if (!DateToLong(&datetime->date, &orddays)) {
        return FALSE;
    }
    if (!TimeToLongLong(&datetime->time, &orduseconds)) {
        return FALSE;
    }
    if (!CreateTimeDelta(orddays, 0, orduseconds, &d2)) {
        return FALSE;
    }
    if (!AddTimeDelta(&d2, delta)) {
        return FALSE;
    }
    if (!LongToDate(d2.days, &datetime->date)) {
        return FALSE;
    }
    return SetTime2(&datetime->time, d2.seconds, d2.microseconds);
}

BOOL AlignTime(struct Time* target, long hour, long minute, long second, long microsecond)
{
    long long ms = (long long)microsecond + ((((long long)hour * 60) + (long long)minute) * 60 + (long long)second) * 1000000;
    long long orign;
    if (!TimeToLongLong(target, &orign)) {
        return FALSE;
    }
    orign -= orign % ms;
    if (!LongLongToTime(orign, target)) {
        return FALSE;
    }
    return TRUE;
}

BOOL AlignDateByDays(struct Date* target, long days)
{
    //将日期向前调整到最接近的整N天
    long orign;
    if (!DateToLong(target, &orign)) {
        return FALSE;
    }
    orign -= orign % days;
    if (!LongToDate(orign, target)) {
        return FALSE;
    }
    return TRUE;
}

BOOL AlignDateToWeek(struct Date* target)
{
    //将日期向前调整到最接近的周一
    return TRUE;
}
BOOL AlignDateToMonth(struct Date* target)
{
    //将日期向前调整到最接近的月初
    return TRUE;
}
BOOL AlignDateToYear(struct Date* target)
{
    //将日期向前调整到最接近的年初
    return TRUE;
}

long CmpDateTimeGeneral(const long* s1, const long* s2, long count)
{
    long i;
    for (i = 0; i < count; i++) {
        if (*(s1 + i) > *(s2 + i)) {
            return 1;
        }
        if (*(s1 + i) < * (s2 + i)) {
            return -1;
        }
    }
    return 0;
}

long CmpDate( const struct Date* date1, const struct Date* date2 )
{
    return CmpDateTimeGeneral((long*)(date1), (long*)(date2), 3);
}

long CmpTime( const struct Time* time1, const struct Time* time2 )
{
    return CmpDateTimeGeneral((long*)(time1), (long*)(time2), 4);
}

long CmpDateTime( const struct DateTime* datetime1, const struct DateTime* datetime2 )
{
    return CmpDateTimeGeneral((long*)(datetime1), (long*)(datetime2), 7);
}

long CmpDateTimeField( const struct DateTime* datetime1, const struct DateTime* datetime2, enum DateTimeField field )
{
    switch (field) {
        case DTField_Year:
            return CmpDateTimeGeneral((long*)(datetime1), (long*)(datetime2), 1);
        case DTField_Month:
            return CmpDateTimeGeneral((long*)(datetime1), (long*)(datetime2), 2);
        case DTField_Day:
            return CmpDateTimeGeneral((long*)(datetime1), (long*)(datetime2), 3);
        case DTField_Hour:
            return CmpDateTimeGeneral((long*)(datetime1), (long*)(datetime2), 4);
        case DTField_Minute:
            return CmpDateTimeGeneral((long*)(datetime1), (long*)(datetime2), 5);
        case DTField_Second:
            return CmpDateTimeGeneral((long*)(datetime1), (long*)(datetime2), 6);
        case DTField_MicroSecond:
            return CmpDateTimeGeneral((long*)(datetime1), (long*)(datetime2), 7);
        default: {
            assert (FALSE);
            return 0;
        }
    }
}

void SetDateTimeNow( struct DateTime* datetime )
{
    time_t now = 0;
    time(&now);
    SetDateTimeFromTimeT(datetime, &now);
}

void SetDateTimeInvalid( struct DateTime* datetime )
{
    datetime->date.year = 0;
    datetime->date.month = 0;
    datetime->date.day = 0;
    datetime->time.hour = 0;
    datetime->time.minute = 0;
    datetime->time.second = 0;
    datetime->time.microsecond = 0;
}
void SetDateTimeMax( struct DateTime* datetime )
{
    datetime->date.year = 9999;
    datetime->date.month = 1;
    datetime->date.day = 1;
    datetime->time.hour = 0;
    datetime->time.minute = 0;
    datetime->time.second = 0;
    datetime->time.microsecond = 0;
}
BOOL SubDateTime( const struct DateTime* from, const struct DateTime* to, struct TimeDelta* delta )
{
    long days1, days2, secs1, secs2;
    if (!DateToLong(&from->date, &days1) || !DateToLong(&to->date, &days2)) {
        return FALSE;
    }
    secs1 = from->time.second + from->time.minute * 60 + from->time.hour * 3600;
    secs2 = to->time.second + to->time.minute * 60 + to->time.hour * 3600;
    if (!CreateTimeDelta(days2 - days1, secs2 - secs1, to->time.microsecond - from->time.microsecond, delta)) {
        return FALSE;
    }
    return TRUE;
}

long TotalSeconds( const struct TimeDelta* delta )
{
    return delta->days * 86400 + delta->seconds;
}

long long TotalMicroSeconds( const struct TimeDelta* delta )
{
    return ((long long)delta->days * 86400 + (long long)delta->seconds) * 1000000 + (long long)delta->microseconds;
}

long TotalMinutes( const struct TimeDelta* delta )
{
    return (delta->days * 86400 + delta->seconds) / 60;
}

long TotalHours( const struct TimeDelta* delta )
{
    return (delta->days * 86400 + delta->seconds) / 3600;
}

BOOL IsDateTimeValid( const struct DateTime* datetime )
{
    return _check_date_fields(datetime->date.year, datetime->date.month, datetime->date.day)
           && _check_time_fields(datetime->time.hour, datetime->time.minute, datetime->time.second, datetime->time.microsecond);
}

void SetDateTimeFromTimeT(struct DateTime* datetime, time_t* src)
{
    struct tm* p;
    p = localtime(src);
    datetime->date.year = p->tm_year + 1900;
    datetime->date.month = p->tm_mon + 1;
    datetime->date.day = p->tm_mday;
    datetime->time.hour = p->tm_hour;
    datetime->time.minute = p->tm_min;
    datetime->time.second = p->tm_sec;
    datetime->time.microsecond = 0;
}

void SetDateTimeFromEpochNano(struct DateTime* datetime, long long epoch_nano)
{
    time_t seconds = epoch_nano / 1000000000;
    SetDateTimeFromTimeT(datetime, &seconds);
    datetime->time.microsecond = (epoch_nano % 1000000000ll) / 1000;
}

void SetDateTimeFromEpochSeconds(struct DateTime* datetime,int epochSeconds)
{
	time_t seconds = epochSeconds;
	SetDateTimeFromTimeT(datetime, &seconds);
	datetime->time.microsecond = 0;
}

void SetTimeInvalid(struct Time* time )
{
    time->hour = 0xFF;
    time->minute = 0xFF;
    time->second = 0xFF;
    time->microsecond = 0xFF;
}

BOOL IsTimeValid( const struct Time* time )
{
    return _check_time_fields(time->hour, time->minute, time->second, time->microsecond);
}

#ifdef _WIN32
#define snprintf _snprintf
#endif

void DateTimeToString( char* buf, long buflen, const struct DateTime* v )
{
    snprintf(buf, buflen, "%04ld%02ld%02ld%02ld%02ld%02ld%06ld"
             , v->date.year
             , v->date.month
             , v->date.day
             , v->time.hour
             , v->time.minute
             , v->time.second
             , v->time.microsecond);
}

BOOL SetDateTime( struct DateTime* datetime, long year, long month, long day, long hour, long minute, long second, long microsecond )
{
    assert(datetime);
    if (!datetime || !_check_date_fields(year, month, day) || !_check_time_fields(hour, minute, second, microsecond)) {
        return FALSE;
    }
    datetime->date.year = year;
    datetime->date.month = month;
    datetime->date.day = day;
    datetime->time.hour = hour;
    datetime->time.minute = minute;
    datetime->time.second = second;
    datetime->time.microsecond = microsecond;
    return TRUE;
}

long GetDateWeek( const struct Date* date )
{
    long c;
    if (DateToLong(date, &c) == FALSE) {
        return -1;
    }
    return (c + 6) % 7;
}

long GetWorkdayOffset(const struct Date* fromday, const struct Date* today )
{
    long days1, days2, difday;
    long weeks, w1, w2;
    long dir = 1;
    if (CmpDate(fromday, today) > 0) {
        const struct Date* t = fromday;
        fromday = today;
        today = t;
        dir = -1;
    }
    if (!DateToLong(fromday, &days1) || !DateToLong(today, &days2)) {
        return FALSE;
    }
    difday = days2 - days1;
    weeks = difday / 7;
    difday -= weeks * 2;
    w1 = GetDateWeek(fromday);
    w2 = GetDateWeek(today);
    if (w2 > w1 && w2 >= 5) {
        if (w1 >= 5) {
            difday -= (w2 - w1);
        } else {
            difday -= (w2 - 4);
        }
    }
    if (w2 < w1) {
        if (w1 <= 5) {
            difday -= 2;
        } else if (w1 == 6) {
            difday -= 1;
        }
    }
    return difday * dir;
}

BOOL MoveDateByWorkday( struct Date* date, long workdays )
{
    long weeks;
    long leftdays;
    long weekday;
    long totaldays = 0;
    long dir = (workdays > 0);
    struct TimeDelta delta;
    if (workdays == 0) {
        return TRUE;
    }
    weekday = GetDateWeek(date);
    //先假装定位到所处周的周1或周5
    if (workdays > 0) {
        workdays += std::min(weekday, (long)4);
    } else {
        workdays -= std::min((11 - weekday) % 7, (long)4);
    }
    //整周的移动
    weeks = workdays / 5;
    leftdays = workdays % 5;
    //最后再调整
    totaldays = weeks * 7 + leftdays;
    if (dir) {
        totaldays -= weekday;
    } else {
        totaldays += ((11 - weekday) % 7);
    }
    CreateTimeDelta(totaldays, 0, 0, &delta);
    return AdjustDate(date, &delta);
}

BOOL SubTime( const struct Time* from, const struct Time* to, struct TimeDelta* delta )
{
    long secs1, secs2;
    secs1 = from->second + from->minute * 60 + from->hour * 3600;
    secs2 = to->second + to->minute * 60 + to->hour * 3600;
    if (!CreateTimeDelta(0, secs2 - secs1, to->microsecond - from->microsecond, delta)) {
        return FALSE;
    }
    return TRUE;
}

BOOL DateTimeToLongLong( const struct DateTime* datetime, long long* n )
{
    /*
    	16		4		5		5		6		6		20
    	YYYY	MM		DD		hh		mm		s		microsecond
    */
    *n = 0
         | ((long long)datetime->date.year << 46)
         | ((long long)datetime->date.month << 42)
         | ((long long)datetime->date.day << 37)
         | ((long long)datetime->time.hour << 32)
         | ((long long)datetime->time.minute << 26)
         | ((long long)datetime->time.second << 20)
         | ((long long)datetime->time.microsecond);
    return TRUE;
}

const char* DateTimeGetString(const struct DateTime* v)
{
    static char buf[10][128];
    static long c = 0;
    c = (c + 1) % 10;
    sprintf(buf[c], "%04ld/%02ld/%02ld-%02ld:%02ld:%02ld:%06ld"
            , v->date.year
            , v->date.month
            , v->date.day
            , v->time.hour
            , v->time.minute
            , v->time.second
            , v->time.microsecond);
    return buf[c];
}

long long DateTimeToEpochNano(const struct DateTime* dt)
{
    struct tm p;
    time_t t;
    long long nano;
    p.tm_year = dt->date.year - 1900;
    p.tm_mon = dt->date.month - 1;
    p.tm_mday = dt->date.day;
    p.tm_hour = dt->time.hour;
    p.tm_min = dt->time.minute;
    p.tm_sec = dt->time.second;
	p.tm_isdst = 0;
    t = mktime(&p);
    nano = (long long)t * 1000000000 + dt->time.microsecond * 1000;
    return nano;
}

int DateTimeToEpochSeconds(const DateTime& dt)
{
	struct tm p;
	time_t t;
	p.tm_year = dt.date.year - 1900;
	p.tm_mon = dt.date.month - 1;
	p.tm_mday = dt.date.day;
	p.tm_hour = dt.time.hour;
	p.tm_min = dt.time.minute;
	p.tm_sec = dt.time.second;
	p.tm_isdst = 0;
	t = mktime(&p);
	return t;
}

void GetTimeFromString(const std::string& str, Time& time)
{
	std::vector<std::string> hms;
	boost::algorithm::split(hms,str,boost::algorithm::is_any_of(":"));
	if (hms.size() != 3)
	{
		return;
	}

	time.hour = atoi(hms[0].c_str());
	time.minute= atoi(hms[1].c_str());
	time.second= atoi(hms[2].c_str());
	time.microsecond = 0;
}


/* bagging_generator.cc
   Jeremy Barnes, 15 March 2006
   Copyright (c) 2006 Jeremy Barnes  All rights reserved.
   $Source$

   Generator for boosted stumps.
*/

#include "bagging_generator.h"
#include "registry.h"
#include <boost/timer.hpp>
#include <boost/progress.hpp>
#include "training_index.h"
#include "weighted_training.h"
#include "committee.h"
#include "jml/utils/sgi_numeric.h"
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_int.hpp>
#include <boost/random/variate_generator.hpp>
#include "jml/utils/worker_task.h"
#include "jml/utils/guard.h"
#include <boost/bind.hpp>
#include "jml/utils/smart_ptr_utils.h"

using namespace std;

namespace ML {

/*****************************************************************************/
/* BAGGING_GENERATOR                                                         */
/*****************************************************************************/

Bagging_Generator::
Bagging_Generator()
{
    defaults();
}

Bagging_Generator::~Bagging_Generator()
{
}

void
Bagging_Generator::
configure(const Configuration & config)
{
    Early_Stopping_Generator::configure(config);

    config.find(num_bags,         "num_bags");
    config.find(validation_split, "validation_split");
    config.find(testing_split,    "testing_split");

    weak_learner = get_trainer("weak_learner", config);
}

void
Bagging_Generator::
defaults()
{
    Early_Stopping_Generator::defaults();
    num_bags = 10;
    validation_split = 0.35;
    testing_split = 0.0;
    weak_learner.reset();
}

Config_Options
Bagging_Generator::
options() const
{
    Config_Options result = Early_Stopping_Generator::options();
    result
        .add("num_bags", num_bags, "N>=1",
             "number of bags to divide classifier into")
        .add("validation_split", validation_split, "0<N<=1",
             "how much of training data to hold off as validation data")
        .add("testing_split", testing_split, "0<N<=1",
             "how much of training data to hold off as testing data (optional)")
        .subconfig("weak_leaner", weak_learner,
                   "weak learner that produces each bag");

    return result;
}

void
Bagging_Generator::
init(std::shared_ptr<const Feature_Space> fs, Feature predicted)
{
    Classifier_Generator::init(fs, predicted);
    weak_learner->init(fs, predicted);
}

namespace {

struct Bag_Job_Info {
    const Training_Data & training_set;
    const distribution<float> & training_ex_weights;
    const vector<Feature> & features;
    vector<std::shared_ptr<Classifier_Impl> > & results;
    float train_prop;
    std::shared_ptr<Classifier_Generator> weak_learner;
    boost::progress_display * progress;
    int num_bags;

    Bag_Job_Info(const Training_Data & training_set,
                 const distribution<float> & training_ex_weights,
                 const vector<Feature> & features,
                 vector<std::shared_ptr<Classifier_Impl> > & results,
                 float train_prop,
                 std::shared_ptr<Classifier_Generator> weak_learner,
                 int num_bags)
        : training_set(training_set), training_ex_weights(training_ex_weights),
          features(features), results(results),
          train_prop(train_prop), weak_learner(weak_learner),
          progress(0), num_bags(num_bags)
    {
    }
};

struct Bag_Job {
    Bag_Job(Bag_Job_Info & info,
            Thread_Context & context,
            int bag_num, int verbosity)
        : info(info), context(context), bag_num(bag_num),
          verbosity(verbosity)
    {
    }

    Bag_Job_Info & info;
    Thread_Context & context;
    int bag_num;
    int verbosity;

    typedef boost::mt19937 engine_type;

    void operator () () const
    {
        Thread_Context::RNG_Type rng = context.rng();

        int nx = info.training_set.example_count();
        /* Partition the dataset. */

#if 0
        distribution<float> test_eq_weights, test_uniform_weights;

        if (test) {
            test_eq_weights = apply_weight_spec(*test, weight_spec);
            test_uniform_weights = distribution<float>(test->example_count(), 1.0);
        }
#endif

        distribution<float> in_training(nx);
        vector<int> tr_ex_nums(nx);
        std::iota(tr_ex_nums.begin(), tr_ex_nums.end(), 0);
        std::random_shuffle(tr_ex_nums.begin(), tr_ex_nums.end(), rng);
        for (unsigned i = 0;  i < nx * info.train_prop;  ++i)
            in_training[tr_ex_nums[i]] = 1.0;
        distribution<float> not_training(nx, 1.0);
        not_training -= in_training;

        distribution<float> example_weights(nx);

        /* Generate our example weights. */
        for (unsigned i = 0;  i < nx;  ++i)
            example_weights[rng(nx)] += 1.0;

        distribution<float> training_weights
            = in_training * example_weights * info.training_ex_weights;
        training_weights.normalize();

        distribution<float> validate_weights
            = not_training * example_weights * info.training_ex_weights;
        validate_weights.normalize();

        if (verbosity > 0)
            cerr << "bag " << bag_num << " of " << info.num_bags << endl;

#if 0
        cerr << "train_prop = " << info.train_prop << endl;
        cerr << "in_training = " << in_training << endl;
        cerr << "example_weights = " << example_weights << endl;
        cerr << "info.training_ex_weights = " << info.training_ex_weights
             << endl;
        cerr << "training_weights = " << training_weights << endl;
        cerr << "validate_weights = " << validate_weights << endl;
#endif

        /* Train me! */
        std::shared_ptr<Classifier_Impl> bag
            = info.weak_learner
            ->generate(context,
                       info.training_set, info.training_set,
                       training_weights, validate_weights,
                       info.features);

        /* No need to lock since we're the only one accessing this part of
           the array. */
        info.results[bag_num] = bag;

        if (info.progress)
            ++(*info.progress);

#if 0
        if (test) {
            cerr << "testing results: "
                 << bag->accuracy(*test, test_eq_weights) * 100.0
                 << "% eq this bag, "
                 << result.accuracy(*test, test_eq_weights) * 100.0
                 << "% eq overall, "
                 << result.accuracy(*test, test_uniform_weights) * 100
                 << "% uniform overall" << endl;
        }
#endif
        //cerr << endl;
    }
};

} // file scope

std::shared_ptr<Classifier_Impl>
Bagging_Generator::
generate(Thread_Context & context,
         const Training_Data & training_set,
         const Training_Data & validation_set,
         const distribution<float> & training_ex_weights,
         const distribution<float> & validate_ex_weights,
         const std::vector<Feature> & features, int) const
{
    boost::timer timer;

    float train_prop = 1.0 - validation_split - testing_split;

    if (train_prop <= 0.0 || train_prop > 1.00001)
        throw Exception("Training proportion out of range");

    if (validation_split < 0.0 || validation_split > 1.00001)
        throw Exception("Validation proportion out of range");

    if (testing_split < 0.0 || testing_split > 1.00001)
        throw Exception("Testing proportion out of range");

    //cerr << "train_prop = " << train_prop << " validation_split = "
    //     << validation_split << " testing_split = " << testing_split
    //     << endl;

    bool local_thread_only = (num_bags > num_threads() * 2);

    vector<std::shared_ptr<Classifier_Impl> > results(num_bags);
    vector<Thread_Context> contexts(num_bags);
    for (unsigned i = 0;  i < num_bags;  ++i)
        contexts[i] = context.child(-1, local_thread_only);

    Bag_Job_Info info(training_set, training_ex_weights,
                      features, results,
                      train_prop, weak_learner, num_bags);
    static Worker_Task & worker = Worker_Task::instance(num_threads() - 1);

    int group;
    {
        group = worker.get_group(NO_JOB,
                                 format("Bagging_Generator::generate(): under %d",
                                        context.group()),
                                 context.group());
        //cerr << "bagging: group = " << group << endl;
        Call_Guard guard(boost::bind(&Worker_Task::unlock_group,
                                     boost::ref(worker),
                                     group));
        for (unsigned i = 0;  i < num_bags;  ++i)
            worker.add(Bag_Job(info, contexts[i], i, verbosity),
                       format("Bagging_Generator::generate() bag %d under %d",
                              i, group),
                       group);
    }

    worker.run_until_finished(group);

    Committee result(feature_space, predicted);

    for (unsigned i = 0;  i < num_bags;  ++i)
        result.add(results[i], 1.0 / num_bags);

    if (profile)
        cerr << "training time: " << timer.elapsed() << "s" << endl;

    return make_sp(result.make_copy());
}

/*****************************************************************************/
/* REGISTRATION                                                              */
/*****************************************************************************/

namespace {

Register_Factory<Classifier_Generator, Bagging_Generator>
    BAGGING_REGISTER("bagging");

} // file scope

} // namespace ML


#include "pipeline.h"

#include <boost/range/adaptors.hpp>
#include <vector>
#include <algorithm>

#define NONIUS_RUNNER
#include <nonius/nonius.h++>
#include <nonius/main.h++>

namespace pl = pipeline;
namespace ad = boost::adaptors;

const auto numbers = []
{
   std::vector<int> v(10000);
   std::iota(v.begin(), v.end(), 0);
   return v;
}();

namespace pipeline
{
   auto for_each = [](auto&& rng){
      return source([&rng](auto&& sink){
         for (auto const& x : rng) if (!sink(x)) return;
      });
   };
}

NONIUS_BENCHMARK("pipeline filter", []
{
   volatile int sum = 0;
   pl::for_each(numbers)
   | pl::filter([](int x){ return x&1; })
   | pl::transform([](int x){ return x*x; })
   | pl::filter([](int x){ return x&1; })
   | pl::transform([](int x){ return x*x; })
   | pl::subscribe([&sum](int x){ sum += x; })
   ;
   return sum;
});

NONIUS_BENCHMARK("range filter",[]
{
   volatile int sum = 0;
   for (auto x : numbers
               | ad::filtered([](int x){ return x&1; })
               | ad::transformed([](int x){ return x*x; })
               | ad::filtered([](int x){ return x&1; })
               | ad::transformed([](int x){ return x*x; })
               )
   {
      sum += x;
   }
   return sum;
});


//==================================================================================================
/*!
  @file

  @copyright 2016 NumScale SAS

  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
*/
//==================================================================================================
#ifndef BOOST_SIMD_FUNCTION_BITGET_HPP_INCLUDED
#define BOOST_SIMD_FUNCTION_BITGET_HPP_INCLUDED

#if defined(DOXYGEN_ONLY)
namespace boost { namespace simd
{

 /*!

    @ingroup group-bitwise
    Function object implementing bitget capabilities

    Returns the value of the ith bit in x as an unsigned integer

    @par semantic:
    For any given value @c x of type @c T, @c i of type @c I:

    @code
    as_integer_t<T> r = bitget(x, i);
    @endcode

    r contains is 0 or \f$2^i\f$ according to the fact the of rank @c i of @c x is 0 or 1

    @see  bitset

  **/
  as_integer_t<T> bitget(Value const & v0, integer_type i);
} }
#endif

#include <boost/simd/function/scalar/bitget.hpp>
#include <boost/simd/function/simd/bitget.hpp>

#endif


/*

    This is the program that created the http://dlib.net/files/shape_predictor_5_face_landmarks.dat.bz2 model file.

*/

#include <dlib/image_processing/frontal_face_detector.h>
#include <dlib/image_processing.h>
#include <dlib/console_progress_indicator.h>
#include <dlib/data_io.h>
#include <dlib/statistics.h>
#include <iostream>

using namespace dlib;
using namespace std;

// ----------------------------------------------------------------------------------------

std::vector<std::vector<double> > get_interocular_distances (
    const std::vector<std::vector<full_object_detection> >& objects
);
/*!
    ensures
        - returns an object D such that:
            - D[i][j] == the distance, in pixels, between the eyes for the face represented
              by objects[i][j].
!*/

// ----------------------------------------------------------------------------------------

template <
    typename image_array_type,
    typename T
    >
void add_image_left_right_flips_5points (
    image_array_type& images,
    std::vector<std::vector<T> >& objects
)
{
    // make sure requires clause is not broken
    DLIB_ASSERT( images.size() == objects.size(),
        "\t void add_image_left_right_flips()"
        << "\n\t Invalid inputs were given to this function."
        << "\n\t images.size():  " << images.size()
        << "\n\t objects.size(): " << objects.size()
        );

    typename image_array_type::value_type temp;
    std::vector<T> rects;

    const unsigned long num = images.size();
    for (unsigned long j = 0; j < num; ++j)
    {
        const point_transform_affine tran = flip_image_left_right(images[j], temp);

        rects.clear();
        for (unsigned long i = 0; i < objects[j].size(); ++i)
        {
            rects.push_back(impl::tform_object(tran, objects[j][i]));

            DLIB_CASSERT(rects.back().num_parts() == 5);
            swap(rects.back().part(0), rects.back().part(2));
            swap(rects.back().part(1), rects.back().part(3));
        }

        images.push_back(temp);
        objects.push_back(rects);
    }
}

// ----------------------------------------------------------------------------------------

int main(int argc, char** argv)
{
    try
    {
        if (argc != 2)
        {
            cout << "give the path to the training data folder" << endl;
            return 0;
        }
        const std::string faces_directory = argv[1];
        dlib::array<array2d<unsigned char> > images_train, images_test;
        std::vector<std::vector<full_object_detection> > faces_train, faces_test;

        std::vector<std::string> parts_list;
        load_image_dataset(images_train, faces_train, faces_directory+"/train_cleaned.xml", parts_list);
        load_image_dataset(images_test, faces_test, faces_directory+"/test_cleaned.xml");

        add_image_left_right_flips_5points(images_train, faces_train);
        add_image_left_right_flips_5points(images_test, faces_test);
        add_image_rotations(linspace(-20,20,3)*pi/180.0,images_train, faces_train);

        cout << "num training images: "<< images_train.size() << endl;

        for (auto& part : parts_list)
            cout << part << endl;

        shape_predictor_trainer trainer;
        trainer.set_oversampling_amount(40);
        trainer.set_num_test_splits(150);
        trainer.set_feature_pool_size(800);
        trainer.set_num_threads(4);
        trainer.set_cascade_depth(15);
        trainer.be_verbose();

        // Now finally generate the shape model
        shape_predictor sp = trainer.train(images_train, faces_train);

        serialize("shape_predictor_5_face_landmarks.dat") << sp;

        cout << "mean training error: "<<
            test_shape_predictor(sp, images_train, faces_train, get_interocular_distances(faces_train)) << endl;

        cout << "mean testing error:  "<<
            test_shape_predictor(sp, images_test, faces_test, get_interocular_distances(faces_test)) << endl;

    }
    catch (exception& e)
    {
        cout << "\nexception thrown!" << endl;
        cout << e.what() << endl;
    }
}

// ----------------------------------------------------------------------------------------

double interocular_distance (
    const full_object_detection& det
)
{
    dlib::vector<double,2> l, r;
    // left eye
    l = (det.part(0) + det.part(1))/2;
    // right eye
    r = (det.part(2) + det.part(3))/2;

    return length(l-r);
}

std::vector<std::vector<double> > get_interocular_distances (
    const std::vector<std::vector<full_object_detection> >& objects
)
{
    std::vector<std::vector<double> > temp(objects.size());
    for (unsigned long i = 0; i < objects.size(); ++i)
    {
        for (unsigned long j = 0; j < objects[i].size(); ++j)
        {
            temp[i].push_back(interocular_distance(objects[i][j]));
        }
    }
    return temp;
}

// ----------------------------------------------------------------------------------------


//==================================================================================================
/**
  Copyright 2016 NumScale SAS

  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
**/
//==================================================================================================
#ifndef BOOST_SIMD_ARCH_COMMON_SCALAR_FUNCTION_BITWISE_SELECT_HPP_INCLUDED
#define BOOST_SIMD_ARCH_COMMON_SCALAR_FUNCTION_BITWISE_SELECT_HPP_INCLUDED

#include <boost/simd/detail/overload.hpp>
#include <boost/simd/function/bitwise_and.hpp>
#include <boost/simd/function/bitwise_andnot.hpp>
#include <boost/simd/function/bitwise_or.hpp>

namespace boost { namespace simd { namespace ext
{
  namespace bd = boost::dispatch;

  BOOST_DISPATCH_OVERLOAD_IF( bitwise_select_
                            , (typename A0, typename A1)
                            , (brigand::bool_<sizeof(A0)==sizeof(A1)>)
                            , bd::cpu_
                            , bd::scalar_<bd::arithmetic_<A0> >
                            , bd::scalar_<bd::arithmetic_<A1> >
                            , bd::scalar_<bd::arithmetic_<A1> >
                            )
  {
    BOOST_FORCEINLINE A1 operator()(A0 const& a0, A1 const& a1, A1 const& a2) const BOOST_NOEXCEPT
    {
      return bitwise_or(bitwise_and(a1, a0), bitwise_andnot(a2,a0));
    }
  };
} } }

#endif


//---------------------------------------------------------------------------//
//!
//! \file   Utility_MeCMomentumUnit.hpp
//! \author Alex Robinson
//! \brief  The me*c momentum unit
//!
//---------------------------------------------------------------------------//

#ifndef UTILITY_MEC_MOMENTUM_UNIT_HPP
#define UTILITY_MEC_MOMENTUM_UNIT_HPP

// Boost Includes
#include <boost/units/systems/si/momentum.hpp>
#include <boost/units/physical_dimensions/length.hpp>
#include <boost/units/base_unit.hpp>
#include <boost/units/conversion.hpp>

// FRENSIE Includes
#include "Utility_RawPhysicalConstants.hpp"

namespace Utility{

namespace Units{

//! The me*c momentum base unit
struct MeCMomentumBaseUnit : public boost::units::base_unit<MeCMomentumBaseUnit, boost::units::momentum_dimension, 3>
{
  static const char* name() { return "MeC Momentum"; }
  static const char* symbol() { return "me*c"; }
};

//! The me*c momentum base unit
typedef MeCMomentumBaseUnit::unit_type MeCMomentum;

BOOST_UNITS_STATIC_CONSTANT( mec_momentum, MeCMomentum );
BOOST_UNITS_STATIC_CONSTANT( mec, MeCMomentum );

} // end Units namespace

} // end Utility namespace

BOOST_UNITS_DEFINE_CONVERSION_FACTOR( Utility::Units::MeCMomentumBaseUnit, boost::units::si::momentum, double, Utility::RawPhysicalConstants::atomic_momentum/Utility::RawPhysicalConstants::fine_structure_constant );

BOOST_UNITS_DEFINE_CONVERSION_FACTOR( boost::units::si::momentum, Utility::Units::MeCMomentumBaseUnit, double, Utility::RawPhysicalConstants::fine_structure_constant/Utility::RawPhysicalConstants::atomic_momentum );

BOOST_UNITS_DEFAULT_CONVERSION( Utility::Units::MeCMomentumBaseUnit, boost::units::si::momentum );

#endif // end UTILITY_MEC_MOMENTUM_UNIT_HPP

//---------------------------------------------------------------------------//
// end Utility_MeCMomentumUnit.hpp
//---------------------------------------------------------------------------//


#ifndef COMBISDESIGN_HPP_INCLUDED
#define COMBISDESIGN_HPP_INCLUDED

#include <fstream>
#include "bisniftiimage.hpp"

#include <dlib/matrix.h>

#include <nlohmann/json.hpp>

using json = nlohmann::json;

typedef float_t value_type;

bool combisSVMdesign(std::string                               designfile,
                     std::vector <dlib::matrix<value_type,0,1>> *x,
                     std::vector <value_type>                   *y,
                     bis::bisnifti<value_type>              *curr) {

    bool isbinary = true;
    json jdesign;

    try {

        // read JSON design file
        std::ifstream infile(designfile);
        infile >> jdesign;

        // load labels
        auto    ytemp ( jdesign[ "labels" ].get<std::vector<value_type>>() );
        y->assign(ytemp.begin(),ytemp.end());

        // determine whether we we have a text design (ascii matrix) or binary inputs (images)
        std::string designtype=jdesign["designtype"].get<std::string>();

        // text vectors: read from ascii matrix
        if (!designtype.compare("text")) {

            isbinary = false;

            std::vector<std::vector<value_type>> xtesti(jdesign["vectors"].get<std::vector<std::vector<value_type>>>());

            // load a vector as a sequence of floats (converted already by json)
            for (auto v: xtesti) {

                dlib::matrix<value_type,0,1> xi = dlib::mat(v);
                x->push_back(xi);

            }

        } else { // binary vectors: read from images

            // test for a mask in json
            std::string maskFile = jdesign["mask"].get<std::string>();

            bis::bisnifti<value_type> *maskImage = new bis::bisnifti<value_type>(maskFile);
            auto
				nzvec = maskImage->nonzeros();

            std::vector<std::string> xtests(jdesign["vectors"].get<std::vector<std::string>>());
            for (auto v: xtests) {

                bis::bisnifti<value_type>
					oneImage = bis::bisnifti<value_type>(v);
                auto
					selectedvoxels = oneImage.vector_get ( nzvec );

                dlib::matrix<value_type,0,1> xs = dlib::mat(selectedvoxels);
                x->push_back(xs);
            }

       }

    } catch(const json::parse_error &) {
        throw (bis::bisException("error parsing design json"));
    }

    return ( isbinary );

} // readdesign

#endif // COMBISDESIGN_HPP_INCLUDED


// Boost.Geometry (aka GGL, Generic Geometry Library)

// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.

// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

#ifndef BOOST_GEOMETRY_GEOMETRY_POLICIES_RELATE_INTERSECTION_POINTS_HPP
#define BOOST_GEOMETRY_GEOMETRY_POLICIES_RELATE_INTERSECTION_POINTS_HPP

#include <algorithm>
#include <string>

#include <boost/concept_check.hpp>
#include <boost/numeric/conversion/cast.hpp>

#include <boost/geometry/arithmetic/determinant.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/strategies/side_info.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
#include <boost/geometry/util/select_most_precise.hpp>

namespace boost { namespace geometry
{

namespace policies { namespace relate
{

template <typename S1, typename S2, typename ReturnType, typename CalculationType = void>
struct segments_intersection_points
{
    typedef ReturnType return_type;
    typedef S1 segment_type1;
    typedef S2 segment_type2;

    typedef typename select_calculation_type
        <
            S1, S2, CalculationType
        >::type coordinate_type;

    template <typename R>
    static inline return_type segments_intersect(side_info const&,
                    R const& r,
                    coordinate_type const& dx1, coordinate_type const& dy1,
                    coordinate_type const& , coordinate_type const& ,
                    S1 const& s1, S2 const& )
    {
        typedef typename geometry::coordinate_type
            <
                typename return_type::point_type
            >::type return_coordinate_type;

        coordinate_type const s1x = get<0, 0>(s1);
        coordinate_type const s1y = get<0, 1>(s1);

        return_type result;
        result.count = 1;
        set<0>(result.intersections[0],
            boost::numeric_cast<return_coordinate_type>(R(s1x) + r * R(dx1)));
        set<1>(result.intersections[0],
            boost::numeric_cast<return_coordinate_type>(R(s1y) + r * R(dy1)));

        return result;
    }

    static inline return_type collinear_touch(coordinate_type const& x,
                coordinate_type const& y, int, int)
    {
        return_type result;
        result.count = 1;
        set<0>(result.intersections[0], x);
        set<1>(result.intersections[0], y);
        return result;
    }

    template <typename S>
    static inline return_type collinear_inside(S const& s, int index1 = 0, int index2 = 1)
    {
        return_type result;
        result.count = 2;
        set<0>(result.intersections[index1], get<0, 0>(s));
        set<1>(result.intersections[index1], get<0, 1>(s));
        set<0>(result.intersections[index2], get<1, 0>(s));
        set<1>(result.intersections[index2], get<1, 1>(s));
        return result;
    }

    template <typename S>
    static inline return_type collinear_interior_boundary_intersect(S const& s, bool a_in_b,
                int, int, bool opposite)
    {
        int index1 = opposite && ! a_in_b ? 1 : 0;
        return collinear_inside(s, index1, 1 - index1);
    }

    static inline return_type collinear_a_in_b(S1 const& s, bool)
    {
        return collinear_inside(s);
    }
    static inline return_type collinear_b_in_a(S2 const& s, bool opposite)
    {
        int index1 = opposite ? 1 : 0;
        return collinear_inside(s, index1, 1 - index1);
    }

    static inline return_type collinear_overlaps(
                coordinate_type const& x1, coordinate_type const& y1,
                coordinate_type const& x2, coordinate_type const& y2,
                int, int, bool)
    {
        return_type result;
        result.count = 2;
        set<0>(result.intersections[0], x1);
        set<1>(result.intersections[0], y1);
        set<0>(result.intersections[1], x2);
        set<1>(result.intersections[1], y2);
        return result;
    }

    static inline return_type segment_equal(S1 const& s, bool)
    {
        return_type result;
        result.count = 2;
        // TODO: order of IP's
        set<0>(result.intersections[0], get<0, 0>(s));
        set<1>(result.intersections[0], get<0, 1>(s));
        set<0>(result.intersections[1], get<1, 0>(s));
        set<1>(result.intersections[1], get<1, 1>(s));
        return result;
    }

    static inline return_type disjoint()
    {
        return return_type();
    }
    static inline return_type error(std::string const&)
    {
        return return_type();
    }

    static inline return_type collinear_disjoint()
    {
        return return_type();
    }

    static inline return_type degenerate(S1 const& s, bool)
    {
        return_type result;
        result.count = 1;
        set<0>(result.intersections[0], get<0, 0>(s));
        set<1>(result.intersections[0], get<0, 1>(s));
        return result;
    }
};

}} // namespace policies::relate

}} // namespace boost::geometry

#endif // BOOST_GEOMETRY_GEOMETRY_POLICIES_RELATE_INTERSECTION_POINTS_HPP


#include "visual_utility/VisualUtilityMosaic.h"

#include <gtest/gtest.h>
#include <boost/scoped_ptr.hpp>

using namespace cv;
using namespace std;
using namespace boost;
using namespace cv_blobs;

namespace visual_utility {

class NullVUMosaicTest : public ::testing::Test {
 protected:
  scoped_ptr<NullVUMosaic> mosaic;

  virtual void SetUp() {
    mosaic.reset(new NullVUMosaic(0, 0));
  }

};

TEST_F(NullVUMosaicTest, IntegralTest) {
  Mat_<double> frame = Mat_<double>::ones(4,6);
  mosaic->AddFrame(frame, NULL);

  EXPECT_DOUBLE_EQ(mosaic->GetIntegralValue(Point2f(-4, -4)), 0);
  EXPECT_DOUBLE_EQ(mosaic->GetIntegralValue(Point2f(4, 4)), 24);
  EXPECT_DOUBLE_EQ(mosaic->GetIntegralValue(Point2f(0, 0)), 6);
  EXPECT_DOUBLE_EQ(mosaic->GetIntegralValue(Point2f(-3, 0)), 0);
  EXPECT_DOUBLE_EQ(mosaic->GetIntegralValue(Point2f(0, -4)), 0);
}

TEST_F(NullVUMosaicTest, SizeTest) {
  EXPECT_DOUBLE_EQ(mosaic->GetSize(), 0);

  Mat_<double> frame = Mat_<double>::ones(4,6);
  mosaic->AddFrame(frame, NULL);

  EXPECT_DOUBLE_EQ(mosaic->GetSize(), 24);
}

TEST_F(NullVUMosaicTest, SumTest) {
  EXPECT_DOUBLE_EQ(mosaic->GetSum(), 0);

  Mat_<double> frame = Mat_<double>::ones(4,6);
  mosaic->AddFrame(frame, NULL);
  EXPECT_DOUBLE_EQ(mosaic->GetSum(), 24);

  frame[2][3] = 10;
  mosaic->AddFrame(frame, NULL);
  EXPECT_DOUBLE_EQ(mosaic->GetSum(), 33);
}

TEST_F(NullVUMosaicTest, ValueTest) {
  EXPECT_DOUBLE_EQ(mosaic->GetValue(Point2f(0, 0)), 0);

  Mat_<double> frame = Mat_<double>::ones(4,6);
  frame[2][3] = 10;
  frame[0][5] = -16;
  mosaic->AddFrame(frame, NULL);
  EXPECT_DOUBLE_EQ(mosaic->GetValue(Point2f(0, 0)), 10);
  EXPECT_DOUBLE_EQ(mosaic->GetValue(Point2f(2, -2)), -16);
  EXPECT_DOUBLE_EQ(mosaic->GetValue(Point2f(4, 4)), 0);
  EXPECT_DOUBLE_EQ(mosaic->GetValue(Point2f(-4, -4)), 0);
}

struct MaxPixelFunc : public PixelValFunc {
  virtual double operator()(const double& val) { return val; };
};

TEST_F(NullVUMosaicTest, MaximumPixelTest) {
  Mat_<double> frame = Mat_<double>::ones(4,6);
  frame[1][3] = 10;
  frame[0][5] = -16;
  mosaic->AddFrame(frame, NULL);

  Point2f maxLoc;
  EXPECT_DOUBLE_EQ(mosaic->MaximizeFunction(&MaxPixelFunc(), &maxLoc), 10);
  EXPECT_DOUBLE_EQ(maxLoc.x, 0);
  EXPECT_DOUBLE_EQ(maxLoc.y, -1);
  EXPECT_DOUBLE_EQ(mosaic->GetValue(maxLoc), 10);
}

TEST_F(NullVUMosaicTest, FindConnectedComponents) {
  Mat_<double> frame = Mat_<double>::ones(4,6);
  frame[1][3] = 10;
  frame[0][3] = 10;
  frame[2][0] = 9;
  frame[0][5] = -16;
  mosaic->AddFrame(frame, NULL);

  BlobResult<double> blobs;
  mosaic->FindConnectedComponents(7, &blobs);
  ASSERT_EQ(blobs.nBlobs(), 2);
  for (int i = 0; i < blobs.nBlobs(); i++) {
    const Blob& curBlob = blobs.GetBlob(i);
    if (curBlob.area() == 1) {
      EXPECT_EQ(curBlob.minX(), -3);
      EXPECT_EQ(curBlob.maxX(), -3);
      EXPECT_EQ(curBlob.minY(), 0);
      EXPECT_EQ(curBlob.maxY(), 0);
    } else if (curBlob.area() == 2) {
      EXPECT_EQ(curBlob.minX(), 0);
      EXPECT_EQ(curBlob.maxX(), 0);
      EXPECT_EQ(curBlob.minY(), -2);
      EXPECT_EQ(curBlob.maxY(), -1);
    } else {
      FAIL() << "We shouldn't have found a blob of size: " << curBlob.area();
    }
  }
}

} // namespace

int main(int argc, char **argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}


#include <boost/graph/edge_coloring.hpp>


// This file is part of MLDB. Copyright 2015 mldb.ai inc. All rights reserved.

/* perceptron_generator.cc
   Jeremy Barnes, 15 March 2006
   Copyright (c) 2006 Jeremy Barnes  All rights reserved.

   Generator for perceptrons.
*/

#include "perceptron_generator.h"
#include "mldb/plugins/jml/jml/registry.h"
#include <boost/timer.hpp>
#include <boost/progress.hpp>
#include "mldb/plugins/jml/jml/training_index.h"
#include "mldb/utils/distribution_simd.h"
#include "mldb/arch/simd_vector.h"
#include "mldb/plugins/jml/algebra/lapack.h"
#include "mldb/plugins/jml/algebra/matrix_ops.h"
#include "mldb/plugins/jml/algebra/irls.h"
#include <iomanip>
#include "mldb/utils/environment.h"
#include "mldb/utils/profile.h"
#include "mldb/base/parallel.h"
#include "mldb/base/scope.h"
#include "mldb/plugins/jml/jml/evaluation.h"
#include <boost/scoped_ptr.hpp>
#include "mldb/utils/smart_ptr_utils.h"
#include "mldb/utils/vector_utils.h"
#include "mldb/utils/pair_utils.h"
#include "mldb/plugins/jml/neural/dense_layer.h"
#include "discriminative_trainer.h"

using namespace std;

namespace ML {

namespace {

EnvOption<bool> profile("PROFILE_PERCEPTRON", false);

double t_train = 0.0, t_decorrelate = 0.0;
double t_cholesky = 0.0, t_qr = 0.0, t_gs = 0.0, t_mean = 0.0, t_covar = 0.0;
double t_update = 0.0, t_fprop = 0.0, t_bprop = 0.0, t_zero = 0.0;
double t_setup = 0.0;

struct Stats {
    ~Stats()
    {
        if (profile) {
            cerr << "perceptron training profile: " << endl;
            cerr << "  decorrelate:    " << t_decorrelate << "s" << endl;
            cerr << "    qr:           " << t_qr          << "s" << endl;
            cerr << "    gram schmidt: " << t_gs          << "s" << endl;
            cerr << "    mean:         " << t_mean        << "s" << endl;
            cerr << "    covar         " << t_covar       << "s" << endl;
            cerr << "    cholesky:     " << t_cholesky    << "s" << endl;
            cerr << "  train:          " << t_train       << "s" << endl;
            cerr << "    setup:        " << t_setup       << "s" << endl;
            cerr << "    update:       " << t_update      << "s" << endl;
            cerr << "    fprop:        " << t_fprop       << "s" << endl;
            cerr << "    bprop:        " << t_bprop       << "s" << endl;
            cerr << "    zero:         " << t_zero        << "s" << endl;
        }
    }
} stats;

} // file scope

/*****************************************************************************/
/* PERCEPTRON_GENERATOR                                                      */
/*****************************************************************************/

Perceptron_Generator::
Perceptron_Generator()
{
    defaults();
}

Perceptron_Generator::~Perceptron_Generator()
{
}

void
Perceptron_Generator::
configure(const Configuration & config, vector<string> & unparsedKeys)
{
    Early_Stopping_Generator::configure(config, unparsedKeys);

    config.findAndRemove(max_iter, "max_iter", unparsedKeys);
    config.findAndRemove(min_iter, "min_iter", unparsedKeys);
    config.findAndRemove(learning_rate, "learning_rate", unparsedKeys);
    config.findAndRemove(arch_str, "arch", unparsedKeys);
    config.findAndRemove(batch_size, "batch_size", unparsedKeys);
    config.findAndRemove(activation, "activation", unparsedKeys);
    config.findAndRemove(output_activation, "output_activation", unparsedKeys);
    config.findAndRemove(do_decorrelate, "decorrelate", unparsedKeys);
    config.findAndRemove(do_normalize, "normalize", unparsedKeys);
    config.findAndRemove(target_value, "target_value", unparsedKeys);
}

void
Perceptron_Generator::
defaults()
{
    Early_Stopping_Generator::defaults();
    max_iter = 100;
    min_iter = 10;
    learning_rate = 0.01;
    arch_str = "%i";
    activation = output_activation = TF_TANH;
    do_decorrelate = true;
    do_normalize = true;
    batch_size = 1024;
    target_value = 0.8;
}

Config_Options
Perceptron_Generator::
options() const
{
    Config_Options result = Early_Stopping_Generator::options();
    result
        .add("min_iter", min_iter, "1-max_iter",
             "minimum number of training iterations to run")
        .add("max_iter", max_iter, ">=min_iter",
             "maximum number of training iterations to run")
        .add("learning_rate", learning_rate, "real",
             "positive: rate of learning relative to dataset size: negative for absolute")
        .add("arch", arch_str, "(see doc)",
             "hidden unit specification; %i=in vars, %o=out vars; eg 5_10")
        .add("activation", activation,
             "activation function for neurons")
        .add("output_activation", output_activation,
             "activation function for output layer of neurons")
        .add("decorrelate", do_decorrelate,
             "decorrelate the features before training")
        .add("normalize", do_normalize,
             "normalize to zero mean and unit std before training")
        .add("batch_size", batch_size, "0.0-1.0 or 1 - nvectors",
             "number of samples in each \"mini batch\" for stochastic")
        .add("target_value", target_value, "0.0-1.0", "the output for a 1 that we ask the network to provide");

    return result;
}

void
Perceptron_Generator::
init(std::shared_ptr<const Feature_Space> fs, Feature predicted)
{
    Early_Stopping_Generator::init(fs, predicted);
    model = Perceptron(fs, predicted);
}

std::shared_ptr<Classifier_Impl>
Perceptron_Generator::
generate(Thread_Context & context,
         const Training_Data & training_set,
         const Training_Data & validation_set,
         const distribution<float> & training_ex_weights,
         const distribution<float> & validate_ex_weights,
         const std::vector<Feature> & features, int) const
{
    boost::timer::cpu_timer timer;

    Feature predicted = model.predicted();

    bool regression = feature_space->info(predicted).type() == REAL;

    Perceptron current(model);
    Perceptron best(model);

    float best_acc = 0.0;
    float best_rmse = 0.0;
    int best_iter = 0;

    bool validate_is_train = false;
    //if (validation_set.example_count() == 0
    //    || &validation_set == &training_set)
    //    validate_is_train = true;

    if (validate_ex_weights.total() == 0.0)
        throw Exception("no validate ex weights");

    std::unique_ptr<boost::progress_display> progress;

    //cerr << "training_ex_weights = " << training_ex_weights << endl;
    //cerr << "validate_ex_weights = " << validate_ex_weights << endl;

    log("perceptron_generator", 1)
        << "training " << max_iter << " iterations..." << endl;

    if (verbosity < 3)
        progress.reset(new boost::progress_display
                       (max_iter, log("perceptron_generator", 1)));

    vector<int> arch = Perceptron::parse_architecture(arch_str);

    boost::multi_array<float, 2> decorrelated
        = init(training_set, features, arch, current, context);

    size_t nx_validate
        = (validate_is_train ? training_set : validation_set)
        .example_count();

    boost::multi_array<float, 2> val_decorrelated
        (boost::extents[nx_validate][decorrelated.shape()[1]]);

    if (validate_is_train) val_decorrelated = decorrelated;
    else val_decorrelated = current.decorrelate(validation_set);

    size_t nx = decorrelated.shape()[0];
    size_t nxv = val_decorrelated.shape()[0];
    size_t nf = decorrelated.shape()[1];

    log("perceptron_generator", 1)
        << current.parameters() << " parameters, "
        << nx << " examples, " << nx * nf << " training values" << endl;

    if (min_iter > max_iter)
        throw Exception("min_iter is greater than max_iter");

    log("perceptron_generator", 3)
        << "  it   train     rmse     val     rmse    best     diff" << endl;

    float validate_acc = 0.0, validate_rmse = 0.0;
    float train_acc = 0.0, train_rmse = 0.0;

    const std::vector<Label> & labels
        = training_set.index().labels(predicted);
    const std::vector<Label> & val_labels MLDB_UNUSED
        = validation_set.index().labels(predicted);

    double last_best_acc = 0.0;
    double last_best_rmse MLDB_UNUSED = 0.0;

    int our_batch_size = batch_size;
    if (batch_size == 0.0) our_batch_size = nx;
    else if (batch_size < 1.0) our_batch_size = nx * batch_size;

    /* If we specified a negative learning rate, that means that we wanted it
       to be absolute (and so not depend upon the size of the dataset).  In
       order to get this behaviour, we need to multipy by the number of
       examples in the dataset, since it is implicitly multiplied by the
       example weight (on average 1/num examples in training set) as part of
       the training, and we want to counteract this effect).
    */
    float learning_rate = this->learning_rate;
    if (learning_rate < 0.0) {
        learning_rate
            *= -1.0 * training_ex_weights.size() / training_ex_weights.total();
    }

    // Create a layer stack without the decorrelation layer to be trained
    Layer_Stack<Layer> train_stack;
    for (unsigned i = 1;  i < current.layers.size();  ++i)
        train_stack.add(current.layers.share(i));

    Discriminative_Trainer trainer;
    trainer.layer = &train_stack;

    bool randomize = false;
    float sample_proportion = 1.0;

    vector<const float *> examples(nx);
    for (unsigned i = 0;  i < nx;  ++i)
        examples[i] = &decorrelated[i][0];

    vector<const float *> val_examples(nxv);
    for (unsigned i = 0;  i < nxv;  ++i)
        val_examples[i] = &val_decorrelated[i][0];

    Output_Encoder & output_encoder = current.output;
    output_encoder.configure(model.feature_space()->info(model.predicted()),
                             train_stack, target_value);

    for (unsigned i = 0;  i < max_iter;  ++i) {

        //cerr << "params = " << Parameters_Copy<float>(train_stack.parameters()).values << endl;

        //cerr << "mode = " << output_encoder.mode << " value_true = " << output_encoder.value_true
        //     << " value_false = " << output_encoder.value_false << " num_inputs = "
        //     << output_encoder.num_inputs << " num_outputs = " << output_encoder.num_outputs
        //     << endl;

        {
            PROFILE_FUNCTION(t_train);

            std::tie(train_acc, train_rmse)
                = trainer.train_iter(examples, labels, training_ex_weights,
                                     output_encoder,
                                     context, our_batch_size, learning_rate,
                                     verbosity, sample_proportion, randomize);
        }

        if (validate_is_train) {
            validate_acc = train_acc;
            validate_rmse = train_rmse;
        }
        else {
            std::tie(validate_acc, validate_rmse)
                = trainer.test(val_examples, val_labels, validate_ex_weights,
                               output_encoder, context, verbosity);
        }

        last_best_acc = best_acc;
        last_best_rmse = best_rmse;

        if (i == min_iter
            || (validate_acc > best_acc && !regression)
            || (validate_acc < best_acc && regression)) {
            best = current;
            best_acc = validate_acc;
            best_rmse = validate_rmse;
            best_iter = i;
        }

        log("perceptron_generator", 3)
            << format("%4d %6.2f%% %8.6f %6.2f%% %8.6f %6.2f%% %+7.3f%%",
                      i, train_acc * 100.0, train_rmse, validate_acc * 100.0,
                      validate_rmse,
                      best_acc * 100.0, (validate_acc - last_best_acc) * 100.0)
            << endl;

        if (progress) ++(*progress);

        log("perceptron_generator", 5) << current.print() << endl;
    }

    if (profile)
        log("perceptron_generator", 1)
            << "training time: " << timer.elapsed().wall << "s" << endl;

    log("perceptron_generator", 1)
        << format("best was %6.2f%% on iteration %d", best_acc * 100.0,
                  best_iter)
        << endl;

    float trn_acc, trn_rmse, val_acc, val_rmse;
    std::tie(trn_acc, trn_rmse)
        = best.accuracy(training_set);
    std::tie(val_acc, val_rmse)
        = best.accuracy(validation_set);

    log("perceptron_generator", 1)
        << "best accuracy: " << trn_acc << "/"
        << trn_rmse << " train, "
        << val_acc << "/" << val_rmse
        << " validation" << endl;

    log("perceptron_generator", 4) << best.print() << endl;

    return make_sp(best.make_copy());
}

namespace {

boost::multi_array<double, 2>
cholesky(const boost::multi_array<double, 2> & A_)
{
    PROFILE_FUNCTION(t_cholesky);

    if (A_.shape()[0] != A_.shape()[1])
        throw Exception("cholesky: matrix isn't square");

    int n = A_.shape()[0];

    boost::multi_array<double, 2> A(boost::extents[n][n]);
    std::copy(A_.begin(), A_.end(), A.begin());

    int res = LAPack::potrf('U', n, A.data(), n);

    if (res < 0)
        throw Exception(format("cholesky: potrf: argument %d was illegal", -res));
    else if (res > 0)
        throw Exception(format("cholesky: potrf: leading minor %d of %d "
                               "not positive definite", res, n));

    for (unsigned i = 0;  i < n;  ++i)
        std::fill(&A[i][0] + i + 1, &A[i][0] + n, 0.0);

    return A;

#if 0
    //cerr << "residuals = " << endl << (A * transpose(A)) - A_ << endl;

    boost::multi_array<float, 2> result(boost::extents[n][n]);
    std::copy(A.begin(), A.end(), result.begin());

    return result;
#endif
}

template<typename Float>
boost::multi_array<Float, 2>
lower_inverse(const boost::multi_array<Float, 2> & A)
{
    if (A.shape()[0] != A.shape()[1])
        throw Exception("lower_inverse: matrix isn't square");

    int n = A.shape()[0];

    boost::multi_array<Float, 2> L = A;

    for (int j = 0;  j < n;  ++j) {
        L[j][j] = 1.0 / L[j][j];

        for (int i = j + 1;  i < n;  ++i) {
            double sum = 0.0;
            for (unsigned k = j;  k < i;  ++k)
                sum -= L[i][k] * L[k][j];
            L[i][j] = sum / L[i][i];
        }
    }

    //cerr << "L * A = " << endl << L * A << endl;

    return L;
}

} // file scope

/** Decorrelates the training data, returning a dense decorrelated dataset. */
boost::multi_array<float, 2>
Perceptron_Generator::
decorrelate(const Training_Data & data,
            const std::vector<Feature> & possible_features,
            Perceptron & result) const
{
    PROFILE_FUNCTION(t_decorrelate);

    const Dataset_Index & index = data.index();

    vector<Feature> & features = result.features;
    features.clear();

    cerr << "decorrelate: " << possible_features.size() << " features at input"
         << endl;

    /* Figure out if we can keep each feature or not. */

    for (unsigned i = 0;  i < possible_features.size();  ++i) {
        const Feature & feature = possible_features[i];

        if (feature == result.predicted()) continue;  // don't use label as a feature!

        /* Find out information about the feature from the training data. */
        if (!index.dense(feature)) {
            cerr << "feature " << result.feature_space()->print(feature)
                 << " skipped due to missing values" << endl;
            continue;
        }
        else if (!index.exactly_one(feature)) {
            cerr << "feature " << i << " ("
                 << result.feature_space()->print(feature)
                 << ") skipped due to more than one value" << endl;
            continue;
        }
        else if (index.constant(feature)) {
            cerr << "feature " << i << " ("
                 << result.feature_space()->print(feature)
                 << ") skipped as it is constant over the dataset" << endl;
            continue;
        }
        else {
            float min, max;
            std::tie(min, max) = index.range(feature);
            if (abs(min) > 1e10 || abs(max) > 1e10) {
                cerr << "feature " << i << " ("
                     << result.feature_space()->print(feature)
                     << ") skipped as its range is too large: "
                     << min << " to " << max << endl;
                continue;
            }
        }
        features.push_back(feature);
    }

    cerr << "decorrelate: " << features.size()
         << " features after trivial elimination" << endl;

    std::sort(features.begin(), features.end());

    size_t nx = data.example_count();
    size_t nf = features.size();

    /* Get a dense matrix of the features. */
    boost::multi_array<double, 2> input(boost::extents[nx][nf + 1]);

    for (unsigned x = 0;  x < nx;  ++x) {
        result.extract_features(data[x], &input[x][0]);
        input[x][nf] = 1.0;  // bias term
    }

    //cerr << "input.shape()[0] = " << input.shape()[0] << endl;
    //cerr << "input.shape()[1] = " << input.shape()[1] << endl;
    boost::multi_array<double, 2> inputt = transpose(input);

    //cerr << "inputt.shape()[0] = " << inputt.shape()[0] << endl;
    //cerr << "inputt.shape()[1] = " << inputt.shape()[1] << endl;
    vector<distribution<double> > dependent;
    vector<int> permutations(nf + 1, 0);

#if 0
    boost::multi_array<float, 2> input2 = inputt;

    /* Factorize the matrix with partial pivoting.  This allows us to find the
       largest number of linearly independent columns possible. */

    float tau[nf];
    vector<int> permutations(nf + 1, 0);
    permutations[nf] = 1;  // make bias be a leading column

    {
        PROFILE_FUNCTION(t_qr);
        int res = LAPack::geqp3(nx, nf + 1, inputt.data_begin(), inputt.shape()[1],
                                &permutations[0],
                                tau);

        if (res != 0)
            throw Exception(format("geqp3: error in parameter %d", -res));
    }

    cerr << "permutations = " << permutations << endl;
    for (unsigned i = 0;  i <= nf;  ++i)
        cerr << "r[" << i << "][" << i << "] = " << inputt[i][i] << endl;

    /* Check for linearly dependent columns. */
    inputt = input2;
#endif

    {
        PROFILE_FUNCTION(t_gs);
        permutations = remove_dependent_impl(inputt, dependent, 1e-4);
    }

    //cerr << "permutations = " << permutations << endl;

    /* Find which features are left */
    vector<Feature> new_features;
    for (unsigned i = 0;  i < features.size();  ++i) {
        if (permutations[i] != -1) {
            //cerr << "feature " << new_features.size() << " is old feature "
            //     << i << " (" << feature_space->print(features[i]) << ")"
            //     << endl;
            new_features.push_back(features[i]);
        }
    }

    for (unsigned i = 0;  i < features.size();  ++i) {
        if (permutations[i] == -1) {
            cerr << "feature "
                 << result.feature_space()->print(features[i])
                 << " removed as it can be calculated as ";
            cerr << result.feature_space()->print(features[i])
                 << " = ";
            bool first = true;
            for (unsigned j = 0;  j < dependent[i].size();  ++j) {
                double v = dependent[i][j];
                if (abs(v) < 0.0001) continue;

                if (v < 0.0) {
                    cerr << " - ";
                }
                else {
                    if (first) ;
                    else cerr << " + ";
                }

                v = abs(v);
                if (abs(v - 1.0) < 0.0001) ;
                else cerr << setprecision(4) << v << " ";

                if (j == new_features.size()) ;
                else cerr << result.feature_space()->print(new_features[j]);

                first = false;
            }
            cerr << endl;
        }
    }

    /* Calculate the covariance matrix over those that are left.  Note that
       we could decorrelate them with the orthogonalization that we did above,
       but then we wouldn't be able to save it as a covariance matrix.
    */
    features.swap(new_features);
    nf = features.size();

    distribution<double> mean(nf, 0.0);
    distribution<double> stdev(nf, 0.0);
    boost::multi_array<double, 2> covar(boost::extents[nf][nf]);

    if (do_decorrelate && !do_normalize)
        throw Exception("normalization required if decorrelation is done");

    if (do_normalize || do_decorrelate) {
        {
            PROFILE_FUNCTION(t_mean);
            for (unsigned f = 0;  f < nf;  ++f) {
                mean[f] = SIMD::vec_sum_dp(&inputt[f][0], nx) / nx;
                for (unsigned x = 0;  x < nx;  ++x)
                    inputt[f][x] -= mean[f];
            }
        }

        cerr << "mean = " << mean << endl;

        {
            PROFILE_FUNCTION(t_covar);
            for (unsigned f = 0;  f < nf;  ++f) {
                for (unsigned f2 = 0;  f2 <= f;  ++f2)
                    covar[f][f2] = covar[f2][f]
                        = SIMD::vec_dotprod_dp(&inputt[f][0], &inputt[f2][0], nx) / nx;
            }

            for (unsigned f = 0;  f < nf;  ++f)
                stdev[f] = sqrt(covar[f][f]);

            cerr << "stdev = " << stdev << endl;
        }
    }

    boost::multi_array<double, 2> transform(boost::extents[nf][nf]);

    if (do_decorrelate) {
        /* Do the cholevsky stuff */
        PROFILE_FUNCTION(t_cholesky);
        transform = transpose(lower_inverse(cholesky(covar)));
    }
    else if (do_normalize) {
        /* Use a unit diagonal of 1/stdev for the transform; no
           decorrelation */
        std::fill(transform.origin(),
                  transform.origin() + transform.num_elements(),
                  0.0f);
        for (unsigned f = 0;  f < nf;  ++f)
            transform[f][f] = 1.0 / stdev[f];
    }
    else {
        /* Use the identity function */
        std::fill(transform.origin(),
                  transform.origin() + transform.num_elements(),
                  0.0f);
        for (unsigned f = 0;  f < nf;  ++f)
            transform[f][f] = 1.0;
    }

    /* Finally, we add a layer.  This will perform both the removal of the
       mean (via the biasing) and the decorrelation (via the application
       of the matrix).
    */

    /* y = (x - mean) * A;
         = (x * A) - (mean * A);
    */

    std::shared_ptr<Dense_Layer<float> > layer
        (new Dense_Layer<float>("decorrelation", nf, nf, TF_IDENTITY,
                                MV_NONE));
    layer->weights.resize(boost::extents[transform.shape()[0]][transform.shape()[1]]);
    layer->weights = transform;
    layer->bias = distribution<float>(nf, 0.0);  // already have mean removed

    //cerr << "transform = " << transform << endl;

    boost::multi_array<float, 2> decorrelated(boost::extents[nx][nf]);
    float fv_in[nf];

    for (unsigned x = 0;  x < nx;  ++x) {
        for (unsigned f = 0;  f < nf;  ++f)
            fv_in[f] = inputt[f][x];

        //cerr << "fv_in = " << distribution<float>(fv_in, fv_in + nf) << endl;

        layer->apply(&fv_in[0], &decorrelated[x][0]);

        //cerr << "fv_out = "
        //     << distribution<float>(&decorrelated[x][0],
        //                            &decorrelated[x][0] + nf)
        //     << endl;

    }

    layer->bias = (transform * mean) * -1.0;  // now add the bias
    result.layers.clear();
    result.add_layer(layer);

    layer->validate();

    return decorrelated;
}

boost::multi_array<float, 2>
Perceptron_Generator::
init(const Training_Data & data,
     const std::vector<Feature> & possible_features,
     const std::vector<int> & architecture,
     Perceptron & result,
     Thread_Context & context) const
{
    result = model;

    /* Find out about the output that we need (in particular, how many
       values it can have). */
    boost::multi_array<float, 2> decorrelated
        = decorrelate(data, possible_features, result);

    Feature_Info pred_info = model.feature_space()->info(model.predicted());
    int nout = pred_info.value_count();
    if (nout == 0) nout = 1;  // regression problem; one output

    int nunits = result.features.size();

    cerr << "adding decorrelating input layer with " << nunits
         << " linear units" << endl;

    /* Add hidden layers with the specified sizes */
    for (unsigned i = 0;  i < architecture.size();  ++i) {
        int units = architecture[i];
        if (units == -1) units = result.features.size();

        cerr << "adding hidden layer " << i + 1 << " with "
             << units << " units and activation function "
             << activation << endl;

        std::shared_ptr<Layer>
            layer(new Dense_Layer<float>(format("hidden%d", i),
                                         nunits, units, activation,
                                         MV_NONE, context));
        result.add_layer(layer);
        nunits = units;
    }

    /* Add the output units. */
    std::shared_ptr<Layer> layer
        (new Dense_Layer<float>("output", nunits, nout, output_activation,
                                MV_NONE, context));
    result.add_layer(layer);

    cerr << "adding output layer with " << nout << " units and activation "
         << output_activation << endl;

    return decorrelated;
}

/*****************************************************************************/
/* REGISTRATION                                                              */
/*****************************************************************************/

namespace {

Register_Factory<Classifier_Generator, Perceptron_Generator>
    PERCEPTRON_REGISTER("perceptron");

} // file scope

} // namespace ML


#pragma once

#include <functional>
#include <Eigen/Core>

typedef unsigned short ushort;
typedef unsigned char uchar;

namespace bold
{
  /** Produces a map used in sub-sampling image data.
   *
   * A granularity function allows processing fewer than all pixels
   * in the image.
   *
   * Granularity is calculated based on y-value, and is specified in
   * both x and y dimensions.
   */
  class ImageSampleMap
  {
  public:
    ImageSampleMap(std::function<Eigen::Matrix<uchar,2,1>(ushort)> granularityFunction, ushort width, ushort height);

    unsigned getPixelCount() const { return d_pixelCount; }

    ushort getSampleRowCount() const { return static_cast<ushort>(d_granularities.size()); }

    std::vector<Eigen::Matrix<uchar,2,1>>::const_iterator begin() const { return d_granularities.begin(); }

  private:
    std::vector<Eigen::Matrix<uchar,2,1>> d_granularities;
    unsigned d_pixelCount;
    ushort d_width;
  };
}


//
//  Raycaster.hpp
//  KinFu
//
//  Created by Dave on 2/06/2016.
//  Copyright © 2016 Sindesso. All rights reserved.
//

#ifndef Raycaster_hpp
#define Raycaster_hpp

#include <Eigen/Core>

#include "TSDFVolumeCPU.hpp"
#include "Camera.hpp"
#include "DepthImage.hpp"

class Raycaster {
    public:
        explicit Raycaster( int width=640, int height=480) {
            m_width = width;
            m_height = height;
        }

        /**
         * Raycast the TSDF and store discovered vertices and normals in the ubput arrays
         * @param volume The volume to cast
         * @param camera The camera
         * @param vertices The vertices discovered
         * @param normals The normals
         */
        float3cpu * compute_normals(const float3cpu * vertices) const;
        float3cpu * get_vertices(const TSDFVolumeCPU& volume, const Camera& camera) const;
        void raycast( const TSDFVolumeCPU & volume, const Camera & camera, Eigen::Matrix<float, 3, Eigen::Dynamic> &  vertices, Eigen::Matrix<float, 3, Eigen::Dynamic> &  normals ) const;
        void render_to_depth_image( const TSDFVolumeCPU & volume, const Camera & camera ) const;

    protected:

        uint16_t    m_width;
        uint16_t    m_height;

    };
#endif /* Raycaster_hpp */


//---------------------------------------------------------------------------//
// Copyright (c) 2013-2015 Kyle Lutz <kyle.r.lutz@gmail.com>
//
// Distributed under the Boost Software License, Version 1.0
// See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt
//
// See http://boostorg.github.com/compute for more information.
//---------------------------------------------------------------------------//

#include <iostream>
#include <vector>

#include <boost/program_options.hpp>

#include <boost/compute/container/vector.hpp>
#include <boost/compute/core.hpp>
#include <boost/compute/random.hpp>

#include "perf.hpp"

namespace compute = boost::compute;
namespace po = boost::program_options;

template<class Engine>
void perf_random_number_engine(const size_t size,
                               const size_t trials,
                               compute::command_queue& queue)
{
    typedef typename Engine::result_type T;

    // create random number engine
    Engine engine(queue);

    // create vector on the device
    std::cout << "size = " << size << std::endl;
    compute::vector<T> vector(size, queue.get_context());

    // generate random numbers
    perf_timer t;
    for(size_t i = 0; i < trials; i++){
        t.start();
        engine.generate(vector.begin(), vector.end(), queue);
        queue.finish();
        t.stop();
    }

    // print result
    std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl;
    std::cout << "rate: " << perf_rate<T>(size, t.min_time()) << " MB/s" << std::endl;
}

int main(int argc, char *argv[])
{
    // setup and parse command line options
    po::options_description options("options");
    options.add_options()
        ("help", "show usage instructions")
        ("size", po::value<size_t>()->default_value(8192), "number of values")
        ("trials", po::value<size_t>()->default_value(3), "number of trials")
        ("engine", po::value<std::string>()->default_value("default_random_engine"), "random number engine")
    ;
    po::variables_map vm;
    po::store(po::parse_command_line(argc, argv, options), vm);
    po::notify(vm);

    if(vm.count("help")) {
        std::cout << options << std::endl;
        return 0;
    }

    // setup context and queue for the default device
    compute::device device = compute::system::default_device();
    compute::context context(device);
    compute::command_queue queue(context, device);

    // get command line options
    const size_t size = vm["size"].as<size_t>();
    const size_t trials = vm["trials"].as<size_t>();
    const std::string& engine = vm["engine"].as<std::string>();

    // run benchmark
    if(engine == "default_random_engine"){
        perf_random_number_engine<compute::default_random_engine>(size, trials, queue);
    }
    else if(engine == "mersenne_twister_engine"){
        perf_random_number_engine<compute::mt19937>(size, trials, queue);
    }
    else if(engine == "linear_congruential_engine"){
        perf_random_number_engine<compute::linear_congruential_engine<> >(size, trials, queue);
    }
    else if(engine == "threefry_engine"){
        perf_random_number_engine<compute::threefry_engine<> >(size, trials, queue);
    }
    else {
        std::cerr << "error: unknown random number engine '" << engine << "'" << std::endl;
        return -1;
    }

    return 0;
}


#include <boost/static_assert.hpp>
#include <boost/type_traits/is_pod.hpp>

#include <boost/mpl/int.hpp>

namespace detail {
    // Generic implementation.
    template <class T, class Tag>
    T process_impl(const T& val, Tag /*ignore*/) {
        // ...
        BOOST_STATIC_ASSERT(sizeof(val) != 1
                && sizeof(val) != 4
                && sizeof(val) != 8
        );
        return val;
    }

    // 1 byte optimized implementation.
    template <class T>
    T process_impl(const T& val, boost::mpl::int_<1> /*ignore*/) {
        // ...
        BOOST_STATIC_ASSERT(sizeof(val) == 1);
        return val;
    }

    // 4 bytes optimized implementation.
    template <class T>
    T process_impl(const T& val, boost::mpl::int_<4> /*ignore*/) {
        // ...
        BOOST_STATIC_ASSERT(sizeof(val) == 4);
        return val;
    }

    // 8 bytes optimized implementation.
    template <class T>
    T process_impl(const T& val, boost::mpl::int_<8> /*ignore*/) {
        // ...
        BOOST_STATIC_ASSERT(sizeof(val) == 8);
        return val;
    }
} // namespace detail

// Dispatching calls:
template <class T>
T process(const T& val) {
    BOOST_STATIC_ASSERT((boost::is_pod<T>::value));
    return detail::process_impl(val, boost::mpl::int_<sizeof(T)>());
}

template <int Value>
struct int_ {
    static const int value = Value;
    typedef int_<Value> type;
    typedef int value_type;
};

#include <iostream>
int main() {
    std::cout
        << ' ' << process(int(0))
        << ' ' << process(double(1))
        << ' ' << process(float(2))
        << ' ' << process(char(3))
        << ' ' << process(unsigned(4))
        << ' ' << process(short(5))
        << std::endl;
}


#ifndef PYTHONIC_NUMPY_ISNAN_HPP
#define PYTHONIC_NUMPY_ISNAN_HPP

#include "pythonic/include/numpy/isnan.hpp"

#include "pythonic/utils/functor.hpp"
#include "pythonic/types/ndarray.hpp"
#include "pythonic/utils/numpy_traits.hpp"

#include <boost/simd/function/is_nan.hpp>

PYTHONIC_NS_BEGIN

namespace numpy
{
  namespace wrapper
  {
    template <class T>
    bool isnan(std::complex<T> const &v)
    {
      return boost::simd::is_nan(v.real()) || boost::simd::is_nan(v.imag());
    }
    template <class T>
    bool isnan(T const &v)
    {
      return boost::simd::is_nan(v);
    }
  }

#define NUMPY_NARY_FUNC_NAME isnan
#define NUMPY_NARY_FUNC_SYM wrapper::isnan
#include "pythonic/types/numpy_nary_expr.hpp"
}
PYTHONIC_NS_END

#endif


#ifndef MPC_H_INCLUDED
#define MPC_H_INCLUDED

#include <iostream>
#include <fstream>
#include <string>
#include <cmath>
#include <limits>
#include <vector>
#include <Eigen/Core>
#include <Eigen/Dense>
#include "osqp.h"
#include "other/st_to_cc.hpp"

typedef Eigen::MatrixXd matXd;

class MPC {
 private:
  double dt, mass, mu, T_gait, h_ref;
  int n_steps, cpt_ML, cpt_P;

  Eigen::Matrix<double, 3, 3> gI;
  Eigen::Matrix<double, 6, 1> q;
  Eigen::Matrix<double, 6, 1> v = Eigen::Matrix<double, 6, 1>::Zero();
  Eigen::Matrix<double, 3, 4> footholds = Eigen::Matrix<double, 3, 4>::Zero();
  Eigen::Matrix<double, 1, 12> footholds_tmp = Eigen::Matrix<double, 12, 1>::Zero();
  Eigen::Matrix<double, 3, 4> lever_arms = Eigen::Matrix<double, 3, 4>::Zero();
  Eigen::Matrix<int, Eigen::Dynamic, 4> gait;
  Eigen::Matrix<int, Eigen::Dynamic, 4> inv_gait;
  Eigen::Matrix<double, 12, 1> g = Eigen::Matrix<double, 12, 1>::Zero();
  Eigen::Matrix<double, 3, 1> offset_CoM = Eigen::Matrix<double, 3, 1>::Zero();

  Eigen::Matrix<double, 12, 12> A = Eigen::Matrix<double, 12, 12>::Identity();
  Eigen::Matrix<double, 12, 12> B = Eigen::Matrix<double, 12, 12>::Zero();
  Eigen::Matrix<double, 12, 1> x0 = Eigen::Matrix<double, 12, 1>::Zero();
  double x_next[12] = {};
  Eigen::MatrixXd x_f_applied;

  // Matrix ML
  const static int size_nz_ML = 5000;
  // int r_ML [size_nz_ML] = {}; // row indexes of non-zero values in matrix ML
  // int c_ML [size_nz_ML] = {}; // col indexes of non-zero values in matrix ML
  // double v_ML [size_nz_ML] = {};  // non-zero values in matrix ML
  // csc* ML_triplet; // Compressed Sparse Column matrix (triplet format)
  csc *ML;  // Compressed Sparse Column matrix
  inline void add_to_ML(int i, int j, double v, int *r_ML, int *c_ML,
                        double *v_ML);                                            // function to fill the triplet r/c/v
  inline void add_to_P(int i, int j, double v, int *r_P, int *c_P, double *v_P);  // function to fill the triplet r/c/v

  // Indices that are used to udpate ML
  int i_x_B[12 * 4] = {};
  int i_y_B[12 * 4] = {};
  int i_update_B[12 * 4] = {};
  // TODO FOR S ????

  // Matrix NK
  const static int size_nz_NK = 5000;
  double v_NK_up[size_nz_NK] = {};   // maxtrix NK (upper bound)
  double v_NK_low[size_nz_NK] = {};  // maxtrix NK (lower bound)
  double v_warmxf[size_nz_NK] = {};  // maxtrix NK (lower bound)

  // Matrix P
  const static int size_nz_P = 5000;
  // c_int r_P [size_nz_P] = {}; // row indexes of non-zero values in matrix ML
  // c_int c_P [size_nz_P] = {}; // col indexes of non-zero values in matrix ML
  // c_float v_P [size_nz_P] = {};  // non-zero values in matrix ML
  csc *P;  // Compressed Sparse Column matrix

  // Matrix Q
  const static int size_nz_Q = 5000;
  double Q[size_nz_Q] = {};  // Q is full of zeros

  // OSQP solver variables
  OSQPWorkspace *workspce = new OSQPWorkspace();
  OSQPData *data;
  OSQPSettings *settings = (OSQPSettings *)c_malloc(sizeof(OSQPSettings));

  // Matrices whose size depends on the arguments sent to the constructor function
  Eigen::Matrix<double, 12, Eigen::Dynamic> xref;
  Eigen::Matrix<double, Eigen::Dynamic, 1> x;
  Eigen::Matrix<int, Eigen::Dynamic, 1> S_gait;
  Eigen::Matrix<double, Eigen::Dynamic, 1> warmxf;
  Eigen::Matrix<double, Eigen::Dynamic, 1> NK_up;
  Eigen::Matrix<double, Eigen::Dynamic, 1> NK_low;
  Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> D;
  Eigen::Matrix<int, Eigen::Dynamic, 1> i_off;

 public:
  MPC();
  MPC(double dt_in, int n_steps_in, double T_gait_in, int N_gait);

  int create_matrices();
  int create_ML();
  int create_NK();
  int create_weight_matrices();
  int update_matrices(Eigen::MatrixXd fsteps);
  int update_ML(Eigen::MatrixXd fsteps);
  int update_NK();
  int call_solver(int);
  int retrieve_result();
  double *get_x_next();
  int run(int num_iter, const Eigen::MatrixXd &xref_in, const Eigen::MatrixXd &fsteps_in);

  Eigen::Matrix<double, 3, 3> getSkew(Eigen::Matrix<double, 3, 1> v);
  int construct_S();
  int construct_gait(Eigen::MatrixXd fsteps_in);

  // Getters
  Eigen::MatrixXd get_latest_result();
  Eigen::MatrixXd get_gait();
  Eigen::MatrixXd get_Sgait();

  // Utils
  double gethref() { return h_ref; }
  void my_print_csc_matrix(csc *M, const char *name);
  void save_csc_matrix(csc *M, std::string filename);
  void save_dns_matrix(double *M, int size, std::string filename);

  // Bindings
  void run_python(const matXd &xref_py, const matXd &fsteps_py);

  // Eigen::Matrix<double, 12, 12> getA() { return A; }
  // Eigen::MatrixXf getML() { return ML; }
  /*void setDate(int year, int month, int day);
  int getYear();
  int getMonth();
  int getDay();*/
};

#endif  // MPC_H_INCLUDED


#include "hsm/hsm.h"

#include <gtest/gtest.h>

#include <boost/hana.hpp>
#include <boost/mp11.hpp>

using namespace ::testing;

class IndexMapTests : public Test {
};

class S1 {
};
class S2 {
};

TEST_F(IndexMapTests, should_make_index_map)
{
    auto T1 = boost::hana::typeid_(S1 {});
    auto T2 = boost::hana::typeid_(S2 {});

    auto tuple = boost::hana::make_tuple(T1, T2);
    auto indexMap = hsm::make_index_map(tuple);

    ASSERT_EQ(boost::hana::size_c<0>, boost::hana::find(indexMap, T1).value());
    ASSERT_EQ(boost::hana::size_c<1>, boost::hana::find(indexMap, T2).value());
}

// TEST_F(IndexMapTests, should_make_reverse_index_map)
// {
//     auto T1 = boost::hana::typeid_(S1 {});
//     auto T2 = boost::hana::typeid_(S2 {});

//     auto tuple = boost::hana::make_tuple(T1, T2);
//     auto reverseIndexMap = hsm::make_reverse_index_map(tuple);

//     ASSERT_EQ(boost::hana::size_c<2>, boost::hana::size(reverseIndexMap));

//     hsm::find(reverseIndexMap, 0, [T1](auto&& element){ASSERT_EQ(T1, element);});
//     hsm::find(reverseIndexMap, 1, [T2](auto&& element){ASSERT_EQ(T2, element);});
// }

TEST_F(IndexMapTests, should_return_index_of_tuple)
{
    auto T1 = boost::hana::typeid_(S1 {});
    auto T2 = boost::hana::typeid_(S2 {});

    auto tuple = boost::hana::make_tuple(T1, T2);

    ASSERT_EQ(boost::hana::size_c<0>, hsm::index_of(tuple, T1));
    ASSERT_EQ(boost::hana::size_c<1>, hsm::index_of(tuple, T2));
}


//#include <boost/assign/std/vector.hpp>
#include <iostream>
#include <set>
#include <queue>
#include <vector>
#include <hash_set>

#include <list>

#include <vector>

using namespace std;
using __gnu_cxx::hash_set;
//necessário para inicialização de vectors

//using namespace boost::assign;
using namespace std;
class State {

   public:
    /*
     * o estado fornece a posição de cada veículo, utilizando a seguinte convenção :
     * para um veículo horizontal é a coluna da casa mais à esquerda
     * para um veículo vertical é a coluna da casa mais acima
     * (lembrete: a coluna mais à esquerda é 0, e a linha mais alta é 0)
     */
    vector<int> pos;

    /*
     * nós guardamos qual o deslocamento levou a este estado
     */
    int c;
    int d;
    State* prev;

    /*
     * constrói um estado inicial (c e d recebem qualquer valor = lixo)
     */
    State(vector<int>& p) {
        //pos = new int[p.size()];
        int tam = p.size();
        for (int i = 0; i < tam; i++)
            pos.push_back(p[i]);
        prev = NULL;
    }

    /*
     * constrói um estado obtido a partir de s deslocando-se o veículo c de d (-1 ou +1)
     */
    State(State* s, int c, int d) {
        // A SER COMPLETADO
    }

    // nós ganhamos?
    bool success() {
        return true; // A SER COMPLETADO
    }

    bool equals(State* s) {
        if (s->pos.size() != pos.size()){
            cerr << "Estados de comprimento diferentes" << endl;
            exit(1);
        }
        int tamanho = pos.size();

        for (int i = 0; i < tamanho; i++)
            if (pos[i] != s->pos[i]) return false;
        return true;
    }

};

//necessário para uso de hash_set

//função hash
struct hash_state
{
   size_t operator()(const State* t) const
   {
     int h = 0;

     for (int i = 0; i < t->pos.size(); i++)
            h = 37 * h + t->pos[i];

     return h;
   }
};

//função igualdade para hash_set
struct eq_state
{
   bool operator()(const State* t1, const State* t2) const {

       if(t1->pos.size() != t2->pos.size()) return false;
       for(int i=0; i < t1->pos.size(); i++){
               if(t1->pos[i] != t2->pos[i]) return false;

       }
	  return true;
   }
};

class RushHour {

      public:

    /*
     * a representação do problema é :
     * a grade tem 6 colunas, numeradas 0 a 5 de esquerda para direita
     * e 6 linhas, numeradas de 0 a  5 de cima para baixo
     *
     * existem nbcars carros, numerados de 0 a  nbcars-1
     * para cada veículo i :
     * - color[i] fornece sua cor
     * - horiz[i] indica se temos um carro na horizontal
     * - len[i] fornece o seu comprimento (2 ou 3)
     * - moveon[i] indica em qual linha o carro se desloca para um carro horizontal
     *   e em qual coluna para um carro vertical
     *
     * o veiculo de indice 0 é o que tem que sair, temos então
     * horiz[0]==true, len[0]==2, moveon[0]==2
     */

    int nbcars;
    vector<string> color;
    vector<bool> horiz;
    vector<int> len;
    vector<int> moveon;

    int nbMoves;
    /*
     * a matriz free é utilizada em moves para determinar rapidamente se a casa (i,j) está livre
     */
    bool free[6][6];

    void initFree(State* s) {
        // A SER COMPLETADA
    }

    /*
     * retorna a lista de deslocamentos a partir de s
     */

    list<State*> moves(State* s) {
        initFree(s);
        list<State*> l;
        // A SER COMPLETADA
        return l;
    }

    /*
     * procura uma solução a partir de s
     */
    State* solve(State* s) {
        hash_set<State*,hash_state,eq_state> visited;
        visited.insert(s);
        queue<State*> Q;
        Q.push(s);
        while (!Q.empty()) {
            // A SER COMPLETADO
        }
        cerr << "sem solução" << endl; exit(1);
    }

    /*
     * imprime uma solução
     */

    void printSolution(State* s) {
        // A SER COMPLETADO
    }

};

void test1() {

	int positioning[] = {1,0,1,4,2,4,0,1};
	vector<int> start(positioning, positioning+8);
	State* s0 = new State(start);
	cout << (!s0->success()) << endl;
	State* s = new State(s0, 1, 1);

	cout << (s->prev == s0) << endl;
	cout << s0->pos[1] << " " << s->pos[1] << endl;

	s = new State(s,6,1);
	s = new State(s,1,-1);
	s = new State(s,6,-1);

	cout << s->equals(s0) << endl;

	s = new State(s0,1,1);
	s = new State(s,2,-1);
	s = new State(s,3,-1);
	s = new State(s,4,-1); s = new State(s, 4, -1);
	s = new State(s,5,-1); s = new State(s,5,-1); s = new State(s,5,-1);
	s = new State(s,6,1); s = new State(s, 6, 1); s = new State(s, 6, 1);
	s = new State(s,7,1); s = new State(s, 7, 1);
	s = new State(s,0,1); s = new State(s,0,1); s = new State(s,0,1);

	cout << (s->success()) << endl;
}

int main(){

	return 0;
	}


//==================================================================================================
/*!
  @file

  @copyright 2016 NumScale SAS
  @copyright 2016 J.T. Lapreste

  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
*/
//==================================================================================================
#ifndef BOOST_SIMD_FUNCTION_SUBS_HPP_INCLUDED
#define BOOST_SIMD_FUNCTION_SUBS_HPP_INCLUDED

#if defined(DOXYGEN_ONLY)
namespace boost { namespace simd
{

 /*!

    @ingroup group-arithmetic
    Function object implementing subs capabilities

    Computes the saturated difference of its parameters.

    @par semantic:
    For any given value @c x,  @c y of type @c T:

    @code
    T r = subs(x, y);
    @endcode

    This function coincides with @ref minus for floating point parameters.
    For integral type, it is similar to:

    @code
    T r = (x-y > Valmax) ? Valmax : (x-y < Valmin ? Valmin : x-y);
    @endcode

  **/
  const boost::dispatch::functor<tag::subs_> subs = {};

} }
#endif

#include <boost/simd/function/scalar/subs.hpp>
#include <boost/simd/function/simd/subs.hpp>

#endif