<commit_before>/**
 * This code is released under the
 * Apache License Version 2.0 http://www.apache.org/licenses/.
 *
 */

#include <unistd.h>
#include "synthetic.h"
#include "timer.h"
#include "intersection.h"

// https://code.google.com/p/likwid/wiki/LikwidPerfCtr#Using_the_marker_API
#ifdef LIKWID_MARKERS  // see 'make likwidintersection' for compiler flags
#include <likwid.h>
#endif

/**
 * Goal: have the largest array count about 4M terms (this
 * matches our experiments), and vary the size of the
 * smallest array vary from 1*4M to 1/1000*4M (or so).
 *
 * Set the size of the intersection to 30% of the lesser
 * array. (Again, this matches our real data...)
 *
 * To match our clueweb, we use a range of values in [0,2**26).
 */
template <class generator>
pair<vector<uint32_t>, vector<uint32_t>> getNaivePair(generator gen, uint32_t minlength, uint32_t Max, float sizeratio,
float intersectionratio) {
    if (sizeratio < 1) throw runtime_error("sizeratio should be larger or equal to 1");
    if (intersectionratio < 0) throw runtime_error("intersectionratio should be positive");
    if (intersectionratio > 1) throw runtime_error("intersectionratio cannot be larger than 1");
    const uint32_t maxlenth = static_cast<uint32_t>(round(static_cast<float>(minlength) * sizeratio));
    if (maxlenth > Max)  throw runtime_error("I can't generate an array so large in such a small range.");
    if (maxlenth < minlength) throw runtime_error("something went wrong, possibly an overflow.");
    // we basically assume that, if we do nothing, intersections are very small
    const uint32_t intersize = static_cast<uint32_t>(round(static_cast<float>(minlength) * intersectionratio));

    vector<uint32_t> inter = gen.generate(intersize, Max);
    vector<uint32_t> smallest =  unite(gen.generate(static_cast<uint32_t>(minlength - inter.size()), Max), inter);
    vector<uint32_t> largest = unite(gen.generate(static_cast<uint32_t>(maxlenth - inter.size()), Max), inter);
    vector<uint32_t> intersection = intersect(smallest, largest);
    if (largest.size() > smallest.size())
        return pair<vector<uint32_t>, vector<uint32_t>>(smallest, largest);
    return pair<vector<uint32_t>, vector<uint32_t>>(largest, smallest);

}

void printusage() {
#ifdef LIKWID_MARKERS
    cout << "example: likwid -m -C 1 -g BRANCH ./likwidintersection -u > uniform.out" << endl;
#else
    cout << " -u switches to uniform distribution" << endl;
#endif
}

int main(int argc, char **argv) {
    size_t howmany = 0;
    size_t loop = 3;
    bool uniform = false;
    uint32_t Big = 22;
    float intersectionratio = 0.3f;
    uint32_t MaxBit = 26;
    int c;
    while ((c = getopt(argc, argv, "uns:m:R:M:S:l:h")) != -1)
        switch (c) {
        case 'h':
            printusage();
            return 0;
        case 'S':
            Big = atoi(optarg);
            break;
        case 'R':
            intersectionratio = atof(optarg);
            break;
        case 'M':
            intersectionratio = atoi(optarg);
            if (MaxBit < 1) {
                printusage();
                return -1;
            }
            break;
        case 'm':
            howmany = atoi(optarg);
            if (howmany < 1) {
                printusage();
                return -1;
            }
            break;
        case 'l':
            loop = atoi(optarg);
            if (loop < 1) {
                printusage();
                return -1;
            }
            break;
        case 'u':
            uniform = true;
            break;
        default:
            abort();
        }
    if (howmany == 0) {
        howmany = 5;
    }
    cout << "# howmany : " << howmany << endl;
    cout << "# loop : " << loop << endl;
    cout << "# distribution : " << (uniform ? "uniform" : "clustered") << endl;
    cout << "# Big : " << Big << endl;
    cout << "# intersectionratio : " << intersectionratio << endl;
    cout << "# MaxBit : " << MaxBit << endl;
    UniformDataGenerator udg;
    ClusteredDataGenerator cdg;
    WallClockTimer z;
    size_t bogus = 0;
    vector <uint32_t> buffer(2 * (1U << Big));
#ifdef LIKWID_MARKERS
    char currentMarker[64];
    likwid_markerInit();
#endif

    cout << "# size-ratio\t";
    for (string intername : IntersectionFactory::allNames()) {
        cout << intername << "\t";
    }
    cout << "relative-intersection-size " << endl;

    for (float ir = 1.001; ir <= 10000; ir = ir * sqrt(1.9)) {
        vector <pair<vector<uint32_t> , vector<uint32_t>>> data(howmany);
        uint32_t smallsize = static_cast<uint32_t>(round(static_cast<float>(1 << Big) / ir));
        cout << "#generating data...";
        cout.flush();
        for (size_t k = 0; k < howmany; ++k) {
            data[k] = uniform ? getNaivePair(udg , smallsize, 1U << MaxBit, ir, intersectionratio)
                      : getNaivePair(cdg , smallsize, 1U << MaxBit, ir, intersectionratio);
        }
        cout << "ok." << endl;
        cout << ir << "\t";
        float aratio = 0.0f;
        for (string intername : IntersectionFactory::allNames()) {
            intersectionfunction interfnc = IntersectionFactory::getFromName(intername);
            size_t volume = 0;
#ifdef LIKWID_MARKERS
            snprintf(currentMarker, sizeof(currentMarker), "%s %.2f", intername.c_str(), ir);
            likwid_markerStartRegion(currentMarker);
#endif
            z.reset();
            for (size_t k = 0; k < data.size(); ++k) {
                volume += (data[k].first.size() + data[k].second.size()) * loop;
                for (size_t L = 0; L < loop; ++L) {
                    aratio = interfnc(data[k].first.data(),
                                      (data[k].first).size(), data[k].second.data(),
                                      (data[k].second).size(), buffer.data());
                    bogus += aratio;
                }
            }
            cout << setw(10) << setprecision(5) << (volume / (static_cast<double>(z.split()))) << "\t";
#ifdef LIKWID_MARKERS
            likwid_markerStopRegion(currentMarker);
#endif
        }
        cout << "\t\t" << aratio / smallsize;
        cout << endl;

    }
#ifdef LIKWID_MARKERS
    likwid_markerClose();
#endif

    cout << "# bogus = " << bogus << endl;
}
<commit_msg>Fixing minor typo<commit_after>/**
 * This code is released under the
 * Apache License Version 2.0 http://www.apache.org/licenses/.
 *
 */

#include <unistd.h>
#include "synthetic.h"
#include "timer.h"
#include "intersection.h"

// https://code.google.com/p/likwid/wiki/LikwidPerfCtr#Using_the_marker_API
#ifdef LIKWID_MARKERS  // see 'make likwidintersection' for compiler flags
#include <likwid.h>
#endif

/**
 * Goal: have the largest array count about 4M terms (this
 * matches our experiments), and vary the size of the
 * smallest array vary from 1*4M to 1/1000*4M (or so).
 *
 * Set the size of the intersection to 30% of the lesser
 * array. (Again, this matches our real data...)
 *
 * To match our clueweb, we use a range of values in [0,2**26).
 */
template <class generator>
pair<vector<uint32_t>, vector<uint32_t>> getNaivePair(generator gen, uint32_t minlength, uint32_t Max, float sizeratio,
float intersectionratio) {
    if (sizeratio < 1) throw runtime_error("sizeratio should be larger or equal to 1");
    if (intersectionratio < 0) throw runtime_error("intersectionratio should be positive");
    if (intersectionratio > 1) throw runtime_error("intersectionratio cannot be larger than 1");
    const uint32_t maxlenth = static_cast<uint32_t>(round(static_cast<float>(minlength) * sizeratio));
    if (maxlenth > Max)  throw runtime_error("I can't generate an array so large in such a small range.");
    if (maxlenth < minlength) throw runtime_error("something went wrong, possibly an overflow.");
    // we basically assume that, if we do nothing, intersections are very small
    const uint32_t intersize = static_cast<uint32_t>(round(static_cast<float>(minlength) * intersectionratio));

    vector<uint32_t> inter = gen.generate(intersize, Max);
    vector<uint32_t> smallest =  unite(gen.generate(static_cast<uint32_t>(minlength - inter.size()), Max), inter);
    vector<uint32_t> largest = unite(gen.generate(static_cast<uint32_t>(maxlenth - inter.size()), Max), inter);
    vector<uint32_t> intersection = intersect(smallest, largest);
    if (largest.size() > smallest.size())
        return pair<vector<uint32_t>, vector<uint32_t>>(smallest, largest);
    return pair<vector<uint32_t>, vector<uint32_t>>(largest, smallest);

}

void printusage() {
#ifdef LIKWID_MARKERS
    cout << "example: likwid -m -C 1 -g BRANCH ./likwidintersection -u > uniform.out" << endl;
#else
    cout << " -u switches to uniform distribution" << endl;
#endif
}

int main(int argc, char **argv) {
    size_t howmany = 0;
    size_t loop = 3;
    bool uniform = false;
    uint32_t Big = 22;
    float intersectionratio = 0.3f;
    uint32_t MaxBit = 26;
    int c;
    while ((c = getopt(argc, argv, "uns:m:R:M:S:l:h")) != -1)
        switch (c) {
        case 'h':
            printusage();
            return 0;
        case 'S':
            Big = atoi(optarg);
            break;
        case 'R':
            intersectionratio = atof(optarg);
            break;
        case 'M':
            MaxBit = atoi(optarg);
            if (MaxBit < 1) {
                printusage();
                return -1;
            }
            break;
        case 'm':
            howmany = atoi(optarg);
            if (howmany < 1) {
                printusage();
                return -1;
            }
            break;
        case 'l':
            loop = atoi(optarg);
            if (loop < 1) {
                printusage();
                return -1;
            }
            break;
        case 'u':
            uniform = true;
            break;
        default:
            abort();
        }
    if (howmany == 0) {
        howmany = 5;
    }
    cout << "# howmany : " << howmany << endl;
    cout << "# loop : " << loop << endl;
    cout << "# distribution : " << (uniform ? "uniform" : "clustered") << endl;
    cout << "# Big : " << Big << endl;
    cout << "# intersectionratio : " << intersectionratio << endl;
    cout << "# MaxBit : " << MaxBit << endl;
    UniformDataGenerator udg;
    ClusteredDataGenerator cdg;
    WallClockTimer z;
    size_t bogus = 0;
    vector <uint32_t> buffer(2 * (1U << Big));
#ifdef LIKWID_MARKERS
    char currentMarker[64];
    likwid_markerInit();
#endif

    cout << "# size-ratio\t";
    for (string intername : IntersectionFactory::allNames()) {
        cout << intername << "\t";
    }
    cout << "relative-intersection-size " << endl;

    for (float ir = 1.001; ir <= 10000; ir = ir * sqrt(1.9)) {
        vector <pair<vector<uint32_t> , vector<uint32_t>>> data(howmany);
        uint32_t smallsize = static_cast<uint32_t>(round(static_cast<float>(1 << Big) / ir));
        cout << "#generating data...";
        cout.flush();
        for (size_t k = 0; k < howmany; ++k) {
            data[k] = uniform ? getNaivePair(udg , smallsize, 1U << MaxBit, ir, intersectionratio)
                      : getNaivePair(cdg , smallsize, 1U << MaxBit, ir, intersectionratio);
        }
        cout << "ok." << endl;
        cout << ir << "\t";
        float aratio = 0.0f;
        for (string intername : IntersectionFactory::allNames()) {
            intersectionfunction interfnc = IntersectionFactory::getFromName(intername);
            size_t volume = 0;
#ifdef LIKWID_MARKERS
            snprintf(currentMarker, sizeof(currentMarker), "%s %.2f", intername.c_str(), ir);
            likwid_markerStartRegion(currentMarker);
#endif
            z.reset();
            for (size_t k = 0; k < data.size(); ++k) {
                volume += (data[k].first.size() + data[k].second.size()) * loop;
                for (size_t L = 0; L < loop; ++L) {
                    aratio = interfnc(data[k].first.data(),
                                      (data[k].first).size(), data[k].second.data(),
                                      (data[k].second).size(), buffer.data());
                    bogus += aratio;
                }
            }
            cout << setw(10) << setprecision(5) << (volume / (static_cast<double>(z.split()))) << "\t";
#ifdef LIKWID_MARKERS
            likwid_markerStopRegion(currentMarker);
#endif
        }
        cout << "\t\t" << aratio / smallsize;
        cout << endl;

    }
#ifdef LIKWID_MARKERS
    likwid_markerClose();
#endif

    cout << "# bogus = " << bogus << endl;
}
<|endoftext|>


<commit_before>///////////////////////////////////////////////////////////////////////////////
//
// For more information, please see: http://www.nektar.info
//
// The MIT License
//
// Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
// Department of Aeronautics, Imperial College London (UK), and Scientific
// Computing and Imaging Institute, University of Utah (USA).
//
// License for the specific language governing rights and limitations under
// 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 NEKTAR_USE_EXPRESSION_TEMPLATES
#define NEKTAR_USE_EXPRESSION_TEMPLATES
#endif //NEKTAR_USE_EXPRESSION_TEMPLATES

#include <boost/test/auto_unit_test.hpp>
#include <boost/test/test_case_template.hpp>
#include <boost/test/floating_point_comparison.hpp>
#include <boost/test/unit_test.hpp>

#include <UnitTests/LibUtilities/ExpressionTemplates/CountedObjectExpression.h>
#include <LibUtilities/LinearAlgebra/NekMatrix.hpp>
#include <ExpressionTemplates/Node.hpp>
#include <ExpressionTemplates/RemoveAllUnecessaryTemporaries.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/type_traits.hpp>
#include <LibUtilities/LinearAlgebra/MatrixSize.hpp>

namespace Nektar
{
    namespace UnitTests
    {
        BOOST_AUTO_TEST_CASE(TestMatrixSizeConstantNode)
        {
            typedef NekMatrix<NekDouble> Matrix;
            typedef NekVector<NekDouble> Vector;

            typedef Node<Matrix> LhsNode;
            typedef Node<Vector> RhsNode;
            typedef Node<LhsNode, MultiplyOp, RhsNode> Expression;
            typedef Expression::Indices Indices;

            double m_buf[] = {1, 4, 2, 5, 3, 6};
            double v_buf[] = {1, 2, 3};
            Matrix m(2, 3, m_buf);
            Vector v(3, v_buf);

            Expression e = m*v;

            boost::tuple<unsigned int, unsigned int, unsigned int> sizes =
                MatrixSize<LhsNode, Indices, 0>::GetRequiredSize(e.GetData());

            unsigned int rows = sizes.get<0>();
            unsigned int cols = sizes.get<1>();
            unsigned int bufferSize = sizes.get<2>();

            BOOST_CHECK_EQUAL(rows, 2u);
            BOOST_CHECK_EQUAL(cols, 3u);
            BOOST_CHECK_EQUAL(bufferSize, rows*cols);

            rows = 0;
            cols = 0;
            bufferSize = 0;
            sizes = MatrixSize<RhsNode, Indices, 1>::GetRequiredSize(e.GetData());
            rows = sizes.get<0>();
            cols = sizes.get<1>();
            bufferSize = sizes.get<2>();

            BOOST_CHECK_EQUAL(rows, 3u);
            BOOST_CHECK_EQUAL(cols, 1u);
            BOOST_CHECK_EQUAL(bufferSize, rows*cols);

            sizes = MatrixSize<Expression, Indices, 0>::GetRequiredSize(e.GetData());
            rows = sizes.get<0>();
            cols = sizes.get<1>();
            bufferSize = sizes.get<2>();
            BOOST_CHECK_EQUAL(rows, 2u);
            BOOST_CHECK_EQUAL(cols, 1u);
            BOOST_CHECK_EQUAL(bufferSize, rows*cols);
        }

        BOOST_AUTO_TEST_CASE(TestConstantConstantTree)
        {
            typedef Node<CountedObject<double> > LhsNode;
            BOOST_MPL_ASSERT(( boost::is_same<LhsNode::ResultType, CountedObject<double> > ));
            BOOST_MPL_ASSERT(( boost::is_same<LhsNode::DataType, const CountedObject<double>&> ));

            typedef Node<CountedObject<double> > RhsNode;
            typedef Node<LhsNode, AddOp, RhsNode> Expression;
            typedef Expression::Indices Indices;

            typedef RemoveUnecessaryTemporaries<Expression, Indices>::TransformedNodeType TransformedNodeType;
            BOOST_MPL_ASSERT(( boost::is_same<Expression, TransformedNodeType> ));

            typedef RemoveUnecessaryTemporaries<Expression, Indices>::TransformedIndices TransformedIndices;
            BOOST_STATIC_ASSERT(( boost::mpl::size<TransformedIndices>::type::value == 2 ));
            BOOST_STATIC_ASSERT(( boost::mpl::at_c<TransformedIndices, 0>::type::value == 0 ));
            BOOST_STATIC_ASSERT(( boost::mpl::at_c<TransformedIndices, 1>::type::value == 1 ));

            typedef boost::fusion::vector2<const CountedObject<double>&, const CountedObject<double>&> ExpectedListType;
            BOOST_MPL_ASSERT(( boost::is_same<Expression::VectorType, ExpectedListType> ));

            CountedObject<double> lhs(3);
            CountedObject<double> rhs(17);
            CountedObject<double>::ClearCounters();

            Expression e = lhs + rhs;
            CountedObject<double>::Check(0, 0, 0, 0, 0, 0);
            CountedObject<double> result = lhs + rhs;
            CountedObject<double>::Check(0, 0, 0, 0, 0, 0);
            BOOST_CHECK_EQUAL( CountedObject<double>::numberOfExpressionConstructions, 1 );
            BOOST_CHECK_EQUAL( CountedObject<double>::numberOfExpressionAssignments, 0 );

            BOOST_CHECK_EQUAL(result.value, lhs.value + rhs.value);
        }

        BOOST_AUTO_TEST_CASE(TestConstantConstantTreeVaryDataType)
        {
            typedef NekMatrix<NekDouble> Matrix;
            typedef NekVector<NekDouble> Vector;

            typedef Node<Matrix> LhsNode;
            BOOST_MPL_ASSERT(( boost::is_same<LhsNode::ResultType, Matrix > ));
            BOOST_MPL_ASSERT(( boost::is_same<LhsNode::DataType, const Matrix&> ));

            typedef Node<Vector> RhsNode;
            typedef Node<LhsNode, MultiplyOp, RhsNode> Expression;
            typedef Expression::Indices Indices;

            typedef RemoveUnecessaryTemporaries<Expression, Indices>::TransformedNodeType TransformedNodeType;
            BOOST_MPL_ASSERT(( boost::is_same<Expression, TransformedNodeType> ));

            typedef RemoveUnecessaryTemporaries<Expression, Indices>::TransformedIndices TransformedIndices;
            BOOST_STATIC_ASSERT(( boost::mpl::size<TransformedIndices>::type::value == 2 ));
            BOOST_STATIC_ASSERT(( boost::mpl::at_c<TransformedIndices, 0>::type::value == 0 ));
            BOOST_STATIC_ASSERT(( boost::mpl::at_c<TransformedIndices, 1>::type::value == 1 ));

            typedef boost::fusion::vector2<const Matrix&, const Vector&> ExpectedListType;
            BOOST_MPL_ASSERT(( boost::is_same<Expression::VectorType, ExpectedListType> ));

            double m_buf[] = {1, 4, 2, 5, 3, 6};
            double v_buf[] = {1, 2, 3};
            Matrix m(2, 3, m_buf);
            Vector v(3, v_buf);

            Expression e = m*v;
            Vector result = m*v;

            double expected_result_buf[] = {1+4+9, 4+10+18};
            Vector expected_result(2, expected_result_buf);
            BOOST_CHECK_EQUAL(result, expected_result);
        }

    }

    BOOST_AUTO_TEST_CASE(TestBinaryBinaryMatrixTree)
    {
        typedef NekMatrix<NekDouble> Matrix;
        double m_buf[] = {1, 4, 2, 5};
        Matrix m1(2, 2, m_buf);
        Matrix m2(2, 2, m_buf);
        Matrix m3(2, 2, m_buf);
        Matrix m4(2, 2, m_buf);

        Array<TwoD, const NekDouble> gmat;

        Matrix result = m1*m2 + m3*m4;
        //Matrix result1 = (gmat[0][0]*gmat[0][0]+gmat[2][0]*gmat[2][0]+gmat[4][0]*gmat[4][0])* (m1) +
        //    (gmat[0][0]*gmat[1][0] + gmat[2][0]*gmat[3][0] + gmat[4][0]*gmat[5][0])*(m2 + Transpose(m2)) +
        //    (gmat[1][0]*gmat[1][0] + gmat[3][0]*gmat[3][0] + gmat[5][0]*gmat[5][0])* (m3);
        //Matrix result2 = (1.0)*(m1) + (2.0)*(m2) + (3.0)*(m3);

        //Matrix result3 = m1*m1 + m2*m2 + m3*m3;
        typedef Node<Node<Matrix>, MultiplyOp, Node<Matrix> > T;
        typedef Node<T, AddOp, T> Lhs;
        typedef T Rhs;
        typedef Node<Lhs, AddOp, Rhs> ExpressionType;
        ExpressionType e = m1*m1 + m2*m2 + m3*m3;
        typedef ExpressionType::Indices Indices;

        //typedef RemoveUnecessaryTemporaries<ExpressionType, Indices>::TransformedNodeType TransformedNodeType;
        typedef RemoveUnecessaryTemporaries<ExpressionType, Indices>::TransformedIndices TransformedIndices;
    }
}
<commit_msg>Boost version-dependent fix for ExpressionTemplates unit tests.<commit_after>///////////////////////////////////////////////////////////////////////////////
//
// For more information, please see: http://www.nektar.info
//
// The MIT License
//
// Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
// Department of Aeronautics, Imperial College London (UK), and Scientific
// Computing and Imaging Institute, University of Utah (USA).
//
// License for the specific language governing rights and limitations under
// 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 NEKTAR_USE_EXPRESSION_TEMPLATES
#define NEKTAR_USE_EXPRESSION_TEMPLATES
#endif //NEKTAR_USE_EXPRESSION_TEMPLATES

#include <boost/test/auto_unit_test.hpp>
#include <boost/test/test_case_template.hpp>
#include <boost/test/floating_point_comparison.hpp>
#include <boost/test/unit_test.hpp>

#include <UnitTests/LibUtilities/ExpressionTemplates/CountedObjectExpression.h>
#include <LibUtilities/LinearAlgebra/NekMatrix.hpp>
#include <ExpressionTemplates/Node.hpp>
#include <ExpressionTemplates/RemoveAllUnecessaryTemporaries.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/type_traits.hpp>
#include <LibUtilities/LinearAlgebra/MatrixSize.hpp>

namespace Nektar
{
    namespace UnitTests
    {
        BOOST_AUTO_TEST_CASE(TestMatrixSizeConstantNode)
        {
            typedef NekMatrix<NekDouble> Matrix;
            typedef NekVector<NekDouble> Vector;

            typedef Node<Matrix> LhsNode;
            typedef Node<Vector> RhsNode;
            typedef Node<LhsNode, MultiplyOp, RhsNode> Expression;
            typedef Expression::Indices Indices;

            double m_buf[] = {1, 4, 2, 5, 3, 6};
            double v_buf[] = {1, 2, 3};
            Matrix m(2, 3, m_buf);
            Vector v(3, v_buf);

            Expression e = m*v;

            boost::tuple<unsigned int, unsigned int, unsigned int> sizes =
                MatrixSize<LhsNode, Indices, 0>::GetRequiredSize(e.GetData());

            unsigned int rows = sizes.get<0>();
            unsigned int cols = sizes.get<1>();
            unsigned int bufferSize = sizes.get<2>();

            BOOST_CHECK_EQUAL(rows, 2u);
            BOOST_CHECK_EQUAL(cols, 3u);
            BOOST_CHECK_EQUAL(bufferSize, rows*cols);

            rows = 0;
            cols = 0;
            bufferSize = 0;
            sizes = MatrixSize<RhsNode, Indices, 1>::GetRequiredSize(e.GetData());
            rows = sizes.get<0>();
            cols = sizes.get<1>();
            bufferSize = sizes.get<2>();

            BOOST_CHECK_EQUAL(rows, 3u);
            BOOST_CHECK_EQUAL(cols, 1u);
            BOOST_CHECK_EQUAL(bufferSize, rows*cols);

            sizes = MatrixSize<Expression, Indices, 0>::GetRequiredSize(e.GetData());
            rows = sizes.get<0>();
            cols = sizes.get<1>();
            bufferSize = sizes.get<2>();
            BOOST_CHECK_EQUAL(rows, 2u);
            BOOST_CHECK_EQUAL(cols, 1u);
            BOOST_CHECK_EQUAL(bufferSize, rows*cols);
        }

        BOOST_AUTO_TEST_CASE(TestConstantConstantTree)
        {
            typedef Node<CountedObject<double> > LhsNode;
            BOOST_MPL_ASSERT(( boost::is_same<LhsNode::ResultType, CountedObject<double> > ));
            BOOST_MPL_ASSERT(( boost::is_same<LhsNode::DataType, const CountedObject<double>&> ));

            typedef Node<CountedObject<double> > RhsNode;
            typedef Node<LhsNode, AddOp, RhsNode> Expression;
            typedef Expression::Indices Indices;

            typedef RemoveUnecessaryTemporaries<Expression, Indices>::TransformedNodeType TransformedNodeType;
            BOOST_MPL_ASSERT(( boost::is_same<Expression, TransformedNodeType> ));

            typedef RemoveUnecessaryTemporaries<Expression, Indices>::TransformedIndices TransformedIndices;
            BOOST_STATIC_ASSERT(( boost::mpl::size<TransformedIndices>::type::value == 2 ));
            BOOST_STATIC_ASSERT(( boost::mpl::at_c<TransformedIndices, 0>::type::value == 0 ));
            BOOST_STATIC_ASSERT(( boost::mpl::at_c<TransformedIndices, 1>::type::value == 1 ));

#if BOOST_VERSION < 104200
            typedef boost::fusion::vector<const CountedObject<double>&, const CountedObject<double>&> ExpectedListType;
#else
            typedef boost::fusion::vector2<const CountedObject<double>&, const CountedObject<double>&> ExpectedListType;
#endif
            BOOST_MPL_ASSERT(( boost::is_same<Expression::VectorType, ExpectedListType> ));

            CountedObject<double> lhs(3);
            CountedObject<double> rhs(17);
            CountedObject<double>::ClearCounters();

            Expression e = lhs + rhs;
            CountedObject<double>::Check(0, 0, 0, 0, 0, 0);
            CountedObject<double> result = lhs + rhs;
            CountedObject<double>::Check(0, 0, 0, 0, 0, 0);
            BOOST_CHECK_EQUAL( CountedObject<double>::numberOfExpressionConstructions, 1 );
            BOOST_CHECK_EQUAL( CountedObject<double>::numberOfExpressionAssignments, 0 );

            BOOST_CHECK_EQUAL(result.value, lhs.value + rhs.value);
        }

        BOOST_AUTO_TEST_CASE(TestConstantConstantTreeVaryDataType)
        {
            typedef NekMatrix<NekDouble> Matrix;
            typedef NekVector<NekDouble> Vector;

            typedef Node<Matrix> LhsNode;
            BOOST_MPL_ASSERT(( boost::is_same<LhsNode::ResultType, Matrix > ));
            BOOST_MPL_ASSERT(( boost::is_same<LhsNode::DataType, const Matrix&> ));

            typedef Node<Vector> RhsNode;
            typedef Node<LhsNode, MultiplyOp, RhsNode> Expression;
            typedef Expression::Indices Indices;

            typedef RemoveUnecessaryTemporaries<Expression, Indices>::TransformedNodeType TransformedNodeType;
            BOOST_MPL_ASSERT(( boost::is_same<Expression, TransformedNodeType> ));

            typedef RemoveUnecessaryTemporaries<Expression, Indices>::TransformedIndices TransformedIndices;
            BOOST_STATIC_ASSERT(( boost::mpl::size<TransformedIndices>::type::value == 2 ));
            BOOST_STATIC_ASSERT(( boost::mpl::at_c<TransformedIndices, 0>::type::value == 0 ));
            BOOST_STATIC_ASSERT(( boost::mpl::at_c<TransformedIndices, 1>::type::value == 1 ));

#if BOOST_VERSION < 104200
            typedef boost::fusion::vector<const Matrix&, const Vector&> ExpectedListType;
#else
            typedef boost::fusion::vector2<const Matrix&, const Vector&> ExpectedListType;
#endif
            BOOST_MPL_ASSERT(( boost::is_same<Expression::VectorType, ExpectedListType> ));

            double m_buf[] = {1, 4, 2, 5, 3, 6};
            double v_buf[] = {1, 2, 3};
            Matrix m(2, 3, m_buf);
            Vector v(3, v_buf);

            Expression e = m*v;
            Vector result = m*v;

            double expected_result_buf[] = {1+4+9, 4+10+18};
            Vector expected_result(2, expected_result_buf);
            BOOST_CHECK_EQUAL(result, expected_result);
        }

    }

    BOOST_AUTO_TEST_CASE(TestBinaryBinaryMatrixTree)
    {
        typedef NekMatrix<NekDouble> Matrix;
        double m_buf[] = {1, 4, 2, 5};
        Matrix m1(2, 2, m_buf);
        Matrix m2(2, 2, m_buf);
        Matrix m3(2, 2, m_buf);
        Matrix m4(2, 2, m_buf);

        Array<TwoD, const NekDouble> gmat;

        Matrix result = m1*m2 + m3*m4;
        //Matrix result1 = (gmat[0][0]*gmat[0][0]+gmat[2][0]*gmat[2][0]+gmat[4][0]*gmat[4][0])* (m1) +
        //    (gmat[0][0]*gmat[1][0] + gmat[2][0]*gmat[3][0] + gmat[4][0]*gmat[5][0])*(m2 + Transpose(m2)) +
        //    (gmat[1][0]*gmat[1][0] + gmat[3][0]*gmat[3][0] + gmat[5][0]*gmat[5][0])* (m3);
        //Matrix result2 = (1.0)*(m1) + (2.0)*(m2) + (3.0)*(m3);

        //Matrix result3 = m1*m1 + m2*m2 + m3*m3;
        typedef Node<Node<Matrix>, MultiplyOp, Node<Matrix> > T;
        typedef Node<T, AddOp, T> Lhs;
        typedef T Rhs;
        typedef Node<Lhs, AddOp, Rhs> ExpressionType;
        ExpressionType e = m1*m1 + m2*m2 + m3*m3;
        typedef ExpressionType::Indices Indices;

        //typedef RemoveUnecessaryTemporaries<ExpressionType, Indices>::TransformedNodeType TransformedNodeType;
        typedef RemoveUnecessaryTemporaries<ExpressionType, Indices>::TransformedIndices TransformedIndices;
    }
}
<|endoftext|>


<commit_before>#ifndef _SDD_MANAGER_HH_
#define _SDD_MANAGER_HH_

#include <stdexcept> // runtime_error

#include "sdd/internal_manager.hh"
#include "sdd/values_manager.hh"

namespace sdd {

/*------------------------------------------------------------------------------------------------*/

/// @brief This class represents the global context of the library.
///
/// It can only be created by the init() function. It is safe to use the library as long as the
/// instance returned by manager::init() exists.
template <typename C>
class manager final
{
  // Can't copy a manager.
  manager(const manager&) = delete;
  manager& operator=(const manager&) = delete;

private:

  /// @brief The type of a set of values.
  using values_type = typename C::Values;

  /// @brief Keep the configuration.
  const C conf_;

  /// @brief The manager of Values.
  values_manager<values_type>* values_;

  /// @brief The manager of SDD and homomorphisms.
  internal_manager<C>* m_;

  /// @brief Construct a manager from an internal manager.
  manager(const C& conf, values_manager<values_type>* v, internal_manager<C>* m)
    : conf_(conf), values_(v), m_(m)
  {}

public:

  /// @brief Initialize the library for a specific configuration.
  /// @tparam C The configuration type.
  /// @param configuration An instance of the configuration with some parameters set.
  /// @throw std::runtime_error if the library was already configured.
  ///
  /// It must be the first function called before any other call to the library.
  static
  manager<C>
  init(const C& configuration = C())
  {
    if (*global_ptr<C>() == nullptr and *global_ptr<values_type>() == nullptr)
    {
      values_manager<values_type>* v = new values_manager<values_type>(configuration);
      if (not v)
      {
        throw std::runtime_error("Can't allocate values manager.");
      }

      *global_values_ptr<values_type>() = v;

      internal_manager<C>* g = new internal_manager<C>(configuration);
      if (not g)
      {
        delete v;
        throw std::runtime_error("Can't allocate internal manager.");
      }
      *global_ptr<C>() = g;

      return manager<C>(configuration, v, g);
    }
    else
    {
      throw std::runtime_error("Library already initialized.");
    }
  }

  /// @brief Destructor.
  ~manager()
  {
    if (m_)
    {
      *global_ptr<C>() = nullptr;
      if (conf_.final_cleanup)
      {
        delete m_;
      }
    }
    if (values_)
    {
      *global_values_ptr<values_type>() = nullptr;
      if (conf_.final_cleanup)
      {
        delete values_;
      }
    }
  }

  /// @brief Reset homomorphisms evaluation cache.
  void
  reset_hom_cache()
  {
    m_->hom_context.clear();
  }

  /// @brief Get the statistics for SDDs.
  mem::unique_table_statistics
  sdd_stats()
  const noexcept
  {
    return m_->sdd_unique_table.stats();
  }

  /// @brief Get the statistics for homomorphisms.
  mem::unique_table_statistics
  hom_stats()
  const noexcept
  {
    return m_->hom_unique_table.stats();
  }

  /// @brief Default move constructor.
  manager(manager&&) = default;

  /// @brief Default move operator.
  manager& operator=(manager&&) = default;
};

/*------------------------------------------------------------------------------------------------*/

} // namespace sdd

#endif // _SDD_MANAGER_HH_
<commit_msg>Statistics are internal stuff.<commit_after>#ifndef _SDD_MANAGER_HH_
#define _SDD_MANAGER_HH_

#include <stdexcept> // runtime_error

#include "sdd/internal_manager.hh"
#include "sdd/values_manager.hh"

namespace sdd {

/*------------------------------------------------------------------------------------------------*/

/// @brief This class represents the global context of the library.
///
/// It can only be created by the init() function. It is safe to use the library as long as the
/// instance returned by manager::init() exists.
template <typename C>
class manager final
{
  // Can't copy a manager.
  manager(const manager&) = delete;
  manager& operator=(const manager&) = delete;

private:

  /// @brief The type of a set of values.
  using values_type = typename C::Values;

  /// @brief Keep the configuration.
  const C conf_;

  /// @brief The manager of Values.
  values_manager<values_type>* values_;

  /// @brief The manager of SDD and homomorphisms.
  internal_manager<C>* m_;

  /// @brief Construct a manager from an internal manager.
  manager(const C& conf, values_manager<values_type>* v, internal_manager<C>* m)
    : conf_(conf), values_(v), m_(m)
  {}

public:

  /// @brief Initialize the library for a specific configuration.
  /// @tparam C The configuration type.
  /// @param configuration An instance of the configuration with some parameters set.
  /// @throw std::runtime_error if the library was already configured.
  ///
  /// It must be the first function called before any other call to the library.
  static
  manager<C>
  init(const C& configuration = C())
  {
    if (*global_ptr<C>() == nullptr and *global_ptr<values_type>() == nullptr)
    {
      values_manager<values_type>* v = new values_manager<values_type>(configuration);
      if (not v)
      {
        throw std::runtime_error("Can't allocate values manager.");
      }

      *global_values_ptr<values_type>() = v;

      internal_manager<C>* g = new internal_manager<C>(configuration);
      if (not g)
      {
        delete v;
        throw std::runtime_error("Can't allocate internal manager.");
      }
      *global_ptr<C>() = g;

      return manager<C>(configuration, v, g);
    }
    else
    {
      throw std::runtime_error("Library already initialized.");
    }
  }

  /// @brief Destructor.
  ~manager()
  {
    if (m_)
    {
      *global_ptr<C>() = nullptr;
      if (conf_.final_cleanup)
      {
        delete m_;
      }
    }
    if (values_)
    {
      *global_values_ptr<values_type>() = nullptr;
      if (conf_.final_cleanup)
      {
        delete values_;
      }
    }
  }

  /// @brief Default move constructor.
  manager(manager&&) = default;

  /// @brief Default move operator.
  manager& operator=(manager&&) = default;

  /// @brief Reset homomorphisms evaluation cache.
  void
  reset_hom_cache()
  {
    m_->hom_context.clear();
  }

  /// @internal
  /// @brief Get the statistics for SDDs.
  mem::unique_table_statistics
  sdd_stats()
  const noexcept
  {
    return m_->sdd_unique_table.stats();
  }

  /// @internal
  /// @brief Get the statistics for homomorphisms.
  mem::unique_table_statistics
  hom_stats()
  const noexcept
  {
    return m_->hom_unique_table.stats();
  }
};

/*------------------------------------------------------------------------------------------------*/

} // namespace sdd

#endif // _SDD_MANAGER_HH_
<|endoftext|>


<commit_before>/**
 * @file hoeffding_tree_main.cpp
 * @author Ryan Curtin
 *
 * A command-line executable that can build a streaming decision tree.
 */
#include <mlpack/core.hpp>
#include <mlpack/methods/hoeffding_trees/hoeffding_tree.hpp>
#include <mlpack/methods/hoeffding_trees/binary_numeric_split.hpp>
#include <mlpack/methods/hoeffding_trees/information_gain.hpp>

using namespace std;
using namespace mlpack;
using namespace mlpack::tree;
using namespace mlpack::data;

PARAM_STRING("training_file", "Training dataset file.", "t", "");
PARAM_STRING("labels_file", "Labels for training dataset.", "l", "");

PARAM_DOUBLE("confidence", "Confidence before splitting (between 0 and 1).",
    "c", 0.95);
PARAM_INT("max_samples", "Maximum number of samples before splitting.", "n",
    5000);

PARAM_STRING("input_model_file", "File to load trained tree from.", "m", "");
PARAM_STRING("output_model_file", "File to save trained tree to.", "M", "");

PARAM_STRING("test_file", "File of testing data.", "T", "");
PARAM_STRING("predictions_file", "File to output label predictions for test "
    "data into.", "p", "");
PARAM_STRING("probabilities_file", "In addition to predicting labels, provide "
    "prediction probabilities in this file.", "P", "");

PARAM_STRING("numeric_split_strategy", "The splitting strategy to use for "
    "numeric features: 'domingos' or 'binary'.", "N", "binary");
PARAM_FLAG("batch_mode", "If true, samples will be considered in batch instead "
    "of as a stream.  This generally results in better trees but at the cost of"
    " memory usage and runtime.", "b");
PARAM_FLAG("info_gain", "If set, information gain is used instead of Gini "
    "impurity for calculating Hoeffding bounds.", "i");
PARAM_INT("passes", "Number of passes to take over the dataset.", "s", 1);

PARAM_INT("bins", "If the 'domingos' split strategy is used, this specifies "
    "the number of bins for each numeric split.", "B", 10);
PARAM_INT("observations_before_binning", "If the 'domingos' split strategy is "
    "used, this specifies the number of samples observed before binning is "
    "performed.", "o", 100);

// Helper function for once we have chosen a tree type.
template<typename TreeType>
void PerformActions(const typename TreeType::NumericSplit& numericSplit =
    typename TreeType::NumericSplit(0));

int main(int argc, char** argv)
{
  CLI::ParseCommandLine(argc, argv);

  // Check input parameters for validity.
  const string trainingFile = CLI::GetParam<string>("training_file");
  const string labelsFile = CLI::GetParam<string>("labels_file");
  const string inputModelFile = CLI::GetParam<string>("input_model_file");
  const string testFile = CLI::GetParam<string>("test_file");
  const string predictionsFile = CLI::GetParam<string>("predictions_file");
  const string probabilitiesFile = CLI::GetParam<string>("probabilities_file");
  const string numericSplitStrategy =
      CLI::GetParam<string>("numeric_split_strategy");

  if ((!predictionsFile.empty() || !probabilitiesFile.empty()) &&
      testFile.empty())
    Log::Fatal << "--test_file must be specified if --predictions_file or "
        << "--probabilities_file is specified." << endl;

  if (trainingFile.empty() && inputModelFile.empty())
    Log::Fatal << "One of --training_file or --input_model_file must be "
        << "specified!" << endl;

  if (!trainingFile.empty() && labelsFile.empty())
    Log::Fatal << "If --training_file is specified, --labels_file must be "
        << "specified too!" << endl;

  if (trainingFile.empty() && CLI::HasParam("batch_mode"))
    Log::Warn << "--batch_mode (-b) ignored; no training set provided." << endl;

  if (CLI::HasParam("passes") && CLI::HasParam("batch_mode"))
    Log::Warn << "--batch_mode (-b) ignored because --passes was specified."
        << endl;

  if (CLI::HasParam("info_gain"))
  {
    if (numericSplitStrategy == "domingos")
    {
      const size_t bins = (size_t) CLI::GetParam<int>("bins");
      const size_t observationsBeforeBinning = (size_t)
          CLI::GetParam<int>("observations_before_binning");
      HoeffdingDoubleNumericSplit<InformationGain> ns(0, bins,
          observationsBeforeBinning);
      PerformActions<HoeffdingTree<InformationGain, HoeffdingDoubleNumericSplit,
          HoeffdingCategoricalSplit>>(ns);
    }
    else if (numericSplitStrategy == "binary")
    {
      PerformActions<HoeffdingTree<InformationGain, BinaryDoubleNumericSplit,
          HoeffdingCategoricalSplit>>();
    }
    else
    {
      Log::Fatal << "Unrecognized numeric split strategy ("
          << numericSplitStrategy << ")!  Must be 'domingos' or 'binary'."
          << endl;
    }
  }
  else
  {
    if (numericSplitStrategy == "domingos")
    {
      const size_t bins = (size_t) CLI::GetParam<int>("bins");
      const size_t observationsBeforeBinning = (size_t)
          CLI::GetParam<int>("observations_before_binning");
      HoeffdingDoubleNumericSplit<GiniImpurity> ns(0, bins,
          observationsBeforeBinning);
      PerformActions<HoeffdingTree<GiniImpurity, HoeffdingDoubleNumericSplit,
          HoeffdingCategoricalSplit>>(ns);
    }
    else if (numericSplitStrategy == "binary")
    {
      PerformActions<HoeffdingTree<GiniImpurity, BinaryDoubleNumericSplit,
          HoeffdingCategoricalSplit>>();
    }
    else
    {
      Log::Fatal << "Unrecognized numeric split strategy ("
          << numericSplitStrategy << ")!  Must be 'domingos' or 'binary'."
          << endl;
    }
  }
}

template<typename TreeType>
void PerformActions(const typename TreeType::NumericSplit& numericSplit)
{
  // Load necessary parameters.
  const string trainingFile = CLI::GetParam<string>("training_file");
  const string labelsFile = CLI::GetParam<string>("labels_file");
  const double confidence = CLI::GetParam<double>("confidence");
  const size_t maxSamples = (size_t) CLI::GetParam<int>("max_samples");
  const size_t minSamples = (size_t) CLI::GetParam<size_t>("min_samples");
  const string inputModelFile = CLI::GetParam<string>("input_model_file");
  const string outputModelFile = CLI::GetParam<string>("output_model_file");
  const string testFile = CLI::GetParam<string>("test_file");
  const string predictionsFile = CLI::GetParam<string>("predictions_file");
  const string probabilitiesFile = CLI::GetParam<string>("probabilities_file");
  bool batchTraining = CLI::HasParam("batch_mode");
  const size_t passes = (size_t) CLI::GetParam<int>("passes");
  if (passes > 1)
    batchTraining = false; // We already warned about this earlier.

  TreeType* tree = NULL;
  DatasetInfo datasetInfo;
  if (inputModelFile.empty())
  {
    arma::mat trainingSet;
    data::Load(trainingFile, trainingSet, datasetInfo, true);
    for (size_t i = 0; i < trainingSet.n_rows; ++i)
      Log::Info << datasetInfo.NumMappings(i) << " mappings in dimension "
          << i << "." << endl;

    arma::Col<size_t> labelsIn;
    data::Load(labelsFile, labelsIn, true, false);
    arma::Row<size_t> labels = labelsIn.t();

    // Now create the decision tree.
    Timer::Start("tree_training");
    if (passes > 1)
      Log::Info << "Taking " << passes << " passes over the dataset." << endl;

    tree = new TreeType(trainingSet, datasetInfo, labels, max(labels) + 1,
        batchTraining, confidence, maxSamples, 100, minSamples,
        typename TreeType::CategoricalSplit(0, 0), numericSplit);

    for (size_t i = 1; i < passes; ++i)
      tree->Train(trainingSet, labels, false);
    Timer::Stop("tree_training");
  }
  else
  {
    tree = new TreeType(datasetInfo, 1, 1);
    data::Load(inputModelFile, "streamingDecisionTree", *tree, true);

    if (!trainingFile.empty())
    {
      arma::mat trainingSet;
      data::Load(trainingFile, trainingSet, datasetInfo, true);
      for (size_t i = 0; i < trainingSet.n_rows; ++i)
        Log::Info << datasetInfo.NumMappings(i) << " mappings in dimension "
            << i << "." << endl;

      arma::Col<size_t> labelsIn;
      data::Load(labelsFile, labelsIn, true, false);
      arma::Row<size_t> labels = labelsIn.t();

      // Now create the decision tree.
      Timer::Start("tree_training");
      if (passes > 1)
      {
        Log::Info << "Taking " << passes << " passes over the dataset." << endl;
        for (size_t i = 0; i < passes; ++i)
          tree->Train(trainingSet, labels, false);
      }
      else
      {
        tree->Train(trainingSet, labels, batchTraining);
      }
      Timer::Stop("tree_training");
    }
  }

  // The tree is trained or loaded.  Now do any testing if we need.
  if (!testFile.empty())
  {
    arma::mat testSet;
    data::Load(testFile, testSet, datasetInfo, true);

    arma::Row<size_t> predictions;
    arma::rowvec probabilities;

    Timer::Start("tree_testing");
    tree->Classify(testSet, predictions, probabilities);
    Timer::Stop("tree_testing");

    if (!predictionsFile.empty())
      data::Save(predictionsFile, predictions);

    if (!probabilitiesFile.empty())
      data::Save(probabilitiesFile, probabilities);
  }

  // Check the accuracy on the training set.
  if (!outputModelFile.empty())
    data::Save(outputModelFile, "streamingDecisionTree", tree, true);

  // Clean up memory.
  delete tree;
}
<commit_msg>Add min_samples option.<commit_after>/**
 * @file hoeffding_tree_main.cpp
 * @author Ryan Curtin
 *
 * A command-line executable that can build a streaming decision tree.
 */
#include <mlpack/core.hpp>
#include <mlpack/methods/hoeffding_trees/hoeffding_tree.hpp>
#include <mlpack/methods/hoeffding_trees/binary_numeric_split.hpp>
#include <mlpack/methods/hoeffding_trees/information_gain.hpp>

using namespace std;
using namespace mlpack;
using namespace mlpack::tree;
using namespace mlpack::data;

PARAM_STRING("training_file", "Training dataset file.", "t", "");
PARAM_STRING("labels_file", "Labels for training dataset.", "l", "");

PARAM_DOUBLE("confidence", "Confidence before splitting (between 0 and 1).",
    "c", 0.95);
PARAM_INT("max_samples", "Maximum number of samples before splitting.", "n",
    5000);
PARAM_INT("min_samples", "Minimum number of samples before splitting.", "I",
    100);

PARAM_STRING("input_model_file", "File to load trained tree from.", "m", "");
PARAM_STRING("output_model_file", "File to save trained tree to.", "M", "");

PARAM_STRING("test_file", "File of testing data.", "T", "");
PARAM_STRING("predictions_file", "File to output label predictions for test "
    "data into.", "p", "");
PARAM_STRING("probabilities_file", "In addition to predicting labels, provide "
    "prediction probabilities in this file.", "P", "");

PARAM_STRING("numeric_split_strategy", "The splitting strategy to use for "
    "numeric features: 'domingos' or 'binary'.", "N", "binary");
PARAM_FLAG("batch_mode", "If true, samples will be considered in batch instead "
    "of as a stream.  This generally results in better trees but at the cost of"
    " memory usage and runtime.", "b");
PARAM_FLAG("info_gain", "If set, information gain is used instead of Gini "
    "impurity for calculating Hoeffding bounds.", "i");
PARAM_INT("passes", "Number of passes to take over the dataset.", "s", 1);

PARAM_INT("bins", "If the 'domingos' split strategy is used, this specifies "
    "the number of bins for each numeric split.", "B", 10);
PARAM_INT("observations_before_binning", "If the 'domingos' split strategy is "
    "used, this specifies the number of samples observed before binning is "
    "performed.", "o", 100);

// Helper function for once we have chosen a tree type.
template<typename TreeType>
void PerformActions(const typename TreeType::NumericSplit& numericSplit =
    typename TreeType::NumericSplit(0));

int main(int argc, char** argv)
{
  CLI::ParseCommandLine(argc, argv);

  // Check input parameters for validity.
  const string trainingFile = CLI::GetParam<string>("training_file");
  const string labelsFile = CLI::GetParam<string>("labels_file");
  const string inputModelFile = CLI::GetParam<string>("input_model_file");
  const string testFile = CLI::GetParam<string>("test_file");
  const string predictionsFile = CLI::GetParam<string>("predictions_file");
  const string probabilitiesFile = CLI::GetParam<string>("probabilities_file");
  const string numericSplitStrategy =
      CLI::GetParam<string>("numeric_split_strategy");

  if ((!predictionsFile.empty() || !probabilitiesFile.empty()) &&
      testFile.empty())
    Log::Fatal << "--test_file must be specified if --predictions_file or "
        << "--probabilities_file is specified." << endl;

  if (trainingFile.empty() && inputModelFile.empty())
    Log::Fatal << "One of --training_file or --input_model_file must be "
        << "specified!" << endl;

  if (!trainingFile.empty() && labelsFile.empty())
    Log::Fatal << "If --training_file is specified, --labels_file must be "
        << "specified too!" << endl;

  if (trainingFile.empty() && CLI::HasParam("batch_mode"))
    Log::Warn << "--batch_mode (-b) ignored; no training set provided." << endl;

  if (CLI::HasParam("passes") && CLI::HasParam("batch_mode"))
    Log::Warn << "--batch_mode (-b) ignored because --passes was specified."
        << endl;

  if (CLI::HasParam("info_gain"))
  {
    if (numericSplitStrategy == "domingos")
    {
      const size_t bins = (size_t) CLI::GetParam<int>("bins");
      const size_t observationsBeforeBinning = (size_t)
          CLI::GetParam<int>("observations_before_binning");
      HoeffdingDoubleNumericSplit<InformationGain> ns(0, bins,
          observationsBeforeBinning);
      PerformActions<HoeffdingTree<InformationGain, HoeffdingDoubleNumericSplit,
          HoeffdingCategoricalSplit>>(ns);
    }
    else if (numericSplitStrategy == "binary")
    {
      PerformActions<HoeffdingTree<InformationGain, BinaryDoubleNumericSplit,
          HoeffdingCategoricalSplit>>();
    }
    else
    {
      Log::Fatal << "Unrecognized numeric split strategy ("
          << numericSplitStrategy << ")!  Must be 'domingos' or 'binary'."
          << endl;
    }
  }
  else
  {
    if (numericSplitStrategy == "domingos")
    {
      const size_t bins = (size_t) CLI::GetParam<int>("bins");
      const size_t observationsBeforeBinning = (size_t)
          CLI::GetParam<int>("observations_before_binning");
      HoeffdingDoubleNumericSplit<GiniImpurity> ns(0, bins,
          observationsBeforeBinning);
      PerformActions<HoeffdingTree<GiniImpurity, HoeffdingDoubleNumericSplit,
          HoeffdingCategoricalSplit>>(ns);
    }
    else if (numericSplitStrategy == "binary")
    {
      PerformActions<HoeffdingTree<GiniImpurity, BinaryDoubleNumericSplit,
          HoeffdingCategoricalSplit>>();
    }
    else
    {
      Log::Fatal << "Unrecognized numeric split strategy ("
          << numericSplitStrategy << ")!  Must be 'domingos' or 'binary'."
          << endl;
    }
  }
}

template<typename TreeType>
void PerformActions(const typename TreeType::NumericSplit& numericSplit)
{
  // Load necessary parameters.
  const string trainingFile = CLI::GetParam<string>("training_file");
  const string labelsFile = CLI::GetParam<string>("labels_file");
  const double confidence = CLI::GetParam<double>("confidence");
  const size_t maxSamples = (size_t) CLI::GetParam<int>("max_samples");
  const size_t minSamples = (size_t) CLI::GetParam<size_t>("min_samples");
  const string inputModelFile = CLI::GetParam<string>("input_model_file");
  const string outputModelFile = CLI::GetParam<string>("output_model_file");
  const string testFile = CLI::GetParam<string>("test_file");
  const string predictionsFile = CLI::GetParam<string>("predictions_file");
  const string probabilitiesFile = CLI::GetParam<string>("probabilities_file");
  bool batchTraining = CLI::HasParam("batch_mode");
  const size_t passes = (size_t) CLI::GetParam<int>("passes");
  if (passes > 1)
    batchTraining = false; // We already warned about this earlier.

  TreeType* tree = NULL;
  DatasetInfo datasetInfo;
  if (inputModelFile.empty())
  {
    arma::mat trainingSet;
    data::Load(trainingFile, trainingSet, datasetInfo, true);
    for (size_t i = 0; i < trainingSet.n_rows; ++i)
      Log::Info << datasetInfo.NumMappings(i) << " mappings in dimension "
          << i << "." << endl;

    arma::Col<size_t> labelsIn;
    data::Load(labelsFile, labelsIn, true, false);
    arma::Row<size_t> labels = labelsIn.t();

    // Now create the decision tree.
    Timer::Start("tree_training");
    if (passes > 1)
      Log::Info << "Taking " << passes << " passes over the dataset." << endl;

    tree = new TreeType(trainingSet, datasetInfo, labels, max(labels) + 1,
        batchTraining, confidence, maxSamples, 100, minSamples,
        typename TreeType::CategoricalSplit(0, 0), numericSplit);

    for (size_t i = 1; i < passes; ++i)
      tree->Train(trainingSet, labels, false);
    Timer::Stop("tree_training");
  }
  else
  {
    tree = new TreeType(datasetInfo, 1, 1);
    data::Load(inputModelFile, "streamingDecisionTree", *tree, true);

    if (!trainingFile.empty())
    {
      arma::mat trainingSet;
      data::Load(trainingFile, trainingSet, datasetInfo, true);
      for (size_t i = 0; i < trainingSet.n_rows; ++i)
        Log::Info << datasetInfo.NumMappings(i) << " mappings in dimension "
            << i << "." << endl;

      arma::Col<size_t> labelsIn;
      data::Load(labelsFile, labelsIn, true, false);
      arma::Row<size_t> labels = labelsIn.t();

      // Now create the decision tree.
      Timer::Start("tree_training");
      if (passes > 1)
      {
        Log::Info << "Taking " << passes << " passes over the dataset." << endl;
        for (size_t i = 0; i < passes; ++i)
          tree->Train(trainingSet, labels, false);
      }
      else
      {
        tree->Train(trainingSet, labels, batchTraining);
      }
      Timer::Stop("tree_training");
    }
  }

  // The tree is trained or loaded.  Now do any testing if we need.
  if (!testFile.empty())
  {
    arma::mat testSet;
    data::Load(testFile, testSet, datasetInfo, true);

    arma::Row<size_t> predictions;
    arma::rowvec probabilities;

    Timer::Start("tree_testing");
    tree->Classify(testSet, predictions, probabilities);
    Timer::Stop("tree_testing");

    if (!predictionsFile.empty())
      data::Save(predictionsFile, predictions);

    if (!probabilitiesFile.empty())
      data::Save(probabilitiesFile, probabilities);
  }

  // Check the accuracy on the training set.
  if (!outputModelFile.empty())
    data::Save(outputModelFile, "streamingDecisionTree", tree, true);

  // Clean up memory.
  delete tree;
}
<|endoftext|>


<commit_before>/**
 * @file hoeffding_tree_main.cpp
 * @author Ryan Curtin
 *
 * A command-line executable that can build a streaming decision tree.
 */
#include <mlpack/core.hpp>
#include <mlpack/methods/hoeffding_trees/hoeffding_tree.hpp>
#include <mlpack/methods/hoeffding_trees/binary_numeric_split.hpp>
#include <mlpack/methods/hoeffding_trees/information_gain.hpp>

using namespace std;
using namespace mlpack;
using namespace mlpack::tree;
using namespace mlpack::data;

PARAM_STRING("training_file", "Training dataset file.", "t", "");
PARAM_STRING("labels_file", "Labels for training dataset.", "l", "");

PARAM_DOUBLE("confidence", "Confidence before splitting (between 0 and 1).",
    "c", 0.95);
PARAM_INT("max_samples", "Maximum number of samples before splitting.", "n",
    5000);
PARAM_INT("min_samples", "Minimum number of samples before splitting.", "I",
    100);

PARAM_STRING("input_model_file", "File to load trained tree from.", "m", "");
PARAM_STRING("output_model_file", "File to save trained tree to.", "M", "");

PARAM_STRING("test_file", "File of testing data.", "T", "");
PARAM_STRING("test_labels_file", "Labels of test data.", "L", "");
PARAM_STRING("predictions_file", "File to output label predictions for test "
    "data into.", "p", "");
PARAM_STRING("probabilities_file", "In addition to predicting labels, provide "
    "prediction probabilities in this file.", "P", "");

PARAM_STRING("numeric_split_strategy", "The splitting strategy to use for "
    "numeric features: 'domingos' or 'binary'.", "N", "binary");
PARAM_FLAG("batch_mode", "If true, samples will be considered in batch instead "
    "of as a stream.  This generally results in better trees but at the cost of"
    " memory usage and runtime.", "b");
PARAM_FLAG("info_gain", "If set, information gain is used instead of Gini "
    "impurity for calculating Hoeffding bounds.", "i");
PARAM_INT("passes", "Number of passes to take over the dataset.", "s", 1);

PARAM_INT("bins", "If the 'domingos' split strategy is used, this specifies "
    "the number of bins for each numeric split.", "B", 10);
PARAM_INT("observations_before_binning", "If the 'domingos' split strategy is "
    "used, this specifies the number of samples observed before binning is "
    "performed.", "o", 100);

// Helper function for once we have chosen a tree type.
template<typename TreeType>
void PerformActions(const typename TreeType::NumericSplit& numericSplit =
    typename TreeType::NumericSplit(0));

int main(int argc, char** argv)
{
  CLI::ParseCommandLine(argc, argv);

  // Check input parameters for validity.
  const string trainingFile = CLI::GetParam<string>("training_file");
  const string labelsFile = CLI::GetParam<string>("labels_file");
  const string inputModelFile = CLI::GetParam<string>("input_model_file");
  const string testFile = CLI::GetParam<string>("test_file");
  const string predictionsFile = CLI::GetParam<string>("predictions_file");
  const string probabilitiesFile = CLI::GetParam<string>("probabilities_file");
  const string numericSplitStrategy =
      CLI::GetParam<string>("numeric_split_strategy");

  if ((!predictionsFile.empty() || !probabilitiesFile.empty()) &&
      testFile.empty())
    Log::Fatal << "--test_file must be specified if --predictions_file or "
        << "--probabilities_file is specified." << endl;

  if (trainingFile.empty() && inputModelFile.empty())
    Log::Fatal << "One of --training_file or --input_model_file must be "
        << "specified!" << endl;

  if (!trainingFile.empty() && labelsFile.empty())
    Log::Fatal << "If --training_file is specified, --labels_file must be "
        << "specified too!" << endl;

  if (trainingFile.empty() && CLI::HasParam("batch_mode"))
    Log::Warn << "--batch_mode (-b) ignored; no training set provided." << endl;

  if (CLI::HasParam("passes") && CLI::HasParam("batch_mode"))
    Log::Warn << "--batch_mode (-b) ignored because --passes was specified."
        << endl;

  if (CLI::HasParam("info_gain"))
  {
    if (numericSplitStrategy == "domingos")
    {
      const size_t bins = (size_t) CLI::GetParam<int>("bins");
      const size_t observationsBeforeBinning = (size_t)
          CLI::GetParam<int>("observations_before_binning");
      HoeffdingDoubleNumericSplit<InformationGain> ns(0, bins,
          observationsBeforeBinning);
      PerformActions<HoeffdingTree<InformationGain, HoeffdingDoubleNumericSplit,
          HoeffdingCategoricalSplit>>(ns);
    }
    else if (numericSplitStrategy == "binary")
    {
      PerformActions<HoeffdingTree<InformationGain, BinaryDoubleNumericSplit,
          HoeffdingCategoricalSplit>>();
    }
    else
    {
      Log::Fatal << "Unrecognized numeric split strategy ("
          << numericSplitStrategy << ")!  Must be 'domingos' or 'binary'."
          << endl;
    }
  }
  else
  {
    if (numericSplitStrategy == "domingos")
    {
      const size_t bins = (size_t) CLI::GetParam<int>("bins");
      const size_t observationsBeforeBinning = (size_t)
          CLI::GetParam<int>("observations_before_binning");
      HoeffdingDoubleNumericSplit<GiniImpurity> ns(0, bins,
          observationsBeforeBinning);
      PerformActions<HoeffdingTree<GiniImpurity, HoeffdingDoubleNumericSplit,
          HoeffdingCategoricalSplit>>(ns);
    }
    else if (numericSplitStrategy == "binary")
    {
      PerformActions<HoeffdingTree<GiniImpurity, BinaryDoubleNumericSplit,
          HoeffdingCategoricalSplit>>();
    }
    else
    {
      Log::Fatal << "Unrecognized numeric split strategy ("
          << numericSplitStrategy << ")!  Must be 'domingos' or 'binary'."
          << endl;
    }
  }
}

template<typename TreeType>
void PerformActions(const typename TreeType::NumericSplit& numericSplit)
{
  // Load necessary parameters.
  const string trainingFile = CLI::GetParam<string>("training_file");
  const string labelsFile = CLI::GetParam<string>("labels_file");
  const double confidence = CLI::GetParam<double>("confidence");
  const size_t maxSamples = (size_t) CLI::GetParam<int>("max_samples");
  const size_t minSamples = (size_t) CLI::GetParam<int>("min_samples");
  const string inputModelFile = CLI::GetParam<string>("input_model_file");
  const string outputModelFile = CLI::GetParam<string>("output_model_file");
  const string testFile = CLI::GetParam<string>("test_file");
  const string predictionsFile = CLI::GetParam<string>("predictions_file");
  const string probabilitiesFile = CLI::GetParam<string>("probabilities_file");
  bool batchTraining = CLI::HasParam("batch_mode");
  const size_t passes = (size_t) CLI::GetParam<int>("passes");
  if (passes > 1)
    batchTraining = false; // We already warned about this earlier.

  TreeType* tree = NULL;
  DatasetInfo datasetInfo;
  if (inputModelFile.empty())
  {
    arma::mat trainingSet;
    data::Load(trainingFile, trainingSet, datasetInfo, true);
    for (size_t i = 0; i < trainingSet.n_rows; ++i)
      Log::Info << datasetInfo.NumMappings(i) << " mappings in dimension "
          << i << "." << endl;

    arma::Col<size_t> labelsIn;
    data::Load(labelsFile, labelsIn, true, false);
    arma::Row<size_t> labels = labelsIn.t();

    // Now create the decision tree.
    Timer::Start("tree_training");
    if (passes > 1)
      Log::Info << "Taking " << passes << " passes over the dataset." << endl;

    tree = new TreeType(trainingSet, datasetInfo, labels, max(labels) + 1,
        batchTraining, confidence, maxSamples, 100, minSamples,
        typename TreeType::CategoricalSplit(0, 0), numericSplit);

    for (size_t i = 1; i < passes; ++i)
      tree->Train(trainingSet, labels, false);
    Timer::Stop("tree_training");
  }
  else
  {
    tree = new TreeType(datasetInfo, 1, 1);
    data::Load(inputModelFile, "streamingDecisionTree", *tree, true);

    if (!trainingFile.empty())
    {
      arma::mat trainingSet;
      data::Load(trainingFile, trainingSet, datasetInfo, true);
      for (size_t i = 0; i < trainingSet.n_rows; ++i)
        Log::Info << datasetInfo.NumMappings(i) << " mappings in dimension "
            << i << "." << endl;

      arma::Col<size_t> labelsIn;
      data::Load(labelsFile, labelsIn, true, false);
      arma::Row<size_t> labels = labelsIn.t();

      // Now create the decision tree.
      Timer::Start("tree_training");
      if (passes > 1)
      {
        Log::Info << "Taking " << passes << " passes over the dataset." << endl;
        for (size_t i = 0; i < passes; ++i)
          tree->Train(trainingSet, labels, false);
      }
      else
      {
        tree->Train(trainingSet, labels, batchTraining);
      }
      Timer::Stop("tree_training");
    }
  }

  if (!trainingFile.empty())
  {
    // Get training error.
    arma::mat trainingSet;
    data::Load(trainingFile, trainingSet, datasetInfo, true);
    arma::Row<size_t> predictions;
    tree->Classify(trainingSet, predictions);

    arma::Col<size_t> labelsIn;
    data::Load(labelsFile, labelsIn, true, false);
    arma::Row<size_t> labels = labelsIn.t();

    size_t correct = 0;
    for (size_t i = 0; i < labels.n_elem; ++i)
      if (labels[i] == predictions[i])
        ++correct;

    Log::Info << correct << " out of " << labels.n_elem << " correct "
        << "on training set (" << double(correct) / double(labels.n_elem) *
        100.0 << ")." << endl;

  }

  // The tree is trained or loaded.  Now do any testing if we need.
  if (!testFile.empty())
  {
    arma::mat testSet;
    data::Load(testFile, testSet, datasetInfo, true);

    arma::Row<size_t> predictions;
    arma::rowvec probabilities;

    Timer::Start("tree_testing");
    tree->Classify(testSet, predictions, probabilities);
    Timer::Stop("tree_testing");

    if (CLI::HasParam("test_labels_file"))
    {
      string testLabelsFile = CLI::GetParam<string>("test_labels_file");
      arma::Col<size_t> testLabelsIn;
      data::Load(testLabelsFile, testLabelsIn, true, false);
      arma::Row<size_t> testLabels = testLabelsIn.t();

      size_t correct = 0;
      for (size_t i = 0; i < testLabels.n_elem; ++i)
      {
        if (predictions[i] == testLabels[i])
          ++correct;
      }
      Log::Info << correct << " out of " << testLabels.n_elem << " correct "
          << "on test set (" << double(correct) / double(testLabels.n_elem) *
          100.0 << ")." << endl;
    }

    if (!predictionsFile.empty())
      data::Save(predictionsFile, predictions);

    if (!probabilitiesFile.empty())
      data::Save(probabilitiesFile, probabilities);
  }

  // Check the accuracy on the training set.
  if (!outputModelFile.empty())
    data::Save(outputModelFile, "streamingDecisionTree", tree, true);

  // Clean up memory.
  delete tree;
}
<commit_msg>Print the number of nodes in the tree.<commit_after>/**
 * @file hoeffding_tree_main.cpp
 * @author Ryan Curtin
 *
 * A command-line executable that can build a streaming decision tree.
 */
#include <mlpack/core.hpp>
#include <mlpack/methods/hoeffding_trees/hoeffding_tree.hpp>
#include <mlpack/methods/hoeffding_trees/binary_numeric_split.hpp>
#include <mlpack/methods/hoeffding_trees/information_gain.hpp>
#include <queue>

using namespace std;
using namespace mlpack;
using namespace mlpack::tree;
using namespace mlpack::data;

PARAM_STRING("training_file", "Training dataset file.", "t", "");
PARAM_STRING("labels_file", "Labels for training dataset.", "l", "");

PARAM_DOUBLE("confidence", "Confidence before splitting (between 0 and 1).",
    "c", 0.95);
PARAM_INT("max_samples", "Maximum number of samples before splitting.", "n",
    5000);
PARAM_INT("min_samples", "Minimum number of samples before splitting.", "I",
    100);

PARAM_STRING("input_model_file", "File to load trained tree from.", "m", "");
PARAM_STRING("output_model_file", "File to save trained tree to.", "M", "");

PARAM_STRING("test_file", "File of testing data.", "T", "");
PARAM_STRING("test_labels_file", "Labels of test data.", "L", "");
PARAM_STRING("predictions_file", "File to output label predictions for test "
    "data into.", "p", "");
PARAM_STRING("probabilities_file", "In addition to predicting labels, provide "
    "prediction probabilities in this file.", "P", "");

PARAM_STRING("numeric_split_strategy", "The splitting strategy to use for "
    "numeric features: 'domingos' or 'binary'.", "N", "binary");
PARAM_FLAG("batch_mode", "If true, samples will be considered in batch instead "
    "of as a stream.  This generally results in better trees but at the cost of"
    " memory usage and runtime.", "b");
PARAM_FLAG("info_gain", "If set, information gain is used instead of Gini "
    "impurity for calculating Hoeffding bounds.", "i");
PARAM_INT("passes", "Number of passes to take over the dataset.", "s", 1);

PARAM_INT("bins", "If the 'domingos' split strategy is used, this specifies "
    "the number of bins for each numeric split.", "B", 10);
PARAM_INT("observations_before_binning", "If the 'domingos' split strategy is "
    "used, this specifies the number of samples observed before binning is "
    "performed.", "o", 100);

// Helper function for once we have chosen a tree type.
template<typename TreeType>
void PerformActions(const typename TreeType::NumericSplit& numericSplit =
    typename TreeType::NumericSplit(0));

int main(int argc, char** argv)
{
  CLI::ParseCommandLine(argc, argv);

  // Check input parameters for validity.
  const string trainingFile = CLI::GetParam<string>("training_file");
  const string labelsFile = CLI::GetParam<string>("labels_file");
  const string inputModelFile = CLI::GetParam<string>("input_model_file");
  const string testFile = CLI::GetParam<string>("test_file");
  const string predictionsFile = CLI::GetParam<string>("predictions_file");
  const string probabilitiesFile = CLI::GetParam<string>("probabilities_file");
  const string numericSplitStrategy =
      CLI::GetParam<string>("numeric_split_strategy");

  if ((!predictionsFile.empty() || !probabilitiesFile.empty()) &&
      testFile.empty())
    Log::Fatal << "--test_file must be specified if --predictions_file or "
        << "--probabilities_file is specified." << endl;

  if (trainingFile.empty() && inputModelFile.empty())
    Log::Fatal << "One of --training_file or --input_model_file must be "
        << "specified!" << endl;

  if (!trainingFile.empty() && labelsFile.empty())
    Log::Fatal << "If --training_file is specified, --labels_file must be "
        << "specified too!" << endl;

  if (trainingFile.empty() && CLI::HasParam("batch_mode"))
    Log::Warn << "--batch_mode (-b) ignored; no training set provided." << endl;

  if (CLI::HasParam("passes") && CLI::HasParam("batch_mode"))
    Log::Warn << "--batch_mode (-b) ignored because --passes was specified."
        << endl;

  if (CLI::HasParam("info_gain"))
  {
    if (numericSplitStrategy == "domingos")
    {
      const size_t bins = (size_t) CLI::GetParam<int>("bins");
      const size_t observationsBeforeBinning = (size_t)
          CLI::GetParam<int>("observations_before_binning");
      HoeffdingDoubleNumericSplit<InformationGain> ns(0, bins,
          observationsBeforeBinning);
      PerformActions<HoeffdingTree<InformationGain, HoeffdingDoubleNumericSplit,
          HoeffdingCategoricalSplit>>(ns);
    }
    else if (numericSplitStrategy == "binary")
    {
      PerformActions<HoeffdingTree<InformationGain, BinaryDoubleNumericSplit,
          HoeffdingCategoricalSplit>>();
    }
    else
    {
      Log::Fatal << "Unrecognized numeric split strategy ("
          << numericSplitStrategy << ")!  Must be 'domingos' or 'binary'."
          << endl;
    }
  }
  else
  {
    if (numericSplitStrategy == "domingos")
    {
      const size_t bins = (size_t) CLI::GetParam<int>("bins");
      const size_t observationsBeforeBinning = (size_t)
          CLI::GetParam<int>("observations_before_binning");
      HoeffdingDoubleNumericSplit<GiniImpurity> ns(0, bins,
          observationsBeforeBinning);
      PerformActions<HoeffdingTree<GiniImpurity, HoeffdingDoubleNumericSplit,
          HoeffdingCategoricalSplit>>(ns);
    }
    else if (numericSplitStrategy == "binary")
    {
      PerformActions<HoeffdingTree<GiniImpurity, BinaryDoubleNumericSplit,
          HoeffdingCategoricalSplit>>();
    }
    else
    {
      Log::Fatal << "Unrecognized numeric split strategy ("
          << numericSplitStrategy << ")!  Must be 'domingos' or 'binary'."
          << endl;
    }
  }
}

template<typename TreeType>
void PerformActions(const typename TreeType::NumericSplit& numericSplit)
{
  // Load necessary parameters.
  const string trainingFile = CLI::GetParam<string>("training_file");
  const string labelsFile = CLI::GetParam<string>("labels_file");
  const double confidence = CLI::GetParam<double>("confidence");
  const size_t maxSamples = (size_t) CLI::GetParam<int>("max_samples");
  const size_t minSamples = (size_t) CLI::GetParam<int>("min_samples");
  const string inputModelFile = CLI::GetParam<string>("input_model_file");
  const string outputModelFile = CLI::GetParam<string>("output_model_file");
  const string testFile = CLI::GetParam<string>("test_file");
  const string predictionsFile = CLI::GetParam<string>("predictions_file");
  const string probabilitiesFile = CLI::GetParam<string>("probabilities_file");
  bool batchTraining = CLI::HasParam("batch_mode");
  const size_t passes = (size_t) CLI::GetParam<int>("passes");
  if (passes > 1)
    batchTraining = false; // We already warned about this earlier.

  TreeType* tree = NULL;
  DatasetInfo datasetInfo;
  if (inputModelFile.empty())
  {
    arma::mat trainingSet;
    data::Load(trainingFile, trainingSet, datasetInfo, true);
    for (size_t i = 0; i < trainingSet.n_rows; ++i)
      Log::Info << datasetInfo.NumMappings(i) << " mappings in dimension "
          << i << "." << endl;

    arma::Col<size_t> labelsIn;
    data::Load(labelsFile, labelsIn, true, false);
    arma::Row<size_t> labels = labelsIn.t();

    // Now create the decision tree.
    Timer::Start("tree_training");
    if (passes > 1)
      Log::Info << "Taking " << passes << " passes over the dataset." << endl;

    tree = new TreeType(trainingSet, datasetInfo, labels, max(labels) + 1,
        batchTraining, confidence, maxSamples, 100, minSamples,
        typename TreeType::CategoricalSplit(0, 0), numericSplit);

    for (size_t i = 1; i < passes; ++i)
      tree->Train(trainingSet, labels, false);
    Timer::Stop("tree_training");
  }
  else
  {
    tree = new TreeType(datasetInfo, 1, 1);
    data::Load(inputModelFile, "streamingDecisionTree", *tree, true);

    if (!trainingFile.empty())
    {
      arma::mat trainingSet;
      data::Load(trainingFile, trainingSet, datasetInfo, true);
      for (size_t i = 0; i < trainingSet.n_rows; ++i)
        Log::Info << datasetInfo.NumMappings(i) << " mappings in dimension "
            << i << "." << endl;

      arma::Col<size_t> labelsIn;
      data::Load(labelsFile, labelsIn, true, false);
      arma::Row<size_t> labels = labelsIn.t();

      // Now create the decision tree.
      Timer::Start("tree_training");
      if (passes > 1)
      {
        Log::Info << "Taking " << passes << " passes over the dataset." << endl;
        for (size_t i = 0; i < passes; ++i)
          tree->Train(trainingSet, labels, false);
      }
      else
      {
        tree->Train(trainingSet, labels, batchTraining);
      }
      Timer::Stop("tree_training");
    }
  }

  if (!trainingFile.empty())
  {
    // Get training error.
    arma::mat trainingSet;
    data::Load(trainingFile, trainingSet, datasetInfo, true);
    arma::Row<size_t> predictions;
    tree->Classify(trainingSet, predictions);

    arma::Col<size_t> labelsIn;
    data::Load(labelsFile, labelsIn, true, false);
    arma::Row<size_t> labels = labelsIn.t();

    size_t correct = 0;
    for (size_t i = 0; i < labels.n_elem; ++i)
      if (labels[i] == predictions[i])
        ++correct;

    Log::Info << correct << " out of " << labels.n_elem << " correct "
        << "on training set (" << double(correct) / double(labels.n_elem) *
        100.0 << ")." << endl;
  }

  // Get the number of nods in the tree.
  std::queue<TreeType*> queue;
  queue.push(tree);
  size_t nodes = 0;
  while (!queue.empty())
  {
    TreeType* node = queue.front();
    queue.pop();
    ++nodes;

    for (size_t i = 0; i < node->NumChildren(); ++i)
      queue.push(&node->Child(i));
  }
  Log::Info << nodes << " nodes in the tree." << endl;

  // The tree is trained or loaded.  Now do any testing if we need.
  if (!testFile.empty())
  {
    arma::mat testSet;
    data::Load(testFile, testSet, datasetInfo, true);

    arma::Row<size_t> predictions;
    arma::rowvec probabilities;

    Timer::Start("tree_testing");
    tree->Classify(testSet, predictions, probabilities);
    Timer::Stop("tree_testing");

    if (CLI::HasParam("test_labels_file"))
    {
      string testLabelsFile = CLI::GetParam<string>("test_labels_file");
      arma::Col<size_t> testLabelsIn;
      data::Load(testLabelsFile, testLabelsIn, true, false);
      arma::Row<size_t> testLabels = testLabelsIn.t();

      size_t correct = 0;
      for (size_t i = 0; i < testLabels.n_elem; ++i)
      {
        if (predictions[i] == testLabels[i])
          ++correct;
      }
      Log::Info << correct << " out of " << testLabels.n_elem << " correct "
          << "on test set (" << double(correct) / double(testLabels.n_elem) *
          100.0 << ")." << endl;
    }

    if (!predictionsFile.empty())
      data::Save(predictionsFile, predictions);

    if (!probabilitiesFile.empty())
      data::Save(probabilitiesFile, probabilities);
  }

  // Check the accuracy on the training set.
  if (!outputModelFile.empty())
    data::Save(outputModelFile, "streamingDecisionTree", tree, true);

  // Clean up memory.
  delete tree;
}
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    OptionList.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 2001 Insight Consortium
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.

 * Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

 * The name of the Insight Consortium, nor the names of any consortium members,
   nor of any contributors, may be used to endorse or promote products derived
   from this software without specific prior written permission.

  * Modified source versions must be plainly marked as such, and must not be
    misrepresented as being the original software.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

=========================================================================*/
#include "OptionList.h"

OptionList::OptionList(int argc, char* argv[])
{
  std::string tag ;
  std::string value ;

  int arg_type = 1 ;
  int prev_arg_type = 0 ;

  int index = 1 ;
  while (index < argc)
    {
      if (argv[index][0] == '-' && argv[index][1] == '-')
        {
          // tag
          tag = argv[index] ;
          tag = tag.erase(0, 2) ; // remove '--'
        }
      else
        {
          // value
          value = argv[index] ;
          m_Map.insert(std::make_pair(tag, value)) ;
        }
      index++ ;
    }
}

int OptionList::GetOption(std::string option_tag, StringVector* values)
{
  values->clear() ;
  typedef OptionMap::const_iterator CI ;
  std::pair<CI, CI> bound = m_Map.equal_range(option_tag) ;
  int count = 0 ;

  for (CI i = bound.first ; i != bound.second ; ++i)
    {
      values->push_back(i->second) ;
      count++ ;
    }
  return count ;
}

int OptionList::DumpOption(std::string option_tag, bool withTag,
                           bool withNewLine)
{
  typedef OptionMap::const_iterator CI ;
  std::pair<CI, CI> bound = m_Map.equal_range(option_tag) ;
  int count = 0 ;

  if (bound.first != bound.second)
    {
      if (withTag)
        std::cout << "--" << option_tag << " " ;

      for (CI i = bound.first ; i != bound.second ; ++i)
        {
          std::cout << i->second << " " ;
          count++ ;
        }

      if (withNewLine)
        std::cout << std::endl ;

      return count++ ;
    }

    return 0 ;
}

int OptionList::GetMultiDoubleOption(std::string tag,
                                     std::vector<double>* args,
                                     bool required)
  throw (RequiredOptionMissing)
{
  args->clear() ;

  StringVector temp_args ;
  int arg_no = this->GetOption(tag, &temp_args) ;

  if (required && arg_no == 0)
    throw RequiredOptionMissing(tag) ;

  if (arg_no == 0)
    return -1 ;

  if (temp_args[0] == "-")
    return -2 ;

  for (int i = 0 ; i < arg_no ; i++)
    {
      args->push_back( atof(temp_args[i].c_str()) ) ;
    }

  return arg_no ;
}

double OptionList::GetDoubleOption(std::string tag, double default_value,
                                   bool required)
  throw (RequiredOptionMissing)
{
  StringVector temp_args ;
  int arg_no = this->GetOption(tag, &temp_args) ;

  if (required && arg_no == 0)
    throw RequiredOptionMissing(tag) ;

  if (arg_no == 0)
    return default_value ;

  return atof(temp_args[0].c_str()) ;
}

bool OptionList::GetBooleanOption(std::string tag, bool default_value, bool required)
  throw (RequiredOptionMissing)
{
  StringVector args ;
  int arg_no = this->GetOption(tag, &args) ;

  if (required && arg_no == 0)
    throw RequiredOptionMissing(tag) ;

  if (arg_no == 0)
    return default_value ;

  if (args[0] == "yes")
    {
      return true ;
    }
  else
    {
      return false ;
    }
}

int OptionList::GetMultiIntOption(std::string tag,
                                  std::vector<int>* args,
                                  bool required)
  throw (RequiredOptionMissing)
{
  args->clear() ;

  StringVector temp_args ;
  int arg_no = this->GetOption(tag, &temp_args) ;

  if (required && arg_no == 0)
    throw RequiredOptionMissing(tag) ;

  if (arg_no == 0)
    return -1 ;

  if (temp_args[0] == "-")
    return -2 ;

  for (int i = 0 ; i < arg_no ; i++)
    {
      args->push_back( atoi(temp_args[i].c_str()) ) ;
    }

  return arg_no ;
}

int OptionList::GetIntOption(std::string tag, int default_value, bool required)
  throw (RequiredOptionMissing)
{
  StringVector args ;
  int arg_no = this->GetOption(tag, &args) ;

  if (required && arg_no == 0)
    throw RequiredOptionMissing(tag) ;

  if (arg_no == 0)
    return default_value ;

  return atoi(args[0].c_str()) ;
}

int OptionList::GetStringOption(std::string tag,
                                std::string* ret,
                                bool required)
  throw (RequiredOptionMissing)
{
  StringVector args ;
  int arg_no = this->GetOption(tag, &args) ;

  if (required && arg_no == 0)
    throw RequiredOptionMissing(tag) ;

  if (arg_no == 0)
    return -1 ;

  *ret = args[0] ;
  return arg_no ;
}

<commit_msg>STYLE: removed unused variables to remove SGI warnings<commit_after>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    OptionList.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 2001 Insight Consortium
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.

 * Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

 * The name of the Insight Consortium, nor the names of any consortium members,
   nor of any contributors, may be used to endorse or promote products derived
   from this software without specific prior written permission.

  * Modified source versions must be plainly marked as such, and must not be
    misrepresented as being the original software.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

=========================================================================*/
#include "OptionList.h"

OptionList::OptionList(int argc, char* argv[])
{
  std::string tag ;
  std::string value ;

  int index = 1 ;
  while (index < argc)
    {
      if (argv[index][0] == '-' && argv[index][1] == '-')
        {
          // tag
          tag = argv[index] ;
          tag = tag.erase(0, 2) ; // remove '--'
        }
      else
        {
          // value
          value = argv[index] ;
          m_Map.insert(std::make_pair(tag, value)) ;
        }
      index++ ;
    }
}

int OptionList::GetOption(std::string option_tag, StringVector* values)
{
  values->clear() ;
  typedef OptionMap::const_iterator CI ;
  std::pair<CI, CI> bound = m_Map.equal_range(option_tag) ;
  int count = 0 ;

  for (CI i = bound.first ; i != bound.second ; ++i)
    {
      values->push_back(i->second) ;
      count++ ;
    }
  return count ;
}

int OptionList::DumpOption(std::string option_tag, bool withTag,
                           bool withNewLine)
{
  typedef OptionMap::const_iterator CI ;
  std::pair<CI, CI> bound = m_Map.equal_range(option_tag) ;
  int count = 0 ;

  if (bound.first != bound.second)
    {
      if (withTag)
        std::cout << "--" << option_tag << " " ;

      for (CI i = bound.first ; i != bound.second ; ++i)
        {
          std::cout << i->second << " " ;
          count++ ;
        }

      if (withNewLine)
        std::cout << std::endl ;

      return count++ ;
    }

    return 0 ;
}

int OptionList::GetMultiDoubleOption(std::string tag,
                                     std::vector<double>* args,
                                     bool required)
  throw (RequiredOptionMissing)
{
  args->clear() ;

  StringVector temp_args ;
  int arg_no = this->GetOption(tag, &temp_args) ;

  if (required && arg_no == 0)
    throw RequiredOptionMissing(tag) ;

  if (arg_no == 0)
    return -1 ;

  if (temp_args[0] == "-")
    return -2 ;

  for (int i = 0 ; i < arg_no ; i++)
    {
      args->push_back( atof(temp_args[i].c_str()) ) ;
    }

  return arg_no ;
}

double OptionList::GetDoubleOption(std::string tag, double default_value,
                                   bool required)
  throw (RequiredOptionMissing)
{
  StringVector temp_args ;
  int arg_no = this->GetOption(tag, &temp_args) ;

  if (required && arg_no == 0)
    throw RequiredOptionMissing(tag) ;

  if (arg_no == 0)
    return default_value ;

  return atof(temp_args[0].c_str()) ;
}

bool OptionList::GetBooleanOption(std::string tag, bool default_value, bool required)
  throw (RequiredOptionMissing)
{
  StringVector args ;
  int arg_no = this->GetOption(tag, &args) ;

  if (required && arg_no == 0)
    throw RequiredOptionMissing(tag) ;

  if (arg_no == 0)
    return default_value ;

  if (args[0] == "yes")
    {
      return true ;
    }
  else
    {
      return false ;
    }
}

int OptionList::GetMultiIntOption(std::string tag,
                                  std::vector<int>* args,
                                  bool required)
  throw (RequiredOptionMissing)
{
  args->clear() ;

  StringVector temp_args ;
  int arg_no = this->GetOption(tag, &temp_args) ;

  if (required && arg_no == 0)
    throw RequiredOptionMissing(tag) ;

  if (arg_no == 0)
    return -1 ;

  if (temp_args[0] == "-")
    return -2 ;

  for (int i = 0 ; i < arg_no ; i++)
    {
      args->push_back( atoi(temp_args[i].c_str()) ) ;
    }

  return arg_no ;
}

int OptionList::GetIntOption(std::string tag, int default_value, bool required)
  throw (RequiredOptionMissing)
{
  StringVector args ;
  int arg_no = this->GetOption(tag, &args) ;

  if (required && arg_no == 0)
    throw RequiredOptionMissing(tag) ;

  if (arg_no == 0)
    return default_value ;

  return atoi(args[0].c_str()) ;
}

int OptionList::GetStringOption(std::string tag,
                                std::string* ret,
                                bool required)
  throw (RequiredOptionMissing)
{
  StringVector args ;
  int arg_no = this->GetOption(tag, &args) ;

  if (required && arg_no == 0)
    throw RequiredOptionMissing(tag) ;

  if (arg_no == 0)
    return -1 ;

  *ret = args[0] ;
  return arg_no ;
}

<|endoftext|>