#ifndef EXTRACTORS_DEFAULT_HPP
#define EXTRACTORS_DEFAULT_HPP

/// COMPONENT
#include <csapex_vision_features/extractor_manager.h>

/// PROJECT
#include <csapex/param/parameter_factory.h>

/// SYSTEM
#include <opencv2/features2d/features2d.hpp>
#if CV_NON_FREE
#include <opencv2/nonfree/nonfree.hpp>
#endif
#include <boost/bind.hpp>
#include <boost/static_assert.hpp>

using namespace csapex;
using namespace param;

/// COMBINATIONS

struct Orb : public ExtractorManager::ExtractorInitializer
{
    EXTRACTOR_IMPLEMENTATION

    struct KeyParams : public ExtractorManager::Params
    {
        KeyParams()
        {
            add(ParameterFactory::declareRange("orb/extractor_threshold", 0, 200, 50, 1));
            add(ParameterFactory::declareRange("orb/levels", 1, 20, 8, 1));
            add(ParameterFactory::declareRange("orb/edgeThreshold", 0, 64, 0, 1));
            add(ParameterFactory::declareRange("orb/first_level", 0, 8, 0, 1));
            add(ParameterFactory::declareRange("orb/WTA_K", 2, 4, 2, 1));
            add(ParameterFactory::declareRange("orb/patch_size", 0, 128, 31, 1));

            add(ParameterFactory::declareRange("orb/scale", 0.5, 2.0, 1.2, 0.05));

            std::map<std::string, int> set;
            set["ORB::HARRIS_SCORE"] = cv::ORB::HARRIS_SCORE;
            set["ORB::FAST_SCORE"] = cv::ORB::FAST_SCORE;
            add(ParameterFactory::declareParameterSet("orb/type", set, (int)cv::ORB::HARRIS_SCORE));
        }
    };
    static KeyParams& params()
    {
        static KeyParams p;
        return p;
    }
    static std::vector<Parameter::Ptr> usedParameters()
    {
        return params().params;
    }

    static void keypoint(Extractor* e, const csapex::param::ParameterProvider& param, bool complete)
    {
        int et = params().read<int>(param, "orb/extractor_threshold");
        double scale = params().read<double>(param, "orb/scale");
        int levels = params().read<int>(param, "orb/levels");
        int edge = params().read<int>(param, "orb/edgeThreshold");
        int first_level = params().read<int>(param, "orb/first_level");
        int WTA_K = params().read<int>(param, "orb/WTA_K");
        int patch_size = params().read<int>(param, "orb/patch_size");
        int type = params().read<int>(param, "orb/type");

        e->keypoint = "orb";
        e->has_orientation = true;
#if CV_MAJOR_VERSION == 2
        e->detector = new cv::ORB((200 - et) * 10, scale, levels, edge, first_level, WTA_K, type, patch_size);
#elif CV_MAJOR_VERSION == 3
        e->detector = cv::ORB::create((200 - et) * 10, scale, levels, edge, first_level, WTA_K, type, patch_size);
#elif CV_MAJOR_VERSION > 3
        e->detector = cv::ORB::create((200 - et) * 10, scale, levels, edge, first_level, WTA_K, cv::ORB::ScoreType(type), patch_size);
#endif

        if (complete) {
            e->is_binary = true;
            e->descriptor = "orb";
            e->descriptor_extractor = e->detector;
        }
    }

    static void descriptor(Extractor* e, const csapex::param::ParameterProvider& param)
    {
        e->is_binary = true;
        e->descriptor = "orb";
#if CV_MAJOR_VERSION == 2
        e->descriptor_extractor = new cv::ORB();
#elif CV_MAJOR_VERSION >= 3
        e->descriptor_extractor = cv::ORB::create();
#endif
    }
};
REGISTER_FEATURE_DETECTOR(Orb, ORB)
static_assert(DetectorTraits<Orb>::HasKeypoint);
static_assert(DetectorTraits<Orb>::HasDescriptor);

struct Brisk : public ExtractorManager::ExtractorInitializer
{
    EXTRACTOR_IMPLEMENTATION

    struct KeyParams : public ExtractorManager::Params
    {
        KeyParams()
        {
            add(ParameterFactory::declareRange("brisk/extractor_threshold", 0, 1000, 50, 1));
            add(ParameterFactory::declareRange("brisk/octaves", 0, 10, 4, 1));
            add(ParameterFactory::declareRange("brisk/pattern_scale", 0.2, 10.0, 2.0, 0.1));
        }
    };
    static KeyParams& params()
    {
        static KeyParams p;
        return p;
    }
    static std::vector<Parameter::Ptr> usedParameters()
    {
        return params().params;
    }

    static void keypoint(Extractor* e, const csapex::param::ParameterProvider& param, bool complete)
    {
        int et = params().read<int>(param, "brisk/extractor_threshold");
        int octaves = params().read<int>(param, "brisk/octaves");
        double scale = params().read<double>(param, "brisk/pattern_scale");

        e->keypoint = "brisk";
        e->has_orientation = true;
#if CV_MAJOR_VERSION == 2
        e->detector = new cv::BRISK(et, octaves, scale);
#elif CV_MAJOR_VERSION >= 3
        e->descriptor_extractor = cv::BRISK::create(et, octaves, scale);
#endif
        if (complete) {
            e->is_binary = true;
            e->descriptor = "brisk";
            e->descriptor_extractor = e->detector;
        }
    }

    static void descriptor(Extractor* e, const csapex::param::ParameterProvider& param)
    {
        int et = params().read<int>(param, "brisk/extractor_threshold");
        int octaves = params().read<int>(param, "brisk/octaves");

        e->is_binary = true;
        e->descriptor = "brisk";
#if CV_MAJOR_VERSION == 2
        e->descriptor_extractor = new cv::BRISK(et, octaves);
#elif CV_MAJOR_VERSION >= 3
        e->descriptor_extractor = cv::BRISK::create(et, octaves);
#endif
    }
};
REGISTER_FEATURE_DETECTOR(Brisk, BRISK)
static_assert(DetectorTraits<Brisk>::HasKeypoint);
static_assert(DetectorTraits<Brisk>::HasDescriptor);

#if CV_NON_FREE
struct Sift : public ExtractorManager::ExtractorInitializer
{
    EXTRACTOR_IMPLEMENTATION

    struct KeyParams : public ExtractorManager::Params
    {
        KeyParams()
        {
            add(ParameterFactory::declareRange("sift/extractor_threshold", 0, 1000, 50, 1));
            add(ParameterFactory::declareRange("sift/nOctaveLayers", 0, 5, 3, 1));
            add(ParameterFactory::declareRange("sift/contrastThreshold", 0.0, 1.0, 0.04, 0.005));
            add(ParameterFactory::declareRange("sift/edgeThreshold", 0.0, 100.0, 10.0, 1.0));
            add(ParameterFactory::declareRange("sift/sigma", 0.0, 5.0, 1.6, 0.01));
        }
    };
    static KeyParams& params()
    {
        static KeyParams p;
        return p;
    }
    static std::vector<Parameter::Ptr> usedParameters()
    {
        return params().params;
    }
    static void keypoint(Extractor* e, const csapex::param::ParameterProvider& param, bool complete)
    {
        int et = params().read<int>(param, "sift/extractor_threshold");
        int nOctaveLayers = params().read<int>(param, "sift/nOctaveLayers");
        double contrastThreshold = params().read<double>(param, "sift/contrastThreshold");
        double edgeThreshold = params().read<double>(param, "sift/edgeThreshold");
        double sigma = params().read<double>(param, "sift/sigma");
        e->keypoint = "sift";
        e->has_orientation = true;
        e->detector = new cv::SiftFeatureDetector(et * 0.002 / 3, nOctaveLayers, contrastThreshold, edgeThreshold, sigma);

        if (complete) {
            e->is_binary = false;
            e->descriptor = "sift";
            e->descriptor_extractor = e->detector;
        }
    }

    static void descriptor(Extractor* e, const csapex::param::ParameterProvider& param)
    {
        e->is_binary = false;
        e->descriptor = "sift";
        e->descriptor_extractor = new cv::SiftDescriptorExtractor();
    }
};
REGISTER_FEATURE_DETECTOR(Sift, SIFT);
static_assert(DetectorTraits<Sift>::HasKeypoint);
static_assert(DetectorTraits<Sift>::HasDescriptor);

struct Surf : public ExtractorManager::ExtractorInitializer
{
    EXTRACTOR_IMPLEMENTATION

    struct KeyParams : public ExtractorManager::Params
    {
        KeyParams()
        {
            add(ParameterFactory::declareRange("surf/extractor_threshold", 0, 5000, 1000, 1));
            add(ParameterFactory::declareRange("surf/nOctaves", 0, 10, 4, 1));
            add(ParameterFactory::declareRange("surf/nOctaveLayers", 0, 10, 2, 1));
            add(ParameterFactory::declareBool("surf/extended", true));
            add(ParameterFactory::declareBool("surf/upright", false));
        }
    };
    static KeyParams& params()
    {
        static KeyParams p;
        return p;
    }
    static std::vector<Parameter::Ptr> usedParameters()
    {
        return params().params;
    }

    static void keypoint(Extractor* e, const csapex::param::ParameterProvider& param, bool complete)
    {
        int et = params().read<int>(param, "surf/extractor_threshold");
        int nOctaves = params().read<int>(param, "surf/nOctaves");
        int nOctaveLayers = params().read<int>(param, "surf/nOctaveLayers");
        bool extended = params().read<bool>(param, "surf/extended");
        bool upright = params().read<bool>(param, "surf/upright");

        e->keypoint = "surf";
        e->has_orientation = true;
        e->detector = new cv::SurfFeatureDetector(et, nOctaves, nOctaveLayers, extended, upright);

        if (complete) {
            e->is_binary = false;
            e->descriptor = "surf";
            e->descriptor_extractor = e->detector;
        }
    }

    static void descriptor(Extractor* e, const csapex::param::ParameterProvider& param)
    {
        e->is_binary = false;
        e->descriptor = "surf";
        e->descriptor_extractor = new cv::SurfDescriptorExtractor();
    }
};
REGISTER_FEATURE_DETECTOR(Surf, SURF);
static_assert(DetectorTraits<Surf>::HasKeypoint);
static_assert(DetectorTraits<Surf>::HasDescriptor);
#endif

/// KEYPOINTS ONLY

struct Fast : public ExtractorManager::ExtractorInitializer
{
    EXTRACTOR_IMPLEMENTATION

    struct KeyParams : public ExtractorManager::Params
    {
        KeyParams()
        {
            add(ParameterFactory::declareRange("fast/extractor_threshold", 0, 200, 50, 1));
            add(ParameterFactory::declareBool("fast/nonmaxSuppression", true));
        }
    };
    static KeyParams& params()
    {
        static KeyParams p;
        return p;
    }
    static std::vector<Parameter::Ptr> usedParameters()
    {
        return params().params;
    }

    static void keypoint(Extractor* e, const csapex::param::ParameterProvider& param, bool complete)
    {
        int et = params().read<int>(param, "fast/extractor_threshold");
        bool nonmaxSuppression = params().read<bool>(param, "fast/nonmaxSuppression");
        e->keypoint = "fast";
        e->has_orientation = false;
#if CV_MAJOR_VERSION == 2
        e->detector = new cv::FastFeatureDetector(et, nonmaxSuppression);
#elif CV_MAJOR_VERSION >= 3
        e->detector = cv::FastFeatureDetector::create(et, nonmaxSuppression);
#endif
    }
};
REGISTER_FEATURE_DETECTOR(Fast, FAST)
static_assert(DetectorTraits<Fast>::HasKeypoint);
static_assert(!DetectorTraits<Fast>::HasDescriptor);

struct Mser : public ExtractorManager::ExtractorInitializer
{
    EXTRACTOR_IMPLEMENTATION

    struct KeyParams : public ExtractorManager::Params
    {
        KeyParams()
        {
            add(ParameterFactory::declareRange("mser/delta", 0, 50, 5, 1));
            add(ParameterFactory::declareRange("mser/minArea", 0, 1000, 60, 1));
            add(ParameterFactory::declareRange("mser/maxArea", 0, 30000, 14400, 1));
            add(ParameterFactory::declareRange("mser/maxVariation", 0.0, 1.0, 0.25, 0.01));
            add(ParameterFactory::declareRange("mser/minDiversity", 0.0, 1.0, 0.2, 0.01));
            add(ParameterFactory::declareRange("mser/maxEvolution", 0, 1000, 200, 1));
            add(ParameterFactory::declareRange("mser/areaThreshold", 0.0, 2.0, 1.01, 0.01));
            add(ParameterFactory::declareRange("mser/minMargin", 0.0, 0.1, 0.003, 0.001));
            add(ParameterFactory::declareRange("mser/edgeBlurSize", 0, 50, 5, 1));
        }
    };
    static KeyParams& params()
    {
        static KeyParams p;
        return p;
    }
    static std::vector<Parameter::Ptr> usedParameters()
    {
        return params().params;
    }

    static void keypoint(Extractor* e, const csapex::param::ParameterProvider& param, bool complete)
    {
        int delta = params().read<int>(param, "mser/delta");
        int minArea = params().read<int>(param, "mser/minArea");
        int maxArea = params().read<int>(param, "mser/maxArea");
        double maxVariation = params().read<double>(param, "mser/maxVariation");
        double minDiversity = params().read<double>(param, "mser/minDiversity");
        int maxEvolution = params().read<int>(param, "mser/maxEvolution");
        double areaThreshold = params().read<double>(param, "mser/areaThreshold");
        double minMargin = params().read<double>(param, "mser/minMargin");
        int edgeBlurSize = params().read<int>(param, "mser/edgeBlurSize");

        e->keypoint = "mser";
        e->has_orientation = true;

#if CV_MAJOR_VERSION == 2
        e->detector = new cv::MSER(delta, minArea, maxArea, maxVariation, minDiversity, maxEvolution, areaThreshold, minMargin, edgeBlurSize);
#elif CV_MAJOR_VERSION >= 3
        e->detector = cv::MSER::create(delta, minArea, maxArea, maxVariation, minDiversity, maxEvolution, areaThreshold, minMargin, edgeBlurSize);
#endif
    }
};
REGISTER_FEATURE_DETECTOR(Mser, MSER)
static_assert(DetectorTraits<Mser>::HasKeypoint);
static_assert(!DetectorTraits<Mser>::HasDescriptor);

#if CV_MAJOR_VERSION == 2

struct Star : public ExtractorManager::ExtractorInitializer
{
    EXTRACTOR_IMPLEMENTATION

    struct KeyParams : public ExtractorManager::Params
    {
        KeyParams()
        {
            add(ParameterFactory::declareRange("star/extractor_threshold", 0, 1000, 50, 1));
        }
    };
    static KeyParams& params()
    {
        static KeyParams p;
        return p;
    }
    static std::vector<Parameter::Ptr> usedParameters()
    {
        return params().params;
    }

    static void keypoint(Extractor* e, const csapex::param::ParameterProvider& param, bool complete)
    {
        int et = params().read<int>(param, "star/extractor_threshold");

        e->keypoint = "star";
        e->has_orientation = true;

        e->detector = new cv::StarFeatureDetector(16, et);
    }
};
REGISTER_FEATURE_DETECTOR(Star, STAR);
static_assert(DetectorTraits<Star>::HasKeypoint);
static_assert(!DetectorTraits<Star>::HasDescriptor);

#endif

struct Gftt : public ExtractorManager::ExtractorInitializer
{
    EXTRACTOR_IMPLEMENTATION

    struct KeyParams : public ExtractorManager::Params
    {
        KeyParams()
        {
            add(ParameterFactory::declareRange("gftt/extractor_threshold", 0, 1000, 50, 1));
        }
    };
    static KeyParams& params()
    {
        static KeyParams p;
        return p;
    }
    static std::vector<Parameter::Ptr> usedParameters()
    {
        return params().params;
    }

    static void keypoint(Extractor* e, const csapex::param::ParameterProvider& param, bool complete)
    {
        int et = params().read<int>(param, "gftt/extractor_threshold");

        e->keypoint = "gftt";
        e->has_orientation = true;

#if CV_MAJOR_VERSION == 2
        e->detector = new cv::GoodFeaturesToTrackDetector(et * 50.0, 0.005);
#elif CV_MAJOR_VERSION >= 3
        e->detector = cv::GFTTDetector::create(et * 50.0, 0.005);
#endif
    }
};
REGISTER_FEATURE_DETECTOR(Gftt, GFTT)
static_assert(DetectorTraits<Gftt>::HasKeypoint);
static_assert(!DetectorTraits<Gftt>::HasDescriptor);

struct GfttHarris : public ExtractorManager::ExtractorInitializer
{
    EXTRACTOR_IMPLEMENTATION

    struct KeyParams : public ExtractorManager::Params
    {
        KeyParams()
        {
            add(ParameterFactory::declareRange("gftth/extractor_threshold", 0, 1000, 50, 1));
        }
    };
    static KeyParams& params()
    {
        static KeyParams p;
        return p;
    }
    static std::vector<Parameter::Ptr> usedParameters()
    {
        return params().params;
    }

    static void keypoint(Extractor* e, const csapex::param::ParameterProvider& param, bool complete)
    {
        int et = params().read<int>(param, "gftth/extractor_threshold");

        e->keypoint = "gftt_harris";
        e->has_orientation = true;

#if CV_MAJOR_VERSION == 2
        e->detector = new cv::GoodFeaturesToTrackDetector(et * 50.0, 0.005, 2, 3, true);
#elif CV_MAJOR_VERSION >= 3
        e->detector = cv::GFTTDetector::create(et * 50.0, 0.005, 2, 3, true);
#endif
    }
};
REGISTER_FEATURE_DETECTOR(GfttHarris, GFTT_HARRIS)
static_assert(DetectorTraits<GfttHarris>::HasKeypoint);
static_assert(!DetectorTraits<GfttHarris>::HasDescriptor);

/// DESCRIPTORS ONLY

#if CV_MAJOR_VERSION == 2

struct Brief : public ExtractorManager::ExtractorInitializer
{
    EXTRACTOR_IMPLEMENTATION

    struct KeyParams : public ExtractorManager::Params
    {
        KeyParams()
        {
        }
    };
    static KeyParams& params()
    {
        static KeyParams p;
        return p;
    }
    static std::vector<Parameter::Ptr> usedParameters()
    {
        return params().params;
    }

    static void descriptor(Extractor* e, const csapex::param::ParameterProvider& param)
    {
        e->is_binary = true;
        e->descriptor = "brief";

#if CV_MAJOR_VERSION == 2
        e->descriptor_extractor = new cv::BriefDescriptorExtractor(64);
#elif CV_MAJOR_VERSION >= 3
        e->descriptor_extractor = cv::BriefDescriptorExtractor(64);
#endif
    }
};
REGISTER_FEATURE_DETECTOR(Brief, BRIEF);
static_assert(!DetectorTraits<Brief>::HasKeypoint);
static_assert(DetectorTraits<Brief>::HasDescriptor);

struct Freak : public ExtractorManager::ExtractorInitializer
{
    EXTRACTOR_IMPLEMENTATION

    struct KeyParams : public ExtractorManager::Params
    {
        KeyParams()
        {
        }
    };
    static KeyParams& params()
    {
        static KeyParams p;
        return p;
    }
    static std::vector<Parameter::Ptr> usedParameters()
    {
        return params().params;
    }

    static void descriptor(Extractor* e, const csapex::param::ParameterProvider& param)
    {
        e->is_binary = true;
        e->descriptor = "freak";
        e->descriptor_extractor = new cv::FREAK();
    }
};
REGISTER_FEATURE_DETECTOR(Freak, FREAK);
static_assert(!DetectorTraits<Freak>::HasKeypoint);
static_assert(DetectorTraits<Freak>::HasDescriptor);

#endif
#endif  // EXTRACTORS_DEFAULT_HPP


/* training_data_tool.cc
   Jeremy Barnes, 4 February 2004
   Copyright (c) 2004 Jeremy Barnes.  All rights reserved.
   This file is part of MLDB. Copyright 2015 mldb.ai inc. All rights reserved.

   A tool to analyze training data sets.
*/

#include "mldb/plugins/jml/jml/training_data.h"
#include "mldb/plugins/jml/jml/training_index.h"
#include "mldb/plugins/jml/jml/dense_features.h"
#include "boosting_tool_common.h"
#include "mldb/utils/file_functions.h"
#include "mldb/base/parse_context.h"
#include "mldb/plugins/jml/stats/moments.h"
#include "mldb/utils/pair_utils.h"
#include "utils/sparse_distribution.h"
#include "mldb/utils/vector_utils.h"
#include "mldb/utils/floating_point.h"

#include <iterator>
#include <iostream>
#include <set>
#include <cmath>

#include <boost/math/distributions/normal.hpp>

#include <boost/program_options/cmdline.hpp>
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/positional_options.hpp>
#include <boost/program_options/parsers.hpp>
#include <boost/program_options/variables_map.hpp>

using namespace std;

using namespace ML;

/** Return the iterator before.  Requires a bidirectional iterator. */
template<class Iterator>
Iterator pred(Iterator it)
{
    it--;
    return it;
}

/** Return the iterator after.  Requires a forward iterator. */
template<class Iterator>
Iterator succ(Iterator it)
{
    it++;
    return it;
}

/** Structure to contain stats on a variable. */
struct Variable_Stats {
    Variable_Stats()
    {
        clear();
    }

    void clear()
    {
        counts.clear();
        total_count = missing = denorm = 0;
        min = max = range = mean = mode = median = stddev = NAN;
        label_totals.clear();
        label_min.clear();
        label_max.clear();
        label_counts.clear();
    }

    /** Count of unique values of the variable. */
    typedef map<double, int> counts_type;
    counts_type counts;

    /** Total count of all variables. */
    size_t total_count;

    /** Number which were missing (NaN) */
    size_t missing;

    /** Number which were denormalized (usually infinite) */
    size_t denorm;

    /** Statistics. */
    double min;
    double max;
    double range;
    double mode;
    double mean;
    double median;
    double stddev;
    double r_squared;
    double b;

    // Only for when we have two labels
    distribution<double> label_totals;
    distribution<double> label_min;
    distribution<double> label_max;
    distribution<double> label_counts;

    /** Add an instance to the stats. */
    void add(double val)
    {
        counts[val] += 1;
    }

    /** Calculate the stats from the values accumulated. */
    void calc_from_counts()
    {
        /* Min and max are very easy. */
        if (counts.empty()) { min = NAN;  max = NAN;  range = NAN; }
        if (counts.size() > 0) {
            min = counts.begin()->first;
            max = pred(counts.end())->first;
            range = max - min;
        }

        /* Scan through and find the median and mode. */
        size_t pos = 0;
        size_t mode_count = 0;
        //double prev = NAN;
        vector<double> data;
        for (counts_type::const_iterator it = counts.begin();
             it != counts.end();  ++it) {
            double val = it->first;
            size_t count = it->second;

            if (count > mode_count) {
                mode = val;
                mode_count = count;
            }

            if (pos <= total_count / 2 && pos + count > total_count / 2)
                median = val;

            for (unsigned i = 0;  i < count;  ++i) data.push_back(val);
        }

        /* Scan through and calculate the mean and standard deviation. */
        mean = ML::mean(data.begin(), data.end());
        stddev = std_dev(data.begin(), data.end(), mean);
    }

    /** Calculate from a vector of values. */
    void calc(vector<float> values, const vector<double> & labels, int nl)
    {
        clear();

        if (nl == 2) {
            label_totals.resize(nl);
            label_min.resize(nl, INFINITY);
            label_max.resize(nl, -INFINITY);
            label_counts.resize(nl);
        }

        /* Calculate the r-squared. */
        double sum_vsq = 0.0, sum_v = 0.0, sum_lsq = 0.0, sum_l = 0.0;
        double sum_vl = 0.0, n = 0.0;
        for (unsigned i = 0;  i < values.size();  ++i) {
            double v = values[i], l = labels[i];
            if (!finite(v)) continue;
            sum_vsq += v*v;  sum_v += v;
            sum_lsq += l*l;  sum_l += l;
            sum_vl  += v*l;
            n += 1.0;

            if (nl == 2) {
                int label = labels[i];
                if (label < 0 || label > 1) continue;
                label_totals[label] += v;
                label_min[label] = std::min(label_min[label], v);
                label_max[label] = std::max(label_max[label], v);
                label_counts[label] += 1;
            }
        }

        double svl = n * sum_vl - sum_v * sum_l;
        double svv = n * sum_vsq - sum_v * sum_v;
        double sll = n * sum_lsq - sum_l * sum_l;

        r_squared = svl*svl / (svv * sll);
        b = svl / svv;

        //cerr << "n = " << n << " sum_vsq = " << sum_vsq << " sum_v = "
        //     << sum_v << " sum_lsq = " << sum_lsq << " sum_l = " << sum_l
        //     << "  sum_vl = " << sum_vl << endl;

        /* Sort them to improve the efficiency of the counting. */
        std::sort(values.begin(), values.end());

        vector<pair<double, int> > pairs;

        double last_value = 0.0;
        for (unsigned i = 0;  i < values.size();  ++i) {
            double value = values[i];
            if (std::isnan(value)) ++missing;
            else if (!isfinite(value)) ++denorm;
            else if (i != 0 && last_value == value) {
                assert(!pairs.empty());
                pairs.back().second += 1;
            }
            else pairs.push_back(make_pair(value, 1));

            last_value = value;
        }

        counts.insert(pairs.begin(), pairs.end());
        total_count = values.size();

        calc_from_counts();
    }
};

double t_test(const Variable_Stats & s1, const Variable_Stats & s2)
{
    return (s1.mean - s2.mean)
        / sqrt(sqr(s1.stddev)/(double)s1.total_count
               + sqr(s2.stddev)/(double)s2.total_count);
}

int main(int argc, char ** argv)
try
{
    ios::sync_with_stdio(false);

    bool variable_header    = false;
    string variable_name_file;
    string predicted_name   = "LABEL";

    int verbosity           = 1;
    bool is_regression      = false;   // Set to be a regression?
    bool by_label           = false;

    vector<string> dataset_files;

    namespace opt = boost::program_options;

    opt::options_description data_options("Data options");
    opt::options_description output_options("Output options");
    {
        using namespace boost::program_options;

        data_options.add_options()
            ( "variable-names,n", value<string>(&variable_name_file),
              "read variables names from FILE")
            ( "variable-header,d", value<bool>(&variable_header)->zero_tokens(),
              "use first line of file as a variable header")
            ( "regression,N", value<bool>(&is_regression),
              "force dataset to be a regression problem" )
            ( "predict-feature,L", value<string>(&predicted_name),
              "train classifier to predict FEATURE" )
            ( "dataset", value<vector<string> >(&dataset_files),
              "datasets to process" )
            ( "by-label", value<bool>(&by_label)->zero_tokens(),
              "further break down stats by label");

        output_options.add_options()
            ( "verbosity,v", value(&verbosity),
              "set verbosity to LEVEL [0-3]" );

        positional_options_description p;
        p.add("dataset", -1);

        options_description all_opt;
        all_opt
            .add(data_options)
            .add(output_options);

        all_opt.add_options()
            ("help,h", "print this message");

        variables_map vm;
        store(command_line_parser(argc, argv)
              .options(all_opt)
              .positional(p)
              .run(),
              vm);
        notify(vm);

        if (vm.count("help")) {
            cerr << all_opt << endl;
            return 1;
        }
    }

    if (dataset_files.empty())
        throw Exception("error: need to specify at least one data set");

    /* Variables for holding our datasets and feature spaces. */
    vector<std::shared_ptr<Dense_Training_Data> > data(dataset_files.size());
    vector<std::shared_ptr<Dense_Feature_Space> > fs(dataset_files.size());
    vector<Feature> predicted(dataset_files.size(), MISSING_FEATURE);

    vector<string> feature_names;
    map<string, vector<int> > feature_name_map;

    /* First, read in all of the data. */
    for (unsigned i = 0;  i < dataset_files.size();  ++i) {
        fs[i].reset(new Dense_Feature_Space());
        data[i].reset(new Dense_Training_Data());
        data[i]->init(dataset_files[i], fs[i]);

        if (verbosity > 0)
            cout << "dataset \'" << dataset_files[i] << "\': "
                 << data[i]->all_features().size() << " features, "
                 << data[i]->example_count() << " rows." << endl;

        vector<string> data_feature_names = fs[i]->feature_names();

        for (unsigned j = 0;  j < data_feature_names.size();  ++j) {
            string feat = data_feature_names[j];
            if (feature_name_map.count(feat) == 0) {
                feature_names.push_back(feat);
                feature_name_map[feat] = vector<int>(dataset_files.size(), -1);
            }
            feature_name_map[feat][i] = j;
        }

        /* Work out what feature we're predicting. */
        if (predicted_name != "")
            fs[i]->parse(predicted_name, predicted[i]);

        /** Work out what kind of feature it is */
        //data[i]->preindex_features();

        if (fs[i]->info(predicted[i]).type() == UNKNOWN) {
            fs[i]->set_info(predicted[i], guess_info(*data[i], predicted[i]));
        }

    }

    /* Work out our features. */
    int nf = feature_names.size();

    cerr << "overall: " << nf << " features." << endl;

    const Feature NONE(-1);

    /* Calculate labels to be used in calculation of correlations. */
    vector<distribution<double> > label_dists;
    for (unsigned d = 0;  d < data.size();  ++d) {
        label_dists.push_back(distribution<double>(data[d]->example_count()));
        for (unsigned x = 0;  x < data[d]->example_count();  ++x) {
            label_dists.back()[x] = (*data[d])[x][predicted[d]];
        }
    }

    /* Generate the stats. */
    vector<double> significance(nf, 0.0);
    vector<double> t_values(nf, 0.0);
    vector<int> contained(nf, 0);

    for (unsigned f = 0;  f < nf;  ++f) {
        string feat = feature_names[f];
        const vector<int> & ids = feature_name_map[feat];

        cout << feat << ":" << endl;
        vector<Variable_Stats> stats(data.size());

        cout << " set   values      min      max     mean      std     mode"
             << "    uniq      r^2      int"
             << endl;
        /* Go over each dataset. */
        for (unsigned d = 0;  d < data.size();  ++d) {
            if (ids[d] == -1) continue;

            int nl = data[d]->label_count(predicted[d]);

            //cerr << "nl = " << nl << " by_label = " << by_label << endl;
            //cerr << "predicted[d] = " << fs[d]->print(predicted[d]) << endl;
            //cerr << "info = " << fs[d]->info(predicted[d]) << endl;

            Feature feature(ids[d]);

            ++contained[f];

            vector<double> vec;

            // TODO: fill in
            stats[d].calc(data[d]->index().values(feature), label_dists[d], nl);

            cout << format("  %2d %8zd %8.3f %8.3f %8.3f %8.3f %8.3f "
                           "%7zd %8.6f %8.3g\n",
                           d,
                           stats[d].total_count - stats[d].missing
                               - stats[d].denorm,
                           stats[d].min, stats[d].max,
                           stats[d].mean,
                           stats[d].stddev, stats[d].mode,
                           stats[d].counts.size(),
                           stats[d].r_squared, stats[d].b);

            if (nl == 2 && by_label) {
                for (unsigned i = 0;  i < nl;  ++i) {
                    cout
                        << format("        label %d: min %8.3f max: %8.3f avg: %8.3f count: %7.0f",
                                  i, stats[d].label_min[i],
                                  stats[d].label_max[i],
                                  stats[d].label_totals[i] / stats[d].label_counts[i],
                                  stats[d].label_counts[i])
                        << endl;

                }
            }
        }

        //cerr << "contained[" << f << "] = " << contained[f] << endl;

        if (data.size() == 2 && contained[f] == 2) {
            cout << endl;
            double t = t_test(stats[0], stats[1]);

            if (!isfinite(t) && stats[0].stddev == 0.0 && stats[1].stddev == 0)
                t = 0.0;

            double sig = (boost::math::cdf(boost::math::normal_distribution<double>(), abs(t)) - 0.5) * 2.0;

            cout << format("   t    %6.3f\n   sig %6.2f%%\n",
                           t, sig * 100.0);

            t_values[f] = t;
            significance[f] = sig;
        }
        cout << endl;
    }

    if (data.size() == 2) {
        cout << "features sorted by abs(t) score..." << endl;

        vector<pair<double, pair<int, double> > > sorted(nf);

        for (unsigned f = 0;  f < nf;   ++f) {
            sorted[f].second.first = f;
            if (!isfinite(t_values[f])) {
                sorted[f].first = INFINITY;
                sorted[f].second.second = INFINITY;
            }
            else {
                sorted[f].first = abs(t_values[f]);
                sorted[f].second.second = significance[f];
            }
        }

        sort_on_first_descending(sorted);

        cout << "   abs(t)      sig  variable" << endl;
        for (unsigned f = 0;  f < nf;  ++f) {
            cout << format("%9.3f %8.2f  ",
                           sorted[f].first, sorted[f].second.second * 100.0)
                 << feature_names[sorted[f].second.first] << endl;
        }
    }
}
catch (const std::exception & exc) {
    cerr << "error: " << exc.what() << endl;
    exit(1);
}


#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <numeric>
#include <fstream>
#include <chrono>
#include <omp.h>
#include <boost/optional.hpp>
#include <boost/lexical_cast.hpp>
#include "include/Commons.h"
#include "include/Being.h"
#include "include/Food.h"
#include "include/Constants.h"
#include "include/Chromo.h"
#include "include/World.h"

world::world(int64_t N_being_init, int N_food_point_init) {

   food_.reserve(N_food_point_init);
   creatures_.reserve( 2 * N_being_init);
   dead_creatures_.reserve( 2 * N_being_init );
   N_generation_ = 0;

};

void world::add(being const& new_b) {

   creatures_.push_back(new_b);

};

void world::add(food_point const& new_fp) {

   food_.push_back(new_fp);

};

void world::remove_being() {

   creatures_.pop_back();

};

bool IsAlive(being const& b) { return b.is_alive(); };

int64_t world::N_alive() {

//   int64_t N = 0;
//   for(std::vector<being>::const_iterator i = first_b(); i!= last_b(); ++i){
//      if ( (*i).is_alive() ) ++N;
//   };

//   return N;

   int64_t N = count_if( creatures_.begin(), creatures_.end(), IsAlive );
   return N;

};

float sum_nutri(food_point const& lhs, food_point const& rhs) { return lhs.get_nutrival() + rhs.get_nutrival(); };

float world::total_nutrival() {

   float tnutri = 0.0;
#pragma omp parallel for reduction(+:tnutri)

//   for(std::vector<food_point>::const_iterator i = food_begin(); i!= food_end(); ++i){
//      tnutri +=  i->get_nutrival();
//   };

     for(int64_t i = 0 ; i < world::N_food() ; ++i){
        tnutri += food_[i].get_nutrival();
}

//   float tnutri = accumulate( food_.begin(), food_.end(), 0.0f, sum_nutri );
   return tnutri;

};

float world::total_energy() {

   float te = 0;
#pragma omp parallel for reduction(+:te)

// loop for serial execution
//   for(std::vector<being>::const_iterator i = beings_begin(); i!=beings_end(); ++i){
//      if (i->is_alive()) te += i->get_energy() ;
//   };
// end serial loop

//loop for openmp
for(int64_t i = 0 ; i < world::size(); ++i) {
   if(creatures_[i].is_alive()) te += creatures_[i].get_energy() ;
}
//end loop for openmp
//
   return te;
};

void world::dead_burial() {

   std::vector<being> tmp_alive;
   tmp_alive.reserve( N_alive() );
   for(std::vector<being>::iterator b = beings_begin(); b != beings_end(); ++b){

      if (b->is_alive())
      {
         tmp_alive.push_back( (*b) );
      }
      else
      {
         dead_creatures_.push_back( (*b) );
      }
   }

   creatures_ = tmp_alive;

};

void world::advance_one_generation(bool dump_to_file) {

   std::vector<being>::iterator this_generation_beings_end = beings_end();
   std::vector<food_point>::iterator this_generation_fp_end = food_end();

   int64_t creatures_end = size();
   std::string extension(".txt");
   std::string data_path("./DATA/");

   //for(std::vector<being>::iterator lhs_b = beings_begin(); lhs_b != this_generation_beings_end; ++lhs_b){
   std::cout << "Moving and feeding creatures..." << std::endl;
   std::chrono::time_point<std::chrono::high_resolution_clock> start_mov = std::chrono::high_resolution_clock::now();
#pragma omp parallel for
   for(int64_t ii = 0; ii < creatures_end ; ++ii){

      creatures_[ii].move() ;

      for(std::vector<food_point>::iterator fp_i = food_begin(); fp_i!=this_generation_fp_end; ++fp_i){
         creatures_[ii].eat( (*fp_i) ) ;
      };

   };
   std::chrono::time_point<std::chrono::high_resolution_clock> end_mov = std::chrono::high_resolution_clock::now();
   std::cout << "Timing for move and eat = " << std::chrono::duration_cast<std::chrono::milliseconds>(end_mov - start_mov).count() << "ms." << std::endl;

   std::cout << "Time to reproduce, mute and get older for  creatures..."  << std::endl;
   std::chrono::time_point<std::chrono::high_resolution_clock> start_rep = std::chrono::high_resolution_clock::now();
#pragma omp parallel for
   for( int64_t ii = 0; ii < creatures_end ; ++ii ){
      int nclose = 0;
      for ( int64_t jj = ii ; jj < creatures_end ; ++jj){
          if (are_close_enough(creatures_[ii] , creatures_[jj])) ++nclose;
          if ( ii != jj ) {
#pragma omp critical
{
             boost::optional<being> new_b = reproduce( creatures_[ii] , creatures_[jj] ) ;
             if (new_b) {
                being b2(new_b);
                add(b2);
}
             };
          };
      };
      if (nclose > 4) creatures_[ii].make_inhibited();
      else creatures_[ii].remove_inhibition();
      creatures_[ii].mutation();
      creatures_[ii].older();
      creatures_[ii].die();
   };
   std::chrono::time_point<std::chrono::high_resolution_clock> end_rep = std::chrono::high_resolution_clock::now();
   std::cout << "Timing for reproduction, mutation and get older = " << std::chrono::duration_cast<std::chrono::milliseconds>(end_rep - start_rep).count() << "ms." << std::endl;

   std::cout << "Time for dead burial (RIP)..." << std::endl;
   std::chrono::time_point<std::chrono::high_resolution_clock> start_bur = std::chrono::high_resolution_clock::now();

   dead_burial();

   std::chrono::time_point<std::chrono::high_resolution_clock> end_bur = std::chrono::high_resolution_clock::now();
   std::cout << "Timing for dead burial = " << std::chrono::duration_cast<std::chrono::milliseconds>(end_bur - start_bur).count() << "ms." << std::endl;

   ++N_generation_;
   std::string s = boost::lexical_cast<std::string>( N_generation_ );

   if (dump_to_file) save(data_path + s + extension);

};

void world::evolve(int64_t N_gen) {

   bool VERBOSE = true;
   std::string gen_str;
   std::chrono::time_point<std::chrono::high_resolution_clock> start_1gen;
   std::chrono::time_point<std::chrono::high_resolution_clock> end_1gen;
   for (int64_t i = 0; i < N_gen; ++i) {
      gen_str = boost::lexical_cast<std::string>( i );
      bool file_dump(true);
      start_1gen = std::chrono::high_resolution_clock::now();
      advance_one_generation(file_dump);
      end_1gen = std::chrono::high_resolution_clock::now();
      std::cout << "Timing for one generation ( " << gen_str << " ) evolution = " << std::chrono::duration_cast<std::chrono::milliseconds>(end_1gen - start_1gen).count() << "ms." << std::endl;
//      ++N_generation_;
      if (VERBOSE) stats();
      if ( N_alive() == 0 ) break;

   };

};

float world::age_avg() {

   float age_avg(0.0);
   for(std::vector<being>::iterator b = beings_begin(); b!=beings_end(); ++b){

      if ( b->is_alive() ) age_avg += b->get_age() ;

   };   //use accumulate

   float N = float(N_alive());
   if (N !=0) {
      return float(age_avg) / float(N_alive());
   }
   else {
      return 0;
   };
};

void world::stats() {

   std::cout << "World Stats:" << std::endl;
   std::cout << "World Age = " << age() << std::endl;
   std::cout << "N Alive = " << N_alive() << std::endl;
   std::cout << "N beings alive or dead = " << size() + N_dead() << std::endl;
   std::cout << "N dead dead_creatures = " << N_dead() << std::endl;
   std::cout << "Total Energy = " << total_energy() << std::endl;
   std::cout << "Total Nutrival = " << total_nutrival() << std::endl;
   std::cout << "Total Food Points = " << N_food() << std::endl;
   std::cout << "Average Being Age = " << age_avg() << std::endl;

};

void world::save(std::string const& filename) {

      // create and open a character archive for output
   std::ofstream ofs2(filename);
   // save data to archive
    {
        boost::archive::text_oarchive oa(ofs2);
        // write class instance to archive
        oa << (*this);
        // archive and stream closed when destructors are called
    }

};

void world::load(std::string const& filename) {

   world newworld(1,1);
   std::ifstream ifs2(filename);
   boost::archive::text_iarchive ia(ifs2);
   ia >> (*this);

};


#include <bitcoin/bitcoin.hpp>
#include <boost/format.hpp>
#include <boost/algorithm/string.hpp>
#include "coin_data.h"

#define BIP_NUMBER 44

using namespace bc;

int main(int argc, char* argv[]) {
    if (argc < 2) {
        std:cerr << "Syntax: wallet-get <coin> <net>" << std::endl;
        return -1;
    }
    const char* coin_name = argv[1];
    const char* net = argv[2];

    auto& coin = coin_data::get_coin_data(coin_name, net);

    const uint64_t custom_key_prefixes = wallet::hd_private::to_prefixes(
        coin.get_secret_key_prefix(),
        coin.get_public_key_prefix());

    wallet::word_list mnemonic_words;
    std::string input_words;

    std::cout << "Enter mnemonic (empty to autogenerate): ";
    std::getline(cin, input_words);
    if (input_words == "") {
        data_chunk my_entropy(32);
        pseudo_random_fill(my_entropy);
        mnemonic_words = wallet::create_mnemonic(my_entropy);
        std::cout << boost::format("// %s") % bc::join(mnemonic_words) << std::endl;
    } else {
        boost::split(mnemonic_words, input_words, boost::is_space());
    }

    auto hd_seed = wallet::decode_mnemonic(mnemonic_words);
    data_chunk seed_chunk(to_chunk(hd_seed));

    std::cout << "seed:           " << encode_base16(hd_seed) << std::endl;
    std::cout << "seed (base 58): " << encode_base58(hd_seed) << std::endl;

    wallet::hd_private m(seed_chunk, custom_key_prefixes);
    std::cout << "BIP32 Root Key: " << m << std::endl;
    std::cout << "SECRET SIZE: " << m.secret().size() << std::endl;
    auto m_purpose = m.derive_private(wallet::hd_first_hardened_key + BIP_NUMBER);
    auto m_coin = m_purpose.derive_private(coin.bip44_id);
    auto m_account = m_coin.derive_private(wallet::hd_first_hardened_key + 0);
    auto m_ext = m_account.derive_private(0);

    std::cout << std::endl;
    std::cout << "Account extended PrvKey: " << m_account << std::endl;
    std::cout << "Account extended PubKey: " << m_account.to_public() << std::endl;
    std::cout << std::endl;
    std::cout << "BIP32 Extended Private Key: " << m_ext << std::endl;
    std::cout << "BIP32 Extended Public Key:  " << m_ext.to_public() << std::endl;
    std::cout << std::endl;

    for (int i = 0; i < 10; i++) {
        auto mi = m_ext.derive_private(i);
        auto Mi = mi.to_public();

        auto pv_key = wallet::ec_private(
            mi.secret(),
            wallet::ec_private::to_version(
                coin.pubkey_address, coin.secret_key));

        auto payment_addr = pv_key.to_payment_address();

        std::cout << boost::format("m/%d'/%d'/%d'/%d/%d: %s") % BIP_NUMBER % (coin.bip44_id - wallet::hd_first_hardened_key) % 0 % 0 % i % payment_addr.encoded() << std::endl;
    }

    std::cout << std::endl;

    return 0;
}


// Copyright (C) 2005 Douglas Gregor.

// 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)

// Compute parents, children, levels, etc. to effect a parallel
// computation tree.

#include <boost/mpi/detail/computation_tree.hpp>

namespace boost { namespace mpi { namespace detail {

int computation_tree::default_branching_factor = 3;

computation_tree
::computation_tree(int rank, int size, int root, int branching_factor)
  : rank(rank), size(size), root(root),
    branching_factor_(branching_factor > 1? branching_factor
                      /* default */: default_branching_factor),
    level_(0)
{
  // The position in the tree, once we've adjusted for non-zero
  // roots.
  int n = (rank + size - root) % size;
  int sum = 0;
  int term = 1;

  /* The level is the smallest value of k such that

  f^0 + f^1 + ... + f^k > n

  for branching factor f and index n in the tree. */
  while (sum <= n) {
    ++level_;
    term *= branching_factor_;
    sum += term;
  }
}

int computation_tree::level_index(int n) const
{
  int sum = 0;
  int term = 1;
  while (n--) {
    sum += term;
    term *= branching_factor_;
  }
  return sum;
}

int computation_tree::parent() const
{
  if (rank == root) return rank;
  int n = rank + size - 1 - root;
  return ((n % size / branching_factor_) + root) % size ;
}

int computation_tree::child_begin() const
{
  // Zero-based index of this node
  int n = (rank + size - root) % size;

  // Compute the index of the child (in a zero-based tree)
  int child_index = level_index(level_ + 1)
    + branching_factor_ * (n - level_index(level_));

  if (child_index >= size) return root;
  else return (child_index + root) % size;
}

} } } // end namespace boost::mpi::detail


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

#ifndef IKOS_EXTENDED_CONSTRAINTS_HPP
#define IKOS_EXTENDED_CONSTRAINTS_HPP

#include <boost/optional.hpp>
#include <ikos/common.hpp>
#include <ikos/patricia_trees.hpp>
#include <ikos/collections.hpp>
#include <ikos/linear_constraints.hpp>

namespace ikos {

  template< typename Number, typename VariableName >
  class extended_constraint: public writeable {

  public:
    typedef extended_constraint< Number, VariableName > extended_constraint_t;
    typedef linear_constraint< Number, VariableName > linear_constraint_t;
    typedef variable< Number, VariableName > variable_t;
    typedef linear_expression< Number, VariableName > linear_expression_t;
    typedef patricia_tree_set< variable_t > variable_set_t;
    typedef enum {
      INF,
      INF_EQ,
      SUP,
      SUP_EQ,
      EQ,
      NOT_EQ,
      MOD
    } kind_t;
    typedef typename linear_expression_t::iterator iterator;

  private:
    kind_t _kind;
    linear_expression_t _expr;
    boost::optional<Number> _modulus;

  public:
    extended_constraint(): _kind(EQ) { }

    extended_constraint(linear_expression_t expr, kind_t kind, Number modulus): _kind(kind), _expr(expr), _modulus(modulus) { }

    extended_constraint(linear_expression_t expr, kind_t kind): _kind(kind), _expr(expr) { }

    extended_constraint(linear_constraint_t constraint): _kind(EQ), _expr(constraint.expression()) {
      if(constraint.is_inequality()) {
        _kind = INF_EQ;
      } else if(constraint.is_equality()) {
        _kind = EQ;
      } else {
        _kind = NOT_EQ;
      }
    }

    bool is_tautology() {
      switch (this->_kind) {
        case INF: {
          return (this->_expr.is_constant() && this->_expr.constant() < 0);
        }
        case INF_EQ: {
          return (this->_expr.is_constant() && this->_expr.constant() <= 0);
        }
        case SUP: {
          return (this->_expr.is_constant() && this->_expr.constant() > 0);
        }
        case SUP_EQ: {
          return (this->_expr.is_constant() && this->_expr.constant() >= 0);
        }
        case EQ: {
          return (this->_expr.is_constant() && this->_expr.constant() == 0);
        }
        case NOT_EQ: {
          return (this->_expr.is_constant() && this->_expr.constant() != 0);
        }
        case MOD: {
          return false; // TODO: type dependent
        }
        default: {
          throw error("Unreachable");
        }
      }
    }

    bool is_contradiction() {
      switch (this->_kind) {
        case INF: {
          return (this->_expr.is_constant() && this->_expr.constant() >= 0);
        }
        case INF_EQ: {
          return (this->_expr.is_constant() && this->_expr.constant() > 0);
        }
        case SUP: {
          return (this->_expr.is_constant() && this->_expr.constant() <= 0);
        }
        case SUP_EQ: {
          return (this->_expr.is_constant() && this->_expr.constant() < 0);
        }
        case EQ: {
          return (this->_expr.is_constant() && this->_expr.constant() != 0);
        }
        case NOT_EQ: {
          return (this->_expr.is_constant() && this->_expr.constant() == 0);
        }
        case MOD: {
          return false; // TODO: type dependent
        }
        default: {
          throw error("Unreachable");
        }
      }
    }

    linear_expression_t expression() {
      return this->_expr;
    }

    kind_t kind() {
      return this->_kind;
    }

    boost::optional<Number> modulus() {
      return this->_modulus;
    }

    iterator begin() {
      return this->_expr.begin();
    }

    iterator end() {
      return this->_expr.end();
    }

    Number constant() {
      return -this->_expr.constant();
    }

    std::size_t size() {
      return this->_expr.size();
    }

    Number operator[](variable_t x) {
      return this->_expr.operator[](x);
    }

    variable_set_t variables() {
      return this->_expr.variables();
    }

    std::ostream& write(std::ostream& o) {
      if (this->is_contradiction()) {
        o << "false";
      } else if (this->is_tautology()) {
        o << "true";
      } else {
        linear_expression_t e = this->_expr - this->_expr.constant();
        o << e;
        switch (this->_kind) {
          case INF: {
            o << " < ";
            break;
          }
          case INF_EQ: {
            o << " <= ";
            break;
          }
          case SUP: {
            o << " > ";
            break;
          }
          case SUP_EQ: {
            o << " >= ";
            break;
          }
          case EQ: {
            o << " = ";
            break;
          }
          case NOT_EQ: {
            o << " != ";
            break;
          }
          case MOD: {
            o << " = ";
            break;
          }
          default: {
            throw error("Unreachable");
          }
        }
        Number c = -this->_expr.constant();
        o << c;

        if (this->_kind == MOD) {
          o << " [";
          o << *_modulus;
          o << "]";
        }
      }
      return o;
    }

  }; // class extended_constraint

  template< typename Number, typename VariableName >
  class extended_constraint_system: public writeable {

  public:
    typedef extended_constraint< Number, VariableName > extended_constraint_t;
    typedef extended_constraint_system< Number, VariableName > extended_constraint_system_t;
    typedef linear_constraint< Number, VariableName > linear_constraint_t;
    typedef linear_constraint_system< Number, VariableName > linear_constraint_system_t;
    typedef variable< Number, VariableName > variable_t;
    typedef patricia_tree_set< variable_t > variable_set_t;

  private:
    typedef collection< extended_constraint_t > cst_collection_t;

  public:
    typedef typename cst_collection_t::iterator iterator;

  private:
    cst_collection_t _csts;

  public:
    extended_constraint_system() { }

    extended_constraint_system(extended_constraint_t cst) {
      this->_csts += cst;
    }

    extended_constraint_system_t& operator+=(extended_constraint_t cst) {
      this->_csts += cst;
      return *this;
    }

    extended_constraint_system_t& operator+=(extended_constraint_system_t s) {
      this->_csts += s._csts;
      return *this;
    }

    extended_constraint_system_t& operator+=(linear_constraint_t cst) {
      this->_csts += extended_constraint_t(cst);
      return *this;
    }

    extended_constraint_system_t& operator+=(linear_constraint_system_t csts) {
      for(typename linear_constraint_system_t::iterator it = csts.begin(); it != csts.end(); ++it) {
        this->_csts += extended_constraint_t(*it);
      }

      return *this;
    }

    extended_constraint_system_t operator+(extended_constraint_system_t s) {
      extended_constraint_system_t r;
      r.operator+=(s);
      r.operator+=(*this);
      return r;
    }

    iterator begin() {
      return this->_csts.begin();
    }

    iterator end() {
      return this->_csts.end();
    }

    variable_set_t variables() {
      variable_set_t variables;
      for (iterator it = this->begin(); it != this->end(); ++it) {
        variables |= it->variables();
      }
      return variables;
    }

    std::size_t size() {
      return this->_csts.size();
    }

    std::ostream& write(std::ostream& o) {
      return this->_csts.write(o);
    }

  }; // class extended_constraint_system
}

#endif // IKOS_EXTENDED_CONSTRAINTS_HPP


#ifndef _COMMON_HPP_H
#define _COMMON_HPP_H

#include <vector>
#include <boost/shared_array.hpp>
#include "CP_DYN.hpp"
#include "COM_ZMP_DYN.hpp"

#include <iostream>
#include <fstream>
#include <string>
#include <cmath>
#include <eigen3/Eigen/Dense>
#include <eigen3/Eigen/Core>

using namespace Eigen;
#define name2str(name) (#name)

typedef std::vector< boost::shared_array< double > > DoubleArrayVector;
typedef std::vector< boost::shared_array< int > > IntArrayVector;

static constexpr double step_time=0.8;
static constexpr double pre_step=4.0;
static constexpr double frame_rate=1000;

const double zc=0.7;
const double g=9.8;
const double omega=sqrt(g/zc);

#endif


/*
 * LFM_test.cpp
 *
 *  Created on: Aug 5, 2013
 *      Author: Asher Pembroke
 *
 *  This program illustrates some simple ways of using the LFM interpolator.
 *  Note: The initialization phase is somewhat long - it sets up millions of polyhedral cells,
 *  then primes all of them for interpolation. The time spent actually interpolating is printed
 *  whenever the LFMInterpolator is destroyed.
 *
 */

#include <boost/lexical_cast.hpp>
#include <boost/tokenizer.hpp>
#include <boost/foreach.hpp>
#include <iostream>
#include <ccmc/LFM.h>
#include <ccmc/LFMInterpolator.h>
#include <ccmc/Interpolator.h>
#include <ccmc/Point3f.h>
#include <ccmc/Kameleon.h>
#include <ccmc/Tracer.h>
#include <string>
#include <fstream>
#include <iomanip>
#include "time.h"
#include <vector>

using namespace std;
using namespace ccmc;

/**
 * LFM <inputfile> variable x y z
 */
int main (int argc, char * argv[])
{
	std::string variables[] = {"bx", "by", "bz", "ex","ey", "ez", "ux", "uy","uz", "rho", "p"};

	if ((argc != 6) && (argc != 4))
	{
		cout << "You must use the following format to test LFM interpolation at a point in GSE coordinates:\n"
				<<"\t ./lfm path/to/kameleon/converterd/LFMfile.h5 variable x y z \n"
				<<"with variable set to: bx by bz ex ey ez ux uy uz rho p\n"
				<<"or, to interpolate all available lfm variables onto a list of input (single spaced) positions, use\n"
				<<"\t ./lfm path/to/kameleon/converterd/LFMfile.h5 path/to/positions.txt path/to/output/file.txt"
				<< endl;
		exit(1);
	}

	string filename = argv[1];

	cout<<"Creating LFM object... ";
	LFM * lfm = new LFM;

	cout<<"Opening LFM.\n";
	lfm->open(filename);

	/*
	 * Load variables (pressure,density and e-field already loaded)
	 * It is necessary to load the variables prior to interpolating
	 */
	lfm->loadVariable("bx");
	lfm->loadVariable("by");
	lfm->loadVariable("bz");
	lfm->loadVariable("ux");
	lfm->loadVariable("uy");
	lfm->loadVariable("uz");

	cout<<"initializing interpolator (takes a few seconds)... ";
	LFMInterpolator interpolator(lfm);
	cout<<"done.\n";

	float px,py,pz;
	float dx,dy,dz;

	if (argc == 6){

		string variable = argv[2];
		px = boost::lexical_cast<float>(argv[3]);
		py = boost::lexical_cast<float>(argv[4]);
		pz = boost::lexical_cast<float>(argv[5]);

		cout<<"Interpolating variable "<< variable <<" at ("<< px <<","<<py<<","<<pz<<")...\n";

		float variableOut = interpolator.interpolate(variable,px,py,pz, dx,dy,dz);

		std::cout<<variable << "("<< px <<","<<py<<","<<pz<<")="<<variableOut<<endl;
		std::cout<<"resolution at query point: "<<dx<<", "<<dy<<", "<<dz<<endl;
	}

	if (argc == 4){

		string positionsFile = argv[2];
		std::cout<<"Reading positions from file "<<positionsFile<<endl;

		std::vector<Point3f> seedPositions;

		std::ifstream seedsFileStream;
		seedsFileStream.open(positionsFile.c_str());

		if (!seedsFileStream.is_open())
		{
				std::cerr << "Error opening seeds position file " << positionsFile << "." << std::endl;
				exit(1);
		}else
		{
			std::string line;
			while(seedsFileStream.good())
			{
				getline(seedsFileStream, line);
				//std::cout << line << std::endl;
				boost::char_separator<char> sep(" ");
				boost::tokenizer<boost::char_separator<char> > tokens(line, sep);
				int count = 0;
				Point3f p;
				std::string t;
				BOOST_FOREACH(t, tokens){
					if (count == 0){
						p.component1 = boost::lexical_cast<float>(t);
						count++;
					} else if (count == 1){
						p.component2 = boost::lexical_cast<float>(t);
						count++;
					} else {
						p.component3 = boost::lexical_cast<float>(t);
					}
				}

				if (count > 0){
					seedPositions.push_back(p);
				}
			}
		}

		string outputFileName = argv[3];
		std::ofstream outFile(outputFileName.c_str());
		outFile <<"bx by bz[T] ex ey ez[V/m] ux uy uz [m/s] rho [g/cc] p [Pa]\n";

		for (size_t i=0; i<seedPositions.size();i++){
			px = seedPositions[i].component1;
			py = seedPositions[i].component2;
			pz = seedPositions[i].component3;
			for (size_t j = 0; j<11; j++){
				outFile << std::scientific << interpolator.interpolate(variables[j],px,py,pz) <<" ";
			}
			outFile << endl;
		}
	}

	cout <<" Finished. Deleting lfm\n";
	delete lfm;

	return 0;

}


#ifndef NNQS_OPTIMIZERS_OPTIMIZER_HPP
#define NNQS_OPTIMIZERS_OPTIMIZER_HPP
#include <Eigen/Dense>
#include <nlohmann/json.hpp>
#include "Utilities/type_traits.hpp"

namespace yannq
{
template<typename T>
class Optimizer
{
public:
	using RealT = typename yannq::remove_complex<T>::type;
	using Vector = Eigen::Matrix<T, Eigen::Dynamic, 1>;
	using RealVector = Eigen::Matrix<RealT, Eigen::Dynamic, 1>;

	virtual nlohmann::json desc() const = 0;

	virtual Vector getUpdate(const Vector& grad) = 0;

	virtual ~Optimizer() { }
};

template<typename T, typename Enable = void>
class OptimizerGeometry;

/* If T is complex */
template<typename T>
class OptimizerGeometry<T, typename std::enable_if<is_complex_type<T>::value>::type>
	: public Optimizer<T>
{
public:
	using typename Optimizer<T>::RealT;
	using Vector = typename Optimizer<T>::Vector;
	using RealVector = typename Optimizer<T>::RealVector;

	virtual Vector getUpdate(const Vector& grad, const Vector& oloc) = 0;

	virtual Vector getUpdate(const Vector& grad) override
	{
		return this->getUpdate(grad, grad);
	}
};

/* if T is real  */
template<typename T>
class OptimizerGeometry<T, typename std::enable_if<!is_complex_type<T>::value>::type>
	: public Optimizer<T>, public OptimizerGeometry<std::complex<T> >
{
public:
	using RealT = T;
	using ComplexT = std::complex<T>;
	using Vector = typename Optimizer<T>::Vector;
	using RealVector = typename Optimizer<T>::RealVector;
	using ComplexVector = typename Eigen::Matrix<std::complex<T>, Eigen::Dynamic, 1>;

	virtual Vector getUpdate(const Vector& grad, const Vector& oloc) = 0;

	Vector getUpdate(const Vector& grad) override
	{
		return this->getUpdate(grad, grad);
	}

	ComplexVector getUpdate(const ComplexVector& grad) override
	{
		RealVector resReal = this->getUpdate((const RealVector&)Eigen::Map<RealVector>((RealT*)grad.data(), 2*grad.rows(), 1));
		return Eigen::Map<ComplexVector>((ComplexT*)resReal.data(), grad.rows(), 1);
	}

	ComplexVector getUpdate(const ComplexVector& grad, const ComplexVector& oloc) override
	{
		const auto realGrad = Eigen::Map<RealVector>((RealT*)grad.data(), 2*grad.rows(), 1);
		const auto realOloc= Eigen::Map<RealVector>((RealT*)oloc.data(), 2*oloc.rows(), 1);
		RealVector resReal = this->getUpdate((const RealVector&)realGrad, (const RealVector&)realOloc);
		return Eigen::Map<ComplexVector>((ComplexT*)resReal.data(), grad.rows(), 1);
	}
};
}
#endif//NNQS_OPTIMIZERS_OPTIMIZER_HPP


//
// This code is released under the
// Apache License Version 2.0 http://www.apache.org/licenses/.
//
// (c) Zuo Wang, https://github.com/zuowang
//

#include <stdlib.h>
#include <stdio.h>
#include <iostream>

#include <boost/utility.hpp>
#include <gtest/gtest.h>
#include <math.h>

#include "common/init.h"
#include "util/fle-encoding.h"
#include "util/bit-stream-utils.inline.h"

#include "common/names.h"

using namespace std;

namespace impala {

const int MAX_WIDTH = 32;

TEST(BitArray, TestBool) {
  const int len = 8;
  uint8_t buffer[len];

  BitWriter writer(buffer, len);

  // Write alternating 0's and 1's
  for (int i = 0; i < 8; ++i) {
    bool result = writer.PutValue(i % 2, 1);
    EXPECT_TRUE(result);
  }
  writer.Flush();
  EXPECT_EQ((int)buffer[0], BOOST_BINARY(1 0 1 0 1 0 1 0));

  // Write 00110011
  for (int i = 0; i < 8; ++i) {
    bool result = false;
    switch (i) {
      case 0:
      case 1:
      case 4:
      case 5:
        result = writer.PutValue(false, 1);
        break;
      default:
        result = writer.PutValue(true, 1);
        break;
    }
    EXPECT_TRUE(result);
  }
  writer.Flush();

  // Validate the exact bit value
  EXPECT_EQ((int)buffer[0], BOOST_BINARY(1 0 1 0 1 0 1 0));
  EXPECT_EQ((int)buffer[1], BOOST_BINARY(1 1 0 0 1 1 0 0));

  // Use the reader and validate
  BitReader reader(buffer, len);
  for (int i = 0; i < 8; ++i) {
    bool val;
    bool result = reader.GetValue(1, &val);
    EXPECT_TRUE(result);
    EXPECT_EQ(val, i % 2);
  }

  for (int i = 0; i < 8; ++i) {
    bool val;
    bool result = reader.GetValue(1, &val);
    EXPECT_TRUE(result);
    switch (i) {
      case 0:
      case 1:
      case 4:
      case 5:
        EXPECT_EQ(val, false);
        break;
      default:
        EXPECT_EQ(val, true);
        break;
    }
  }
}

// Writes 'num_vals' values with width 'bit_width' and reads them back.
void TestBitArrayValues(int bit_width, int num_vals) {
  const int len = BitUtil::Ceil(bit_width * num_vals, 8);
  const uint64_t mod = bit_width == 64? 1 : 1LL << bit_width;

  uint8_t buffer[len];
  BitWriter writer(buffer, len);
  for (int i = 0; i < num_vals; ++i) {
    bool result = writer.PutValue(i % mod, bit_width);
    EXPECT_TRUE(result);
  }
  writer.Flush();
  EXPECT_EQ(writer.bytes_written(), len);

  BitReader reader(buffer, len);
  for (int i = 0; i < num_vals; ++i) {
    int64_t val;
    bool result = reader.GetValue(bit_width, &val);
    EXPECT_TRUE(result);
    EXPECT_EQ(val, i % mod);
  }
  EXPECT_EQ(reader.bytes_left(), 0);
}

TEST(BitArray, TestValues) {
  for (int width = 0; width <= MAX_WIDTH; ++width) {
    TestBitArrayValues(width, 1);
    TestBitArrayValues(width, 2);
    // Don't write too many values
    TestBitArrayValues(width, (width < 12) ? (1 << width) : 4096);
    TestBitArrayValues(width, 1024);
  }
}

// Test some mixed values
TEST(BitArray, TestMixed) {
  const int len = 1024;
  uint8_t buffer[len];
  bool parity = true;

  BitWriter writer(buffer, len);
  for (int i = 0; i < len; ++i) {
    bool result;
    if (i % 2 == 0) {
      result = writer.PutValue(parity, 1);
      parity = !parity;
    } else {
      result = writer.PutValue(i, 10);
    }
    EXPECT_TRUE(result);
  }
  writer.Flush();

  parity = true;
  BitReader reader(buffer, len);
  for (int i = 0; i < len; ++i) {
    bool result;
    if (i % 2 == 0) {
      bool val;
      result = reader.GetValue(1, &val);
      EXPECT_EQ(val, parity);
      parity = !parity;
    } else {
      int val;
      result = reader.GetValue(10, &val);
      EXPECT_EQ(val, i);
    }
    EXPECT_TRUE(result);
  }
}

// Validates encoding of values by encoding and decoding them.  If
// expected_encoding != NULL, also validates that the encoded buffer is
// exactly 'expected_encoding'.
// if expected_len is not -1, it will validate the encoded size is correct.
void ValidateFle(const vector<int>& values, int bit_width,
                 uint8_t* expected_encoding, int expected_len) {
  const int len = 64 * 1024;
  uint8_t buffer[len];
  EXPECT_LE(expected_len, len);

  FleEncoder encoder(buffer, len, bit_width);
  for (int i = 0; i < values.size(); ++i) {
    bool result = encoder.Put(values[i]);
    EXPECT_TRUE(result);
  }
  int encoded_len = encoder.Flush();

  if (expected_len != -1) {
    EXPECT_EQ(encoded_len, expected_len);
  }
  if (expected_encoding != NULL) {
    EXPECT_TRUE(memcmp(buffer, expected_encoding, expected_len) == 0);
  }

  // Verify read
  FleDecoder decoder(buffer, len, bit_width, values.size());
  for (int i = 0; i < values.size(); ++i) {
    uint64_t val;
    bool result = decoder.Get(&val);
    EXPECT_TRUE(result);
    EXPECT_EQ(values[i], val);
  }
}

TEST(Fle, SpecificSequences) {
//  const int len = 1024;
//  uint8_t expected_buffer[len];
  vector<int> values;

  // Test 50 0' followed by 50 1's
  values.resize(100);
  for (int i = 0; i < 50; ++i) {
    values[i] = 0;
  }
  for (int i = 50; i < 100; ++i) {
    values[i] = 1;
  }

  // expected_buffer valid for bit width <= 1 byte
//  *(reinterpret_cast<int64_t*>(&expected_buffer[0])) = 0x3fff;
//  *(reinterpret_cast<int64_t*>(&expected_buffer[8])) = 0xfffffffff0000000;
  ValidateFle(values, 1, NULL, 16);
//  *(reinterpret_cast<int64_t*>(&expected_buffer[0])) = 0x3fff;
//  *(reinterpret_cast<int64_t*>(&expected_buffer[8])) = 0x0;
//  *(reinterpret_cast<int64_t*>(&expected_buffer[16])) = 0xfffffffff0000000;
//  *(reinterpret_cast<int64_t*>(&expected_buffer[24])) = 0x0;
  ValidateFle(values, 2, NULL, 32);

  for (int width = 2; width <= MAX_WIDTH; ++width) {
    ValidateFle(values, width, NULL, -1);
  }

  // Test 100 0's and 1's alternating
  for (int i = 0; i < 100; ++i) {
    values[i] = i % 2;
  }

//  *(reinterpret_cast<int64_t*>(&expected_buffer[0])) = 0x5555555555555555;
//  *(reinterpret_cast<int64_t*>(&expected_buffer[8])) = 0x5555555550000000;

  ValidateFle(values, 1, NULL, 16);
  for (int width = 2; width <= MAX_WIDTH; ++width) {
    ValidateFle(values, width, NULL, -1);
  }
}

// ValidateFle on 'num_vals' values with width 'bit_width'. If 'value' != -1, that value
// is used, otherwise alternating values are used.
void TestFleValues(int bit_width, int num_vals, int value = -1) {
  const uint64_t mod = (bit_width == 64) ? 1 : 1LL << bit_width;
  vector<int> values;
  for (int v = 0; v < num_vals; ++v) {
    values.push_back((value != -1) ? value : (v % mod));
  }
  ValidateFle(values, bit_width, NULL, -1);
}

TEST(Fle, TestValues) {
  for (int width = 1; width <= MAX_WIDTH; ++width) {
    TestFleValues(width, 1);
    TestFleValues(width, 1024);
    TestFleValues(width, 1024, 0);
    TestFleValues(width, 1024, 1);
  }
}

TEST(Fle, TestRandomValues) {
  srand((int)time(0));
  for (int width = 1; width <= MAX_WIDTH; ++width) {
    const uint64_t mod = (width == 64) ? 1 : 1LL << width;
    vector<int> values;
    for (int v = 0; v < 1024; ++v) {
      values.push_back(rand() % mod);
    }

    ValidateFle(values, width, NULL, -1);
  }
}
}

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


/**
 * @example ocean/test/attenuation_test.cc
 */
#include <boost/test/unit_test.hpp>
#include <usml/ocean/ocean.h>
#include <fstream>

BOOST_AUTO_TEST_SUITE(attenuation_test)

using namespace boost::unit_test;
using namespace usml::ocean;

/**
 * @ingroup ocean_test
 * @{
 */

/**
 * Test the basic features of the attenuation model using
 * the attenuation_constant model.  Given a model where attenuation
 * is 1e-6 * frequency, check to see that the calculated results are
 * within 1e-6% of the analytic values.
 */
BOOST_AUTO_TEST_CASE( constant_attenuation_test ) {
    cout << "=== attenuation_test: constant_attenuation_test ===" << endl;

    // simple values for points and distance

    wposition points(1, 1);
    matrix<double> distance(1, 1);
    distance(0, 0) = 1000.0;

    // compute attenuation

    seq_log freq(10.0, 10.0, 7);
    cout << "freq:  " << freq << endl;
    matrix < vector<double> > atten(1, 1);
    atten(0, 0).resize(freq.size());

    attenuation_constant model(1e-6);
    model.attenuation(points, freq, distance, &atten);
    cout << "atten: " << atten << endl;

    // check the answer

    double value = 0.01;
    for (size_t f = 0; f < freq.size(); ++f) {
        BOOST_CHECK_CLOSE(atten(0, 0)(f), value, 1e-6);
        value *= 10.0;
    }
}

/**
 * Compare values of the Thorp model to Table 7 in
 * Weinburg, "Generic Sonar Model", NUWC TD-5971D (1985).
 * Because GSM uses slightly different constants then
 * Jensen, et. al., we only expect the results to match
 * within 20% and only at 400 Hz and above.
 */
BOOST_AUTO_TEST_CASE( thorp_test_a ) {
    cout << "=== attenuation_test: thorp_test_a ===" << endl;

    // simple values for points and distance

    wposition points(1, 1);
    points.altitude(0, 0, -1000.0);

    matrix<double> distance(1, 1);
    distance(0, 0) = 1000.0;

    // compute attenuation

    seq_log freq(10.0, 2.0, 14);
    matrix < vector<double> > atten(1, 1);
    atten(0, 0).resize(freq.size());

    attenuation_thorp model;
    model.attenuation(points, freq, distance, &atten);

    // Generic Sonar Model values

    static double gsm_thorp[] = { 0.00006, 0.00017, 0.00047, 0.00134, 0.00379,
            0.01125, 0.03615, 0.08538, 0.16469, 0.38326, 1.19919, 4.16885,
            12.81169, 27.26378 };

    for (size_t f = 0; f < freq.size(); ++f) {
        cout << freq(f) << "\t" << atten(0, 0)(f) << endl;
        if (freq(f) > 400.0) {
            BOOST_CHECK_CLOSE(atten(0, 0)(f), gsm_thorp[f], 20.0);
        }
    }
}

/**
 * Reproduce the plot shown in Jensen, et al. Computational
 * Ocean Acoustics p37 Fig. 1.20
 */
BOOST_AUTO_TEST_CASE( thorp_test_b ) {
    cout << "=== attenuation_test: thorp_test_b ===" << endl;

    // simple values for points and distance

    wposition points(1, 1);
    points.altitude(0, 0, -1000.0);

    matrix<double> distance(1, 1);
    distance(0, 0) = 1000.0;

    // compute attenuation

    seq_log freq(10.0, pow(2.0,0.1), 1e7);
    matrix < vector<double> > atten(1, 1);
    atten(0, 0).resize(freq.size());

    attenuation_thorp model;
    model.attenuation(points, freq, distance, &atten);

    const char* name = USML_TEST_DIR "/ocean/test/attenuation_plot.csv" ;
    std::ofstream os(name) ;
    cout << "writing tables to " << name << endl ;

    os << "freq,atten" << endl ;
    for (size_t f = 0; f < freq.size(); ++f) {
        os << freq(f) << "," << atten(0, 0)(f) << endl ;
    }
}

/// @}

BOOST_AUTO_TEST_SUITE_END()


///////////////////////////////////////////////////////////////////////////////
/// \file adjacent_difference.hpp
/// Like \c std::adjacent_difference, but for Series
//
//  Copyright 2006 Eric Niebler. 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)

#ifndef BOOST_TIME_SERIES_NUMERIC_ADJACENT_DIFFERENCE_EAN_06_13_2006
#define BOOST_TIME_SERIES_NUMERIC_ADJACENT_DIFFERENCE_EAN_06_13_2006

#include <boost/implicit_cast.hpp>
#include <boost/concept/requires.hpp>
#include <boost/range_run_storage/algorithm/for_each.hpp>
#include <boost/time_series/concepts.hpp>
#include <boost/time_series/sparse_series.hpp>
#include <boost/time_series/ordered_inserter.hpp>

namespace boost { namespace time_series
{
    namespace detail
    {
        namespace rrs = range_run_storage;

        // adjacent_difference_functor
        template<typename Out, typename Series>
        struct adjacent_difference_functor
        {
            typedef concepts::TimeSeries<Series> series_concept;
            typedef typename series_concept::value_type value_type;
            typedef typename series_concept::offset_type offset_type;

            adjacent_difference_functor(Out const &out, Series const &series)
              : out_(out)
              , zero_(implicit_cast<value_type const &>(rrs::zero(series)))
              , value_(rrs::get_at(series, -inf))
              , offset_(-inf)
            {}

            void operator ()(value_type const &value, offset_type start, offset_type stop)
            {
                if(this->offset_ == start)
                {
                    this->out_(value - this->value_, start);
                }
                else
                {
                    this->out_(this->zero_ - this->value_, this->offset_);
                    this->out_(value - this->zero_, start);
                }
                this->offset_ = stop;
                this->value_ = value;
            }

            Out const &finalize()
            {
                if(inf != this->offset_)
                {
                    this->out_(this->zero_ - this->value_, this->offset_);
                }
                return this->out_;
            }
        private:
            Out out_;
            value_type zero_;
            value_type value_;
            offset_type offset_;
        };
    }

    /// \brief Calculate the adjacent difference of a series.
    ///
    /// Calculate the adjacent difference of a series, much like \c std::adjacent_difference.
    ///
    /// \param series The input series.
    /// \param out The ordered inserter to receive the adjacent difference result.
    ///
    /// \pre \c Series is a model of the \c TimeSeries concept.
    /// \pre \c Out is a model of the \c OrderedInserter concept.
    /// \pre For variaibles \c x and \c y of the series' \c value_type, the expression
    ///     \c (x-y) must be convertible to \c value_type.
    /// \return A \c sparse_series\<\> if no ordered inserter is specified; otherwise,
    ///     the ordered inserter.
    /// \attention If using the version that takes an \c OrderedInserter, you must call
    ///     <tt>.commit()</tt> on the returned \c OrderedInserter when you are done with it.
    template<typename Series, typename Out>
    BOOST_CONCEPT_REQUIRES(
        ((concepts::TimeSeries<Series const>)),
    (ordered_inserter<Out>))
    adjacent_difference(Series const &series, ordered_inserter<Out> out)
    {
        detail::adjacent_difference_functor<ordered_inserter<Out>, Series> fun(out, series);
        return range_run_storage::for_each(series, fun).finalize();
    }

    /// \overload
    ///
    template<typename Series>
    BOOST_CONCEPT_REQUIRES(
        ((concepts::TimeSeries<Series const>)),
    (sparse_series<
        typename concepts::TimeSeries<Series const>::value_type
      , typename concepts::TimeSeries<Series const>::discretization_type
      , typename concepts::TimeSeries<Series const>::offset_type
    >))
    adjacent_difference(Series const &series)
    {
        typedef typename concepts::TimeSeries<Series const>::value_type value_type;
        typedef typename concepts::TimeSeries<Series const>::offset_type offset_type;
        typedef typename concepts::TimeSeries<Series const>::discretization_type discretization_type;

        // The partial differences are held in a sparse array.
        sparse_series<value_type, discretization_type, offset_type> result(
            time_series::discretization = series.discretization()
        );

        time_series::adjacent_difference(
            series
          , time_series::make_ordered_inserter(result)
        ).commit();

        return result;
    }

}}

#endif // BOOST_TIME_SERIES_NUMERIC_ADJACENT_DIFFERENCE_EAN_06_12_2006


//////////////////////////////////////////////////////////////////////////////////////
// distribution::toolkit::distributions::product_pdf::description.hpp               //
//                                                                                //
//  (C) Copyright 2009 Erwann Rogard                                                //
//  Use, modification and distribution are 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_STATISTICS_DETAIL_DISTRIBUTION_TOOLKIT_MAP_PDF_PRODUCT_PDF_DESCRIPTION_HPP_ER_2009
#define BOOST_STATISTICS_DETAIL_DISTRIBUTION_TOOLKIT_MAP_PDF_PRODUCT_PDF_DESCRIPTION_HPP_ER_2009
#include <string>
#include <boost/format.hpp>
#include <boost/statistics/detail/distribution_toolkit/map_pdf/product_pdf/product_pdf.hpp>

namespace boost{
namespace statistics{
namespace detail{
namespace distribution{
namespace toolkit{

    template<typename F,typename S>
    std::string
    description(const product_pdf<F,S>& dist)
    {
        static const char* msg = "product_pdf<%1%,%2%>";
        format f(msg); f%description(dist.first())%description(dist.second());
        return (f.str());
    }

}// toolkit
}// distribution
}// detail
}// statistics
}// boost

#endif


#ifdef STAN_OPENCL

#include <stan/math/opencl/kernel_generator.hpp>
#include <stan/math/opencl/matrix_cl.hpp>
#include <stan/math/opencl/copy.hpp>
#include <test/unit/util.hpp>
#include <Eigen/Dense>
#include <gtest/gtest.h>

TEST(MathMatrixCL, broadcast_errors) {
  using Eigen::MatrixXd;
  using stan::math::matrix_cl;

  MatrixXd m(3, 3);
  m << 1, 2.5, 3, 4, 5, 6.3, 7, -8, -9.5;
  MatrixXd row(1, 3);
  row << 10, 100, 1000;
  MatrixXd col(3, 1);
  col << 10, 100, 1000;
  MatrixXd scal(1, 1);
  scal << 10;

  matrix_cl<double> m_cl(m);
  matrix_cl<double> row_cl(row);
  matrix_cl<double> col_cl(col);
  matrix_cl<double> scal_cl(scal);

  // extra parenthesis is needed for passing type name with comma in a macro
  EXPECT_NO_THROW((stan::math::broadcast<false, false>(m_cl)));
  EXPECT_THROW((stan::math::broadcast<true, false>(m_cl)),
               std::invalid_argument);
  EXPECT_THROW((stan::math::broadcast<false, true>(m_cl)),
               std::invalid_argument);
  EXPECT_THROW((stan::math::colwise_broadcast(m_cl)), std::invalid_argument);
  EXPECT_THROW((stan::math::rowwise_broadcast(m_cl)), std::invalid_argument);
  EXPECT_THROW((stan::math::broadcast<true, true>(m_cl)),
               std::invalid_argument);

  EXPECT_NO_THROW((stan::math::broadcast<false, false>(row_cl)));
  EXPECT_NO_THROW((stan::math::broadcast<true, false>(row_cl)));
  EXPECT_THROW((stan::math::broadcast<false, true>(row_cl)),
               std::invalid_argument);
  EXPECT_NO_THROW((stan::math::colwise_broadcast(row_cl)));
  EXPECT_THROW((stan::math::rowwise_broadcast(row_cl)), std::invalid_argument);
  EXPECT_THROW((stan::math::broadcast<true, true>(row_cl)),
               std::invalid_argument);

  EXPECT_NO_THROW((stan::math::broadcast<false, false>(col_cl)));
  EXPECT_THROW((stan::math::broadcast<true, false>(col_cl)),
               std::invalid_argument);
  EXPECT_NO_THROW((stan::math::broadcast<false, true>(col_cl)));
  EXPECT_THROW((stan::math::colwise_broadcast(col_cl)), std::invalid_argument);
  EXPECT_NO_THROW((stan::math::rowwise_broadcast(col_cl)));
  EXPECT_THROW((stan::math::broadcast<true, true>(col_cl)),
               std::invalid_argument);

  EXPECT_NO_THROW((stan::math::broadcast<false, false>(scal_cl)));
  EXPECT_NO_THROW((stan::math::broadcast<true, false>(scal_cl)));
  EXPECT_NO_THROW((stan::math::broadcast<false, true>(scal_cl)));
  EXPECT_NO_THROW((stan::math::colwise_broadcast(scal_cl)));
  EXPECT_NO_THROW((stan::math::rowwise_broadcast(scal_cl)));
  EXPECT_NO_THROW((stan::math::broadcast<true, true>(scal_cl)));

  EXPECT_NO_THROW((stan::math::broadcast<false, false>(scal_cl).eval()));
  EXPECT_THROW((stan::math::broadcast<true, false>(scal_cl).eval()),
               std::invalid_argument);
  EXPECT_THROW((stan::math::broadcast<false, true>(scal_cl).eval()),
               std::invalid_argument);
  EXPECT_THROW((stan::math::broadcast<true, true>(scal_cl).eval()),
               std::invalid_argument);
}

TEST(MathMatrixCL, broadcast_rows_test) {
  using Eigen::MatrixXd;
  using stan::math::matrix_cl;

  MatrixXd m1(3, 3);
  m1 << 1, 2.5, 3, 4, 5, 6.3, 7, -8, -9.5;
  MatrixXd m2(1, 3);
  m2 << 10, 100, 1000;

  matrix_cl<double> m1_cl(m1);
  matrix_cl<double> m2_cl(m2);

  auto tmp = m1_cl + stan::math::broadcast<true, false>(m2_cl);
  matrix_cl<double> res_cl = tmp;
  MatrixXd res = stan::math::from_matrix_cl(res_cl);

  MatrixXd correct = m1 + m2.replicate<3, 1>();
  EXPECT_MATRIX_NEAR(res, correct, 1e-9);
}

TEST(MathMatrixCL, broadcast_cols_test) {
  using Eigen::MatrixXd;
  using stan::math::matrix_cl;

  MatrixXd m1(3, 3);
  m1 << 1, 2.5, 3, 4, 5, 6.3, 7, -8, -9.5;
  MatrixXd m2(3, 1);
  m2 << 10, 100, 1000;

  matrix_cl<double> m1_cl(m1);
  matrix_cl<double> m2_cl(m2);

  auto tmp = m1_cl + stan::math::broadcast<false, true>(m2_cl);
  matrix_cl<double> res_cl = tmp;
  MatrixXd res = stan::math::from_matrix_cl(res_cl);

  MatrixXd correct = m1 + m2.replicate<1, 3>();
  EXPECT_MATRIX_NEAR(res, correct, 1e-9);
}

TEST(MathMatrixCL, broadcast_both_test) {
  using Eigen::MatrixXd;
  using stan::math::matrix_cl;

  MatrixXd m1(3, 3);
  m1 << 1, 2.5, 3, 4, 5, 6.3, 7, -8, -9.5;
  MatrixXd m2(1, 1);
  m2 << 10;

  matrix_cl<double> m1_cl(m1);
  matrix_cl<double> m2_cl(m2);

  auto tmp = m1_cl + stan::math::broadcast<true, true>(m2_cl);
  matrix_cl<double> res_cl = tmp;
  MatrixXd res = stan::math::from_matrix_cl(res_cl);

  MatrixXd correct = m1 + m2.replicate<3, 3>();
  EXPECT_MATRIX_NEAR(res, correct, 1e-9);
}

TEST(MathMatrixCL, rowwise_sum_broadcast_test) {
  using Eigen::MatrixXd;
  using stan::math::matrix_cl;
  MatrixXd m(3, 2);
  m << 1.1, 1.2, 1.3, 1.4, 1.5, 1.6;

  matrix_cl<double> m_cl(m);

  matrix_cl<double> res_cl
      = stan::math::rowwise_broadcast(stan::math::rowwise_sum(m_cl)) + m_cl;
  MatrixXd res = stan::math::from_matrix_cl(res_cl);
  MatrixXd correct = m.rowwise().sum().replicate(1, 2) + m;
  EXPECT_EQ(correct.rows(), res.rows());
  EXPECT_EQ(correct.cols(), res.cols());
  EXPECT_MATRIX_NEAR(correct, res, 1e-9);
}

TEST(MathMatrixCL, broadcast_view_test) {
  using stan::math::matrix_cl;

  matrix_cl<double> v_cl(2, 1);
  matrix_cl<double> m_cl(2, 2, stan::math::matrix_cl_view::Diagonal);
  matrix_cl<double> dst_block_cl(3, 3, stan::math::matrix_cl_view::Diagonal);
  matrix_cl<double> dst_cl
      = stan::math::broadcast<false, false>(block(dst_block_cl, 0, 0, 2, 2));
  EXPECT_EQ(dst_cl.view(), stan::math::matrix_cl_view::Diagonal);
  dst_cl = stan::math::broadcast<false, true>(v_cl) + m_cl;
  EXPECT_EQ(dst_cl.view(), stan::math::matrix_cl_view::Entire);
  block(dst_block_cl, 0, 0, 2, 2)
      = stan::math::broadcast<false, false>(block(dst_block_cl, 0, 0, 2, 2));
  EXPECT_EQ(dst_block_cl.view(), stan::math::matrix_cl_view::Diagonal);
  block(dst_block_cl, 0, 1, 2, 2)
      = stan::math::broadcast<false, true>(v_cl) + m_cl;
  EXPECT_EQ(dst_block_cl.view(), stan::math::matrix_cl_view::Upper);
  block(dst_block_cl, 0, 1, 2, 2)
      = stan::math::broadcast<true, false>(stan::math::transpose(v_cl)) + m_cl;
  EXPECT_EQ(dst_block_cl.view(), stan::math::matrix_cl_view::Upper);
  block(dst_block_cl, 0, 0, 2, 2)
      = stan::math::broadcast<false, true>(v_cl) + m_cl;
  EXPECT_EQ(dst_block_cl.view(), stan::math::matrix_cl_view::Entire);
}

#endif