// Copyright 2015 XLGAMES Inc.
//
// Distributed under the MIT License (See
// accompanying file "LICENSE" or the website
// http://www.opensource.org/licenses/mit-license.php)

#define _SILENCE_CXX17_NEGATORS_DEPRECATION_WARNING

#include "TestDisplays.h"
#include "../../RenderOverlays/Font.h"
#include "../../RenderCore/Format.h"
#include "../../Math/Geometry.h"
#include "../../Math/Vector.h"
#include "../../Math/Noise.h"
#include "../../Math/RectanglePacking.h"
#include "../../Utility/PtrUtils.h"
#include "../../Utility/MemoryUtils.h"
#include "../../Utility/BitUtils.h"
#include <random>

#pragma warning(disable:4714)
#pragma push_macro("new")
#undef new
#include <Eigen/Dense>
#pragma pop_macro("new")

#pragma warning(disable:4127)       // conditional expression is constant

namespace PlatformRig { namespace Overlays
{
    class CollectIntersectionPts
    {
    public:
        std::vector<Float2> _intr;

        void operator()(XLEMath::Int2 s0, XLEMath::Int2 s1, float edgeAlpha)
        {
            _intr.push_back(LinearInterpolate(Float2(s0), Float2(s1), edgeAlpha));
        }

        void operator()(XLEMath::Float2 s0, XLEMath::Float2 s1, float edgeAlpha)
        {
            _intr.push_back(LinearInterpolate(s0, s1, edgeAlpha));
        }
    };

    void    GridIteratorDisplay::Render(IOverlayContext& context, Layout& layout, Interactables&interactables, InterfaceState& interfaceState)
    {
        auto maxSize = layout.GetMaximumSize();
        Rect gridArea(maxSize._topLeft + Coord2(50, 50), maxSize._bottomRight - Coord2(50, 50));

        const unsigned elementDim = 32;
        unsigned segmentsX = gridArea.Width() / elementDim;
        unsigned segmentsY = gridArea.Height() / elementDim;

        auto segsX = std::make_unique<Coord2[]>(segmentsX*2);
        auto segsY = std::make_unique<Coord2[]>(segmentsY*2);
        auto colours = std::make_unique<ColorB[]>(std::max(segmentsX, segmentsY)*2);
        for (unsigned c=0; c<segmentsX; ++c) {
            segsX[c*2+0] = Coord2(gridArea._topLeft[0] + c * elementDim, gridArea._topLeft[1]);
            segsX[c*2+1] = Coord2(gridArea._topLeft[0] + c * elementDim, gridArea._bottomRight[1]);
            colours[c*2+0] = ColorB(0xffafafaf);
            colours[c*2+1] = ColorB(0xffafafaf);
        }
        for (unsigned c=0; c<segmentsY; ++c) {
            segsY[c*2+0] = Coord2(gridArea._topLeft[0], gridArea._topLeft[1] + c * elementDim);
            segsY[c*2+1] = Coord2(gridArea._bottomRight[0], gridArea._topLeft[1] + c * elementDim);
            colours[c*2+0] = ColorB(0xffafafaf);
            colours[c*2+1] = ColorB(0xffafafaf);
        }

        DrawLines(&context, segsX.get(), colours.get(), segmentsX);
        DrawLines(&context, segsY.get(), colours.get(), segmentsY);

        Float2 start = Float2(float(gridArea._bottomRight[0] - gridArea._topLeft[0]), float(gridArea._bottomRight[1] - gridArea._topLeft[1])) / float(elementDim) / 2.f;
        Float2 end = Float2(float(_currentMousePosition[0] - gridArea._topLeft[0]), float(_currentMousePosition[1] - gridArea._topLeft[1])) / float(elementDim);

        // start[0] = XlFloor(start[0]);
        // start[1] = XlFloor(start[1]);
        // end[0] = XlFloor(end[0]);
        // end[1] = XlFloor(end[1]);

        Coord2 testLine[] =
        {
            Coord2(int(start[0]*elementDim), int(start[1]*elementDim)) + gridArea._topLeft,
            Coord2(int(end[0]*elementDim), int(end[1]*elementDim)) + gridArea._topLeft,
        };
        ColorB testLineCol[] = { ColorB(0xffffffff), ColorB(0xffffffff) };
        DrawLines(&context, testLine, testLineCol, 1);

        CollectIntersectionPts intersections;
        // GridEdgeIterator(Int2(start), Int2(end), intersections);
        GridEdgeIterator2(start, end, intersections);

        for (auto i=intersections._intr.cbegin(); i!=intersections._intr.cend(); ++i) {
            Coord2 centre(int((*i)[0] * elementDim) + gridArea._topLeft[0], int((*i)[1] * elementDim) + gridArea._topLeft[1]);
            Rect rect(centre - Coord2(2,2), centre + Coord2(2,2));
            DrawElipse(&context, rect, ColorB(0xffff0000));
        }
    }

    bool    GridIteratorDisplay::ProcessInput(InterfaceState& interfaceState, const InputContext& inputContext, const InputSnapshot& input)
    {
        if (input.IsHeld_LButton()) {
            _currentMousePosition = input._mousePosition;
        }
        return false;
    }

    GridIteratorDisplay::GridIteratorDisplay() : _currentMousePosition(0,0) {}
    GridIteratorDisplay::~GridIteratorDisplay() {}

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    class FieldIntersection
    {
    public:
        Float2 _position, _normal;
        bool _isGood;
        FieldIntersection(Float2 position, Float2 normal) : _position(position), _normal(normal), _isGood(true) {}
        FieldIntersection() : _position(0.f, 0.f), _normal(0.f, 0.f), _isGood(false) {}
    };

    static std::pair<float, float> RayVsCircle(const Float2& rayStart, const Float2& rayDirection, const Float2& sphereCenter, float sphereRadius)
    {
            //  we're going to look for intersections between this ray and the sphere.
            //  there can be maximum of 2 intersections.
            //  The return values are the length along the line to the intersection points.
            //  When no intersection is found (or only one) the unused return values will be negative).
            //  We solve this using algebra, looking for the points where the equations
            //  for the line and the ray agree.

        const float a = Dot(rayDirection, rayStart - sphereCenter);
        const float m = Magnitude(rayStart - sphereCenter);
        const float x = a*a - m*m + sphereRadius*sphereRadius;
        if (x < 0.f) {
            return std::make_pair(-1.f, -1.f);
        }

        const float A = -a;
        const float B = XlSqrt(x);
        return std::make_pair(A+B, A-B);
    }

    static float CalculateDensity(const Float2& pt)
    {
        const float circleRadius = 20.f;
        // const float theta = atan2(pt[1], pt[0]);
        const float r = Magnitude(pt);
        // static float s0 = 5.f;
        // static float s1 = 0.25f;
        // float noiseValue = SimplexNoise(Float2(s0 * theta, s1 * r));
        //
        // static float noiseScale = 10.f;
        // return r - (circleRadius + noiseScale * noiseValue);
        return r - circleRadius;
    }

    static FieldIntersection GetIntersection(const Float2& e0, const Float2& e1)
    {
            //  For the given edge, find the intersection with the equation.
            //  We're just using a sphere, so it should be easy.
            //
            //  We're interested for the smallest positive value that come out of RayVsCircle

        const bool useDensitySample = true;

        if (useDensitySample) {

            float d0 = CalculateDensity(e0);
            float d1 = CalculateDensity(e1);
            if (d0 < 0.f == d1 < 0.f) {
                return FieldIntersection(); // no intersections here
            }

                //  -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

                //      When we get a change in sign, it means there
                //      is an intersection along this edge somewhere.
                //      We can't know exactly where. But we can take
                //      an estimate based on the density values.
                //
                //      It might be a good idea to further improve the
                //      result by taking a few steps to try to get to the
                //      smallest density value. note that a very strange
                //      density function might behave very non-linearly,
                //      and so produce strange results when trying to
                //      find the intersection (particularly if there are
                //      really multiple intersections).

                //  -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

            float x0 = 0.f, x1 = 1.f;
            float x = 1.f, d = FLT_MAX;
            unsigned improvementSteps = 3;
            for (unsigned c=0; ; ++c) {
                float prevD = d; float prevX = x;
                x = LinearInterpolate(x0, x1, -d0 / (d1 - d0));
                d = CalculateDensity(LinearInterpolate(e0, e1, x));

                    // along noisy edges we could end up getting a worse result after a step
                    //  In these cases, just give up at the last reasonable result
                if (XlAbs(d) > XlAbs(prevD)) {
                    x = prevX;
                    break;
                }

                if ((c+1)>=improvementSteps) break;

                    //  We're going to attempt another improvement.
                    //  Divide the search area again, depending on where
                    //  the origin falls
                if ((d < 0.f) != (d1 < 0.f)) {
                    x0 = x;
                    d0 = d;
                } else {
                    x1 = x;
                    d1 = d;
                }
            }

                //  -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

            Float2 bestIntersection = LinearInterpolate(e0, e1, x);

                //  We need to calculate the normal for this point. We can
                //  use finite different method for this. The normal is just
                //  in the same direction as the partial derivatives of the
                //  density function.
            // static float normalCalcDistance = 1.f;  // changing this distance produces some interesting results in very noisy fields. Larger numbers will generally be smoother
            // float dx0 = CalculateDensity(bestIntersection + Float2(-normalCalcDistance, 0.f));
            // float dx1 = CalculateDensity(bestIntersection + Float2( normalCalcDistance, 0.f));
            // float dy0 = CalculateDensity(bestIntersection + Float2(0.f, -normalCalcDistance));
            // float dy1 = CalculateDensity(bestIntersection + Float2(0.f,  normalCalcDistance));
            //     // (actually the shouldn't matter if the normal is pointing positive or negative)
            // Float2 normal = -Normalize(Float2(dx1-dx0, dy1-dy0));
            Float2 normal = -Normalize(bestIntersection);

            return FieldIntersection(bestIntersection, normal);

        } else {
            const float radius = 28.5f;
            Float2 dir = e1-e0;
            const float length = Magnitude(e1-e0);
            dir *= XlRSqrt(length);
            auto intersection = RayVsCircle(e0, dir, Float2(0.f, 0.f), radius);
            if (intersection.first < 0.f) {
                return FieldIntersection();
            }

            float distance = intersection.first;
            if (intersection.second > 0.f && intersection.second < distance) {
                distance = intersection.second;
            }

            if (distance > length) {
                return FieldIntersection();
            }

            Float2 intersectionPt = e0 + dir * distance;
            return FieldIntersection(intersectionPt, Normalize(intersectionPt));
        }
    }

    // static void RotateToUpperTriangle(cml::matrix<float, cml::fixed<5,4>, cml::col_basis>& matrix)
    // {
    //         // Convert this matrix into a upper triangle using the Householder method
    // }

    static void RotateToUpperTriangle(Eigen::Matrix<float,5,4>& A)
    {
        // Eigen::ColPivHouseholderQR<Eigen::Matrix<float,5,4>> qr(A);
        // A = qr.matrixR().triangularView<Eigen::Upper>();
        Eigen::HouseholderQR<Eigen::Matrix<float,5,4>> qr2(A);
        A = qr2.matrixQR().triangularView<Eigen::Upper>();
    }

    Float2 CalculateDualContouringPt(const FieldIntersection intersections[], unsigned intersectionCount, const Float2& massPoint)
    {
            //  Each intersection point defines a plane. We want to find the point within the grid cell that
            //  is closest to lying on all planes. There might not be an exact solution. However, the following
            //  math will find the solution that minimizes the least squares of the distances from the planes.
            //
            //  Also note the use of the "mass point". This is described in the original dual contouring paper.
            //  This can help avoid cases where the solution is outside of the grid cell.
            //      http://www.cs.rice.edu/~jwarren/papers/techreport02408.pdf

            //  The simplest version of this just involves creating a matrix from the planes
            //  defined by the intersection pts, and using SVD decomposition to calculate
            //  the pseudo-inverse (which will give us a solution).
            //  Let's do this using the "eigen" library. That means using the matrix tpyes from
            //  that library.

        static unsigned method = 2;
        if (method == 1) {

                //  Most basic method. We're just going to solve the linear equations
                //  directly. This doesn't involve any more optimisations or accuracy
                //  improvements
            Eigen::MatrixXf A(intersectionCount, 2);
            Eigen::MatrixXf B(intersectionCount, 1);
            for (unsigned c=0; c<intersectionCount; ++c) {
                A(c, 0) = intersections[c]._normal[0];
                A(c, 1) = intersections[c]._normal[1];
                B(c, 0) = Dot(intersections[c]._position, intersections[c]._normal);
            }

                //  Calculate the decomposition.
                //
                //  The paper suggests that we might not have to do all of this. It uses A multiplied
                //  by it's transpose, which reduces some of the SVD math. It doesn't look like
                //  the eigen library supports this simplification, however.
            Eigen::JacobiSVD<Eigen::MatrixXf> svd(A, Eigen::ComputeFullU | Eigen::ComputeFullV);

            Eigen::MatrixXf x(2, 1);
            x = svd.solve(B).eval();

                // that's our basic solution...
            return Float2(x(0, 0), x(1, 0));

        } else if (method == 0) {

                //  This is the QR decomposition method. This transforms the matrices
                //  beforehand into a form that can be more accurate for later math.

            typedef Eigen::Matrix<float,5,4> Float5x4;
            Float5x4 mat = Float5x4::Zero();

            for (unsigned c=0; c<intersectionCount; ++c) {
                mat(4, 0) = intersections[c]._normal[0];
                mat(4, 1) = intersections[c]._normal[1];
                mat(4, 2) = 0.f;
                mat(4, 3) = Dot(intersections[c]._position, intersections[c]._normal);
                RotateToUpperTriangle(mat);
            }

            Eigen::Matrix<float,3,3> Ahat;
            Eigen::Matrix<float,3,1> Bhat;
            for (unsigned c=0; c<3; ++c) {
                Ahat(c,0) = mat(c,0);
                Ahat(c,1) = mat(c,1);
                Ahat(c,2) = mat(c,2);
                Bhat(c,0) = mat(c,3);
            }

            Eigen::JacobiSVD<Eigen::MatrixXf> svd(Ahat, Eigen::ComputeFullU | Eigen::ComputeFullV);

            Eigen::MatrixXf x(2, 1);
            x = svd.solve(Bhat).eval();

            return Float2(x(0, 0), x(1, 0));

        } else if (method == 2) {

                // same as above, but using the mass point

            typedef Eigen::Matrix<float,5,4> Float5x4;
            Float5x4 mat = Float5x4::Zero();

            for (unsigned c=0; c<intersectionCount; ++c) {
                mat(4, 0) = intersections[c]._normal[0];
                mat(4, 1) = intersections[c]._normal[1];
                mat(4, 2) = 0.f;
                mat(4, 3) = Dot(intersections[c]._position, intersections[c]._normal);
                RotateToUpperTriangle(mat);
            }

            Eigen::Matrix<float,3,3> Ahat;
            Eigen::Matrix<float,3,1> Bhat;
            for (unsigned c=0; c<3; ++c) {
                Ahat(c,0) = mat(c,0);
                Ahat(c,1) = mat(c,1);
                Ahat(c,2) = mat(c,2);
                Bhat(c,0) = mat(c,3);
            }

            // const float r = mat(3,3);        (not clear what I should do with "r". It always seem to be 0.f in tests so far)

            Eigen::Matrix<float,3,1> massPointVec;
            massPointVec(0,0) = massPoint[0];
            massPointVec(1,0) = massPoint[1];
            massPointVec(2,0) = 0.f;

            Eigen::MatrixXf x(2, 1);

                //  The original dual contour multiplies through with the transpose of A. This might
                //  reduce the work when calculating the SVD, but the Eigen library doesn't seem to
                //  support this optimisation, however. So I'm not sure if we need to multiply
                //  through with AHatTranspose here.
            static bool useTranspose = true;
            if (useTranspose) {
                auto AhatTranspose = Ahat.transpose();
                Eigen::JacobiSVD<Eigen::MatrixXf> svd(AhatTranspose * Ahat, Eigen::ComputeFullU | Eigen::ComputeFullV);
                x = svd.solve(AhatTranspose * Bhat - AhatTranspose * Ahat * massPointVec).eval();
            } else {
                    //  note that if we know the mass point when we're calculating Ahat, we can probably
                    //  just take into account the mass point then. However, if we're using a marching
                    //  cubes-like algorithm to move through the data field, and so visiting each cube
                    //  element multiple times, we might not be able to calculate the mass point until
                    //  after AHat has been fully built. But we can compensate during the solution, as so ---
                Eigen::JacobiSVD<Eigen::MatrixXf> svd(Ahat, Eigen::ComputeFullU | Eigen::ComputeFullV);
                x = svd.solve(Bhat - Ahat * massPointVec).eval();
            }

            auto result = Float2(x(0, 0) + massPoint[0], x(1, 0) + massPoint[1]);

                //  We can still get some results where the solution is outside of the
                //  grid element we're building. This can happen when there is significant
                //  curvature inside a single grid element. It produces very strange results
                //  so we have to detect these cases, and use some other solution. In these
                //  cases, the mass point is probably the best estimate of what we need.
                //  The only other option would be to use higher order primitives than cubes
                //  (eg. bezier surfaces). But that would require lots of extra work and calculations.

            if (    result[0] < -.5f || result[0] > .5f
                ||  result[1] < -.5f || result[1] > .5f) {
                return massPoint;       // got a poor result from the QEF test -- too much curvature in a small area.
            }

            return result;

        } else if (method == 3) {
                //  When the normal method isn't working, this can give a rough estimate
                //  of what it should look like
            return massPoint;
        }

        return Float2(0.f, 0.f);
    }

    static Float2 MulAcross(const Float2& zero, const Float2& one)
    {
        return Float2(zero[0]*one[0], zero[1]*one[1]);
    }

    void    DualContouringTest::Render(IOverlayContext& context, Layout& layout, Interactables&interactables, InterfaceState& interfaceState)
    {
        int gridSize = 64;
        std::vector<std::pair<Float2, Float2>> lines;
        for (int y=-gridSize/2; y<gridSize; ++y) {
            for (int x=-gridSize/2; x<gridSize; ++x) {

                    //  Here we're going to test one grid element at a time (in 2d)
                    //  Let's look at the 4 edges of this grid element and find
                    //  the signs and intersection points. We also need the positions
                    //  of the intersections and the normals at those coordinates.
                    //
                    //  Let's start with a simple equation where we can calculate those
                    //  things easily

                Float2 p0 = Float2(  float(x),     float(y));
                Float2 p1 = Float2(float(x+1),     float(y));
                Float2 p2 = Float2(  float(x),   float(y+1));
                Float2 p3 = Float2(float(x+1),   float(y+1));

                auto i0 = GetIntersection(p0, p1);
                auto i1 = GetIntersection(p1, p3);
                auto i2 = GetIntersection(p3, p2);
                auto i3 = GetIntersection(p2, p0);

                FieldIntersection intrs[4];
                Float2 massPoint(0.f, 0.f);
                unsigned intersectionCount = 0;
                if (i0._isGood) { intrs[intersectionCount++] = i0; massPoint += i0._position; }
                if (i1._isGood) { intrs[intersectionCount++] = i1; massPoint += i1._position; }
                if (i2._isGood) { intrs[intersectionCount++] = i2; massPoint += i2._position; }
                if (i3._isGood) { intrs[intersectionCount++] = i3; massPoint += i3._position; }
                if (!intersectionCount) { continue; }

                massPoint /= float(intersectionCount);

                //  We offset the whole system to bring it near
                    //  the origin.
                Float2 offset(float(x) + .5f, float(y) + .5f);
                for (unsigned c=0; c<intersectionCount; ++c) {
                    intrs[c]._position -= offset;
                }
                massPoint -= offset;

                    //  Now we have all our intersection. We need to solve a system
                    //  of linear equations to calculate the point that is closest to
                    //  meeting the planes defined.
                auto cellPt = CalculateDualContouringPt(intrs, intersectionCount, massPoint);

                    //  now we must add lines from each of the intersection points to the
                    //  cell pt.
                for (unsigned c=0; c<intersectionCount; ++c) {
                    lines.push_back(std::make_pair(intrs[c]._position + offset, cellPt + offset));
                }
            }
        }

        auto maxSize = layout.GetMaximumSize();
        Rect gridArea(maxSize._topLeft + Coord2(50, 50), maxSize._bottomRight - Coord2(50, 50));

        Float2 o = LinearInterpolate(AsFloat2(gridArea._topLeft), AsFloat2(gridArea._bottomRight), 0.5f);
        Float2 s = Float2(gridArea.Width() / float(gridSize), gridArea.Height() / float(gridSize));

            //////////////////////////////////////////////////////////////
                    //  draw a background grid          //

        {
            const unsigned segmentsX = gridSize+1;
            const unsigned segmentsY = gridSize+1;
            auto segsX = std::make_unique<Coord2[]>(segmentsX*2);
            auto segsY = std::make_unique<Coord2[]>(segmentsY*2);
            auto colours = std::make_unique<ColorB[]>(std::max(segmentsX, segmentsY)*2);
            unsigned c=0;
            for (int x=-gridSize/2; x<=gridSize/2; ++x, ++c) {
                segsX[c*2+0] = AsCoord2(MulAcross(Float2(float(x), float(-gridSize/2)), s) + o);
                segsX[c*2+1] = AsCoord2(MulAcross(Float2(float(x), float( gridSize/2)), s) + o);
                colours[c*2+0] = ColorB(0xff5f5f5f);
                colours[c*2+1] = ColorB(0xff5f5f5f);
            }
            assert(c==segmentsX);
            c=0;
            for (int y=-gridSize/2; y<=gridSize/2; ++y, ++c) {
                segsY[c*2+0] = AsCoord2(MulAcross(Float2(float(-gridSize/2), float(y)), s) + o);
                segsY[c*2+1] = AsCoord2(MulAcross(Float2(float( gridSize/2), float(y)), s) + o);
                colours[c*2+0] = ColorB(0xff5f5f5f);
                colours[c*2+1] = ColorB(0xff5f5f5f);
            }
            assert(c==segmentsY);

            DrawLines(&context, segsX.get(), colours.get(), segmentsX);
            DrawLines(&context, segsY.get(), colours.get(), segmentsY);
        }

            //////////////////////////////////////////////////////////////

        {
            std::vector<Coord2> transformedLines;
            std::vector<ColorB> lineColours;
            transformedLines.reserve(lines.size()*2);
            lineColours.reserve(lines.size()*2);
            for (auto i=lines.cbegin(); i!=lines.cend(); ++i) {
                transformedLines.push_back(AsCoord2(MulAcross(i->first, s) + o));
                transformedLines.push_back(AsCoord2(MulAcross(i->second, s) + o));
                lineColours.push_back(ColorB(0xffffffff));
                lineColours.push_back(ColorB(0xffffffff));
            }

            DrawLines(&context,
                AsPointer(transformedLines.cbegin()),
                AsPointer(lineColours.cbegin()),
                unsigned(transformedLines.size()/2));
        }

    }

    bool    DualContouringTest::ProcessInput(InterfaceState& interfaceState, const InputContext& inputContext, const InputSnapshot& input)
    {
        return false;
    }

    DualContouringTest::DualContouringTest()
    {
    }

    DualContouringTest::~DualContouringTest()
    {}

///////////////////////////////////////////////////////////////////////////////////////////////////

    static UInt2 RectPackerSize(512, 512);

    class RectanglePackerTest::Pimpl
    {
    public:
        RectanglePacker_MaxRects _packer;

        using Rectangle = std::pair<UInt2, UInt2>;
        std::vector<Rectangle> _rects;

        Pimpl() {}

        UInt2 BuildRandomSize()
        {
            static std::mt19937 generator(std::random_device().operator()());
            // const UInt2 minSize( 32,  32);
            // const UInt2 maxSize(128, 128);
            // return UInt2(
            //     std::uniform_int_distribution<>(minSize[0], maxSize[0])(generator),
            //     std::uniform_int_distribution<>(minSize[1], maxSize[1])(generator));
            return UInt2(
                unsigned(std::normal_distribution<>(64, 16)(generator)),
                unsigned(std::normal_distribution<>(64, 16)(generator)));
            // return UInt2(
            //     1<<IntegerLog2(unsigned(std::normal_distribution<>(64, 16)(generator))),
            //     1<<IntegerLog2(unsigned(std::normal_distribution<>(64, 16)(generator))));
        }

        void FillRandomly()
        {
            const unsigned rects = 128;
            _packer = RectanglePacker_MaxRects();
            _packer.Deallocate(std::make_pair(UInt2(0,0), RectPackerSize));
            _rects.clear();

            for (unsigned c=0; c<rects; ++c) {
                auto rect = _packer.Allocate(BuildRandomSize());
                if (rect.second[0] > rect.first[0] && rect.second[1] > rect.first[1])
                    _rects.push_back(rect);
            }
        }

        void FillEfficiently()
        {
            const unsigned rects = 128;
            _packer = RectanglePacker_MaxRects();
            _packer.Deallocate(std::make_pair(UInt2(0,0), RectPackerSize));
            _rects.clear();

            std::vector<UInt2> rectsToAdd; rectsToAdd.reserve(rects);
            for (unsigned c=0; c<rects; ++c)
                rectsToAdd.push_back(BuildRandomSize());

            std::sort(rectsToAdd.begin(), rectsToAdd.end(),
                [](const UInt2& lhs, const UInt2& rhs)
                {
                    return std::max(lhs[0], lhs[1]) > std::max(rhs[0], rhs[1]);
                });

            for (const auto& size:rectsToAdd) {
                auto rect = _packer.Allocate(size);
                if (rect.second[0] > rect.first[0] && rect.second[1] > rect.first[1])
                    _rects.push_back(rect);
            }
        }
    };

    class ButtonFormatting
    {
    public:
        ColorB  _background;
        ColorB  _foreground;
        ButtonFormatting(ColorB background, ColorB foreground) : _background(background), _foreground(foreground) {}
    };

    static void DrawButtonBasic(IOverlayContext* context, const Rect& rect, const char label[], ButtonFormatting formatting)
    {
        DrawRectangle(context, rect, formatting._background);
        DrawRectangleOutline(context, rect, 0.f, formatting._foreground);
        context->DrawText(
            std::make_tuple(Float3(float(rect._topLeft[0]), float(rect._topLeft[1]), 0.f), Float3(float(rect._bottomRight[0]), float(rect._bottomRight[1]), 0.f)),
			GetDefaultFont(), TextStyle{}, formatting._foreground, TextAlignment::Center, label);
    }

    template<typename T> inline const T& FormatButton(InterfaceState& interfaceState, InteractableId id, const T& normalState, const T& mouseOverState, const T& pressedState)
    {
        if (interfaceState.HasMouseOver(id))
            return interfaceState.IsMouseButtonHeld(0)?pressedState:mouseOverState;
        return normalState;
    }

    void RectanglePackerTest::Render(
        IOverlayContext& context, Layout& layout,
        Interactables&interactables, InterfaceState& interfaceState)
    {
        static ButtonFormatting buttonNormalState(ColorB(127, 192, 127, 64), ColorB(164, 192, 164, 255));
        static ButtonFormatting buttonMouseOverState(ColorB(127, 192, 127, 64), ColorB(255, 255, 255, 160));
        static ButtonFormatting buttonPressedState(ColorB(127, 192, 127, 64), ColorB(255, 255, 255, 96));

        Layout toolbar = layout.AllocateFullWidth(32);
        {
            auto buttonRect = toolbar.Allocate(UInt2(256, 32));
            DrawButtonBasic(
                &context, buttonRect,
                "Randomize",
                FormatButton(interfaceState, Hash64("Randomize"), buttonNormalState, buttonMouseOverState, buttonPressedState));
            interactables.Register(Interactables::Widget(buttonRect, Hash64("Randomize")));
        }
        {
            auto buttonRect = toolbar.Allocate(UInt2(256, 32));
            DrawButtonBasic(
                &context, buttonRect,
                "FillEfficiently",
                FormatButton(interfaceState, Hash64("FillEfficiently"), buttonNormalState, buttonMouseOverState, buttonPressedState));
            interactables.Register(Interactables::Widget(buttonRect, Hash64("FillEfficiently")));
        }

        auto remainingSpace = layout.AllocateFullHeightFraction(1.f);

        unsigned colors[] =
        {
            0xffFDFD96, 0xff03C03C, 0xff836953, 0xffB19CD9, 0xffFFB347, 0xffFF6961,
            0xffCB99C9, 0xffFFD1DC, 0xff779ECB, 0xffAEC6CF
        };
        unsigned c=0;

            // draw each rectangle within the remaining space
        for (const auto&r:_pimpl->_rects) {
            UInt2 mins = remainingSpace._topLeft + UInt2(
                 unsigned(r.first[0] * float(remainingSpace.Width()) / float(RectPackerSize[0])),
                 unsigned(r.first[1] * float(remainingSpace.Height()) / float(RectPackerSize[1])));
            UInt2 maxs = remainingSpace._topLeft + UInt2(
                 unsigned(r.second[0] * float(remainingSpace.Width()) / float(RectPackerSize[0])),
                 unsigned(r.second[1] * float(remainingSpace.Height()) / float(RectPackerSize[1])));
            DrawRectangle(&context, Rect(mins, maxs), ColorB(colors[(++c)%dimof(colors)]));
        }
    }

    bool    RectanglePackerTest::ProcessInput(InterfaceState& interfaceState, const InputContext& inputContext, const InputSnapshot& input)
    {
        if (input.IsRelease_LButton() && interfaceState.TopMostId() == Hash64("Randomize")) {
            _pimpl->FillRandomly();
            return true;
        } else if (input.IsRelease_LButton() && interfaceState.TopMostId() == Hash64("FillEfficiently")) {
            _pimpl->FillEfficiently();
            return true;
        }
        return false;
    }

    RectanglePackerTest::RectanglePackerTest()
    {
        _pimpl = std::make_unique<Pimpl>();
        // _pimpl->FillRandomly();
    }

    RectanglePackerTest::~RectanglePackerTest() {}

}}

#include "../../RenderCore/Metal/DeviceContext.h"
#include "../../RenderCore/Metal/Shader.h"
#include "../../RenderCore/Metal/TextureView.h"
#include "../../RenderCore/Metal/InputLayout.h"
#include "../../RenderCore/Metal/ObjectFactory.h"
#include "../../RenderCore/Assets/Services.h"
#include "../../RenderCore/Techniques/CommonResources.h"
#include "../../ConsoleRig/ResourceBox.h"
#include "../../Assets/Assets.h"

namespace PlatformRig { namespace Overlays
{
    using namespace RenderCore;

    class CRTBox
    {
    public:
        class Desc {};

        using SRV = Metal::ShaderResourceView;
        using RTV = Metal::RenderTargetView;

        RTV _bufferRTV;
        SRV _bufferSRV;
        Metal::ViewportDesc _viewport;

        CRTBox(const Desc&);
        ~CRTBox();
    };

    const unsigned width = 64;
    const unsigned height = 64;

    CRTBox::CRTBox(const Desc&)
    {
        auto& factory = Metal::GetObjectFactory();
        auto buffer = Metal::CreateResource(
            factory,
            CreateDesc(
                BindFlag::RenderTarget|BindFlag::ShaderResource, 0, GPUAccess::Read|GPUAccess::Write,
                TextureDesc::Plain2D(64, 64, Format::R8_UNORM), "ConsRasterTest"));
        _bufferRTV = RTV(buffer);
        _bufferSRV = SRV(buffer);
        _viewport = Metal::ViewportDesc(0.f, 0.f, float(width), float(height), 0.f, 1.f);
    }

    CRTBox::~CRTBox() {}

    void    ConservativeRasterTest::Render(
        IOverlayContext& context, Layout& layout,
        Interactables&interactables, InterfaceState& interfaceState)
    {
		assert(0);		// can no longer get the device context from IOverlayContext
#if 0
        auto& box = ConsoleRig::FindCachedBox2<CRTBox>();
        auto metalContext = Metal::DeviceContext::Get(*context.GetDeviceContext());

        //
        //  We're going to test the conversative rasterization geometry shader
        //  to do this, we need to render to a low-res offscreen texture. Then
        //  we blow that up to fill the screen.
        //
        //  Let's do this in a forked command list, so we don't have to save
        //  and restore state.
        //

        auto& commonResources = Techniques::CommonResources();
        Metal::ViewportDesc mainViewport(*metalContext);
        const float scale = XlFloor((mainViewport.Height - 150.f) / box._viewport.Height);
        const Float2 base(5.f, 100.f);
        Float2 triPoints[] =
        {
            Float2(3.f, 3.f),
            Float2(40.f, 58.f),
            Float2(55.f, 5.f)
        };

        if (interfaceState.IsMouseButtonHeld(0)) {
            auto mp = interfaceState.MousePosition();
            triPoints[0] = (mp - base) / scale;
            triPoints[0][0] = XlFloor(triPoints[0][0]*10.f) / 10.f;
            triPoints[0][1] = XlFloor(triPoints[0][1]*10.f) / 10.f;
        }

        if (interfaceState.IsMouseButtonHeld(1)) {
            auto mp = interfaceState.MousePosition();
            triPoints[1] = (mp - base) / scale;
            triPoints[1][0] = XlFloor(triPoints[1][0]*10.f) / 10.f;
            triPoints[1][1] = XlFloor(triPoints[1][1]*10.f) / 10.f;
        }

        {
            auto forkedContext = metalContext->Fork();

            forkedContext->BeginCommandList();
            forkedContext->Bind(commonResources._blendOpaque);
            forkedContext->Bind(commonResources._dssDisable);
            forkedContext->Bind(commonResources._defaultRasterizer);
            forkedContext->Bind(Topology::TriangleList);

            forkedContext->Bind(mainViewport);

            TRY
            {
                forkedContext->Clear(box._bufferRTV, {0.f, 0.f, 0.f, 0.f});
                forkedContext->Bind(MakeResourceList(box._bufferRTV), nullptr);
                forkedContext->Bind(box._viewport);

                auto& shader = ::Assets::GetAssetDep<Metal::ShaderProgram>(
                    BASIC2D_VERTEX_HLSL ":P2C:vs_*",
                    SCENE_ENGINE_RES "/ShadowGen/ConsRaster.hlsl:gs_conservativeRasterization:gs_*",
                    BASIC_PIXEL_HLSL ":P:ps_*",
                    "");

                class Vertex
                {
                public:
                    Float2 p; unsigned col;
                }
                vertices[3] =
                {
                    { triPoints[0], 0xffff0000 },
                    { triPoints[1], 0xff0000ff },
                    { triPoints[2], 0xff00ff00 }
                };
                Metal::VertexBuffer vb(vertices, sizeof(vertices));
                forkedContext->Bind(MakeResourceList(vb), sizeof(Vertex), 0);
                Metal::BoundInputLayout inputLayout(GlobalInputLayouts::P2C, shader);
                forkedContext->Bind(inputLayout);

                Float4 recipViewport(1.f / box._viewport.Width, 1.f / box._viewport.Height, 0.f, 0.f);
                SharedPkt constants[] = { MakeSharedPkt(recipViewport) };

                Metal::BoundUniforms uniforms(shader);
                uniforms.BindConstantBuffers(1, {"ReciprocalViewportDimensionsCB"});
                uniforms.Apply(
                    *forkedContext, context.GetGlobalUniformsStream(),
                    Metal::UniformsStream(constants));

                forkedContext->Bind(shader);
                forkedContext->Draw(3);

            } CATCH (...) {
            } CATCH_END

            // note --  We actually want to execute the forked command list and some point
            //          earlier than main context is executable -- and insert some synchronization
            //          tests to ensure that it is ready by the time we get to this point.
            //      we can keep a list of "tributary" command lists in the main device context...?
            metalContext->ExecuteCommandList(
                *forkedContext->ResolveCommandList(),
                true);
        }

        // now render this texture onto the main render target
        TRY
        {
            auto& shader = ::Assets::GetAssetDep<Metal::ShaderProgram>(
                BASIC2D_VERTEX_HLSL ":P2CT:vs_*",
                BASIC_PIXEL_HLSL ":PCT:ps_*",
                "");

            class Vertex
            {
            public:
                Float2 p; unsigned col; Float2 tc;
            }
            vertices[6] =
            {
                { Float2(5.f, 100.f), ~0u, Float2(0.f, 0.f) },
                { Float2(5.f, 100.f + scale * box._viewport.Height), ~0u, Float2(0.f, 1.f) },
                { Float2(5.f + scale * box._viewport.Width, 100.f), ~0u, Float2(1.f, 0.f) },
                { Float2(5.f + scale * box._viewport.Width, 100.f), ~0u, Float2(1.f, 0.f) },
                { Float2(5.f, 100.f + scale * box._viewport.Height), ~0u, Float2(0.f, 1.f) },
                { Float2(5.f + scale * box._viewport.Width, 100.f + scale * box._viewport.Height), ~0u, Float2(1.f, 1.f) }
            };
            Metal::VertexBuffer vb(vertices, sizeof(vertices));
            metalContext->Bind(MakeResourceList(vb), sizeof(Vertex), 0);
            Metal::BoundInputLayout inputLayout(GlobalInputLayouts::P2CT, shader);
            metalContext->Bind(inputLayout);

            Float4 recipViewport(1.f / mainViewport.Width, 1.f / mainViewport.Height, 0.f, 0.f);
            SharedPkt constants[] = { MakeSharedPkt(recipViewport) };
            const Metal::ShaderResourceView* srvs[] = {&box._bufferSRV};

            Metal::BoundUniforms uniforms(shader);
            uniforms.BindShaderResources(1, {"DiffuseTexture"});
            uniforms.BindConstantBuffers(1, {"ReciprocalViewportDimensionsCB"});
            uniforms.Apply(
                *metalContext, context.GetGlobalUniformsStream(),
                Metal::UniformsStream(constants, srvs));

            metalContext->BindPS(MakeResourceList(commonResources._pointClampSampler));
            metalContext->Bind(shader);
            metalContext->Draw(6);

        } CATCH (...) {
        } CATCH_END

                // draw the triangle in wireframe
        context.DrawLine(
            ProjectionMode::P2D,
            Expand(Float2(base + scale * triPoints[0]), 0.f), ColorB(0xffffffff),
            Expand(Float2(base + scale * triPoints[1]), 0.f), ColorB(0xffffffff),
            1.f);

        context.DrawLine(
            ProjectionMode::P2D,
            Expand(Float2(base + scale * triPoints[1]), 0.f), ColorB(0xffffffff),
            Expand(Float2(base + scale * triPoints[2]), 0.f), ColorB(0xffffffff),
            1.f);

        context.DrawLine(
            ProjectionMode::P2D,
            Expand(Float2(base + scale * triPoints[2]), 0.f), ColorB(0xffffffff),
            Expand(Float2(base + scale * triPoints[0]), 0.f), ColorB(0xffffffff),
            1.f);

        metalContext->BindPS(MakeResourceList(commonResources._linearClampSampler));
        metalContext->Bind(commonResources._blendStraightAlpha);
#endif
    }

    bool    ConservativeRasterTest::ProcessInput(InterfaceState& interfaceState, const InputContext& inputContext, const InputSnapshot& input)
    {
        return false;
    }

    ConservativeRasterTest::ConservativeRasterTest() {}
    ConservativeRasterTest::~ConservativeRasterTest() {}

}}


/**
 * @file rmva.hpp
 * @author Marcus Edel
 *
 * Definition of the RecurrentNeuralAttention class, which implements the
 * Recurrent Model for Visual Attention.
 */
#ifndef __MLPACK_METHODS_RMVA_RMVA_HPP
#define __MLPACK_METHODS_RMVA_RMVA_HPP

#include <mlpack/core.hpp>

#include <mlpack/methods/ann/network_util.hpp>
#include <mlpack/methods/ann/layer/layer_traits.hpp>
#include <mlpack/methods/ann/init_rules/random_init.hpp>
#include <mlpack/methods/ann/performance_functions/cee_function.hpp>
#include <mlpack/core/optimizers/rmsprop/rmsprop.hpp>
#include <mlpack/methods/ann/layer/negative_log_likelihood_layer.hpp>
#include <mlpack/methods/ann/layer/vr_class_reward_layer.hpp>

#include <boost/ptr_container/ptr_vector.hpp>

namespace mlpack {
namespace ann /** Artificial Neural Network. */ {

/**
 * This class implements the Recurrent Model for Visual Attention, using a
 * variety of possible layer implementations.
 *
 * For more information, see the following paper.
 *
 * @code
 * @article{MnihHGK14,
 *   title={Recurrent Models of Visual Attention},
 *   author={Volodymyr Mnih, Nicolas Heess, Alex Graves, Koray Kavukcuoglu},
 *   journal={CoRR},
 *   volume={abs/1406.6247},
 *   year={2014}
 * }
 * @endcode
 *
 * @tparam LocatorType Type of locator network.
 * @tparam LocationSensorType Type of location sensor network.
 * @tparam GlimpseSensorType Type of glimpse sensor network.
 * @tparam GlimpseType Type of glimpse network.
 * @tparam StartType Type of start network.
 * @tparam FeedbackType Type of feedback network.
 * @tparam TransferType Type of transfer network.
 * @tparam ClassifierType Type of classifier network.
 * @tparam RewardPredictorType Type of reward predictor network.
 * @tparam InitializationRuleType Rule used to initialize the weight matrix.
 * @tparam MatType Matrix type (arma::mat or arma::sp_mat).
 */
template<
  typename LocatorType,
  typename LocationSensorType,
  typename GlimpseSensorType,
  typename GlimpseType,
  typename StartType,
  typename FeedbackType,
  typename TransferType,
  typename ClassifierType,
  typename RewardPredictorType,
  typename InitializationRuleType = RandomInitialization,
  typename MatType = arma::mat
>
class RecurrentNeuralAttention
{
 public:
  //! Convenience typedef for the internal model construction.
  using NetworkType = RecurrentNeuralAttention<
      LocatorType,
      LocationSensorType,
      GlimpseSensorType,
      GlimpseType,
      StartType,
      FeedbackType,
      TransferType,
      ClassifierType,
      RewardPredictorType,
      InitializationRuleType,
      MatType>;

  /**
   * Construct the RecurrentNeuralAttention object, which will construct the
   * recurrent model for visual attentionh using the specified networks.
   *
   * @param locator The locator network.
   * @param locationSensor The location sensor network.
   * @param glimpseSensor The glimpse sensor network.
   * @param glimpse The glimpse network.
   * @param start The start network.
   * @param feedback The feedback network.
   * @param transfer The transfer network.
   * @param classifier The classifier network.
   * @param rewardPredictor The reward predictor network.
   * @param nStep Number of steps for the back-propagate through time.
   * @param initializeRule Rule used to initialize the weight matrix.
   */
  template<typename TypeLocator,
           typename TypeLocationSensor,
           typename TypeGlimpseSensor,
           typename TypeGlimpse,
           typename TypeStart,
           typename TypeFeedback,
           typename TypeTransfer,
           typename TypeClassifier,
           typename TypeRewardPredictor>
  RecurrentNeuralAttention(TypeLocator&& locator,
                           TypeLocationSensor&& locationSensor,
                           TypeGlimpseSensor&& glimpseSensor,
                           TypeGlimpse&& glimpse,
                           TypeStart&& start,
                           TypeFeedback&& feedback,
                           TypeTransfer&& transfer,
                           TypeClassifier&& classifier,
                           TypeRewardPredictor&& rewardPredictor,
                           const size_t nStep,
                           InitializationRuleType initializeRule =
                              InitializationRuleType());
  /**
   * Train the network on the given input data using the given optimizer.
   *
   * This will use the existing model parameters as a starting point for the
   * optimization. If this is not what you want, then you should access the
   * parameters vector directly with Parameters() and modify it as desired.
   *
   * @tparam OptimizerType Type of optimizer to use to train the model.
   * @param predictors Input training variables.
   * @param responses Outputs results from input training variables.
   * @param optimizer Instantiated optimizer used to train the model.
   */
  template<
      template<typename> class OptimizerType = mlpack::optimization::RMSprop
  >
  void Train(const arma::mat& predictors,
             const arma::mat& responses,
             OptimizerType<NetworkType>& optimizer);

  /**
   * Predict the responses to a given set of predictors. The responses will
   * reflect the output of the given output layer as returned by the
   * OutputClass() function.
   *
   * @param predictors Input predictors.
   * @param responses Matrix to put output predictions of responses into.
   */
  void Predict(arma::mat& predictors, arma::mat& responses);

  /**
   * Evaluate the network with the given parameters. This function is usually
   * called by the optimizer to train the model.
   *
   * @param parameters Matrix model parameters.
   * @param i Index of point to use for objective function evaluation.
   * @param deterministic Whether or not to train or test the model. Note some
   * layer act differently in training or testing mode.
   */
  double Evaluate(const arma::mat& parameters,
                  const size_t i,
                  const bool deterministic = true);

  /**
   * Evaluate the gradient of the network with the given parameters, and with
   * respect to only one point in the dataset. This is useful for
   * optimizers such as SGD, which require a separable objective function.
   *
   * @param parameters Matrix of the model parameters to be optimized.
   * @param i Index of points to use for objective function gradient evaluation.
   * @param gradient Matrix to output gradient into.
   */
  void Gradient(const arma::mat& parameters,
                const size_t i,
                arma::mat& gradient);

  //! Return the number of separable functions (the number of predictor points).
  size_t NumFunctions() const { return numFunctions; }

  //! Return the initial point for the optimization.
  const arma::mat& Parameters() const { return parameter; }
  //! Modify the initial point for the optimization.
  arma::mat& Parameters() { return parameter; }

  //! Return the number of steps to back-propagate through time.
  const size_t& Rho() const { return nStep; }
  //! Modify the number of steps to back-propagate through time.
  size_t& Rho() { return nStep; }

  //! Return the current location.
  const arma::mat& Location();

  //! Serialize the model.
  template<typename Archive>
  void Serialize(Archive& ar, const unsigned int /* version */);

 private:
  /*
   * Predict the response of the given input matrix.
   */
  template <typename InputType, typename OutputType>
  void SinglePredict(const InputType& input, OutputType& output)
  {
    // Get the locator input size.
    if (!inputSize)
    {
      inputSize = NetworkInputSize(locator);
    }

    // Reset networks.
    ResetParameter(locator);
    ResetParameter(locationSensor);
    ResetParameter(glimpseSensor);
    ResetParameter(glimpse);
    ResetParameter(feedback);
    ResetParameter(transfer);
    ResetParameter(classifier);
    ResetParameter(rewardPredictor);
    ResetParameter(start);

    // Sample an initial starting actions by forwarding zeros through the
    // locator.
    locatorInput.push_back(new arma::cube(arma::zeros<arma::cube>(inputSize, 1,
        input.n_slices)));

    // Forward pass throught the recurrent network.
    for (step = 0; step < nStep; step++)
    {
      // Locator forward pass.
      Forward(locatorInput.back(), locator);

      // Location sensor forward pass.
      Forward(std::get<std::tuple_size<LocatorType>::value - 1>(
          locator).OutputParameter(), locationSensor);

      // Set the location parameter for all layer that implement a Location
      // function e.g. GlimpseLayer.
      ResetLocation(std::get<std::tuple_size<LocatorType>::value - 1>(
          locator).OutputParameter(), glimpseSensor);

      // Glimpse sensor forward pass.
      Forward(input, glimpseSensor);

      // Concat the parameter activation from the location sensor and
      // glimpse sensor.
      arma::mat concatLayerOutput = arma::join_cols(
          std::get<std::tuple_size<LocationSensorType>::value - 1>(
          locationSensor).OutputParameter(),
          std::get<std::tuple_size<GlimpseSensorType>::value - 1>(
          glimpseSensor).OutputParameter());

      // Glimpse forward pass.
      Forward(concatLayerOutput, glimpse);

      if (step == 0)
      {
        // Start forward pass.
        Forward(std::get<std::tuple_size<GlimpseType>::value - 1>(
            glimpse).OutputParameter(), start);

        // Transfer forward pass.
        Forward(std::get<std::tuple_size<StartType>::value - 1>(
            start).OutputParameter(), transfer);
      }
      else
      {
        // Feedback forward pass.
        Forward(std::get<std::tuple_size<TransferType>::value - 1>(
            transfer).OutputParameter(), feedback);

        arma::mat feedbackLayerOutput =
          std::get<std::tuple_size<GlimpseType>::value - 1>(
          glimpse).OutputParameter() +
          std::get<std::tuple_size<FeedbackType>::value - 1>(
          feedback).OutputParameter();

        // Transfer forward pass.
        Forward(feedbackLayerOutput, transfer);
      }

      // Update the input for the next run
      locatorInput.push_back(new arma::cube(
          std::get<std::tuple_size<TransferType>::value - 1>(
          transfer).OutputParameter().memptr(), locatorInput.back().n_rows,
          locatorInput.back().n_cols, locatorInput.back().n_slices));
    }

    // Classifier forward pass.
    Forward(locatorInput.back().slice(0), classifier);

    output = std::get<std::tuple_size<ClassifierType>::value - 1>(
        classifier).OutputParameter();
  }

  /**
   * Update the layer reward for all layer that implement the Rewards function.
   */
  template<size_t I = 0, typename... Tp>
  typename std::enable_if<I < sizeof...(Tp), void>::type
  ResetReward(const double reward, std::tuple<Tp...>& network)
  {
    SetReward(reward, std::get<I>(network));
    ResetReward<I + 1, Tp...>(reward, network);
  }

  template<size_t I = 0, typename... Tp>
  typename std::enable_if<I == sizeof...(Tp), void>::type
  ResetReward(const double /* reward */, std::tuple<Tp...>& /* network */)
  {
  }

  template<typename T>
  typename std::enable_if<
      HasRewardCheck<T, double&(T::*)()>::value, void>::type
  SetReward(const double reward, T& layer)
  {
    layer.Reward() = reward;
  }

  template<typename T>
  typename std::enable_if<
      !HasRewardCheck<T, double&(T::*)()>::value, void>::type
  SetReward(const double /* reward */, T& /* layer */)
  {
    /* Nothing to do here */
  }

  /**
   * Reset the network by clearing the delta and by setting the layer status.
   */
  template<size_t I = 0, typename... Tp>
  typename std::enable_if<I == sizeof...(Tp), void>::type
  ResetParameter(std::tuple<Tp...>& /* network */) { /* Nothing to do here */ }

  template<size_t I = 0, typename... Tp>
  typename std::enable_if<I < sizeof...(Tp), void>::type
  ResetParameter(std::tuple<Tp...>& network)
  {
    ResetDeterministic(std::get<I>(network));
    std::get<I>(network).Delta().zeros();

    ResetParameter<I + 1, Tp...>(network);
  }

  template<typename T>
  typename std::enable_if<
      HasDeterministicCheck<T, bool&(T::*)(void)>::value, void>::type
  ResetDeterministic(T& layer)
  {
    layer.Deterministic() = deterministic;
  }

  template<typename T>
  typename std::enable_if<
      !HasDeterministicCheck<T, bool&(T::*)(void)>::value, void>::type
  ResetDeterministic(T& /* layer */) { /* Nothing to do here */ }

  /**
   * Reset the location by updating the location for all layer that implement
   * the Location function.
   */
  template<size_t I = 0, typename... Tp>
  typename std::enable_if<I == sizeof...(Tp), void>::type
  ResetLocation(const arma::mat& /* location */,
                std::tuple<Tp...>& /* network */)
  {
    // Nothing to do here.
  }

  template<size_t I = 0, typename... Tp>
  typename std::enable_if<I < sizeof...(Tp), void>::type
  ResetLocation(const arma::mat& location, std::tuple<Tp...>& network)
  {
    SetLocation(std::get<I>(network), location);
    ResetLocation<I + 1, Tp...>(location, network);
  }

  template<typename T>
  typename std::enable_if<
      HasLocationCheck<T, void(T::*)(const arma::mat&)>::value, void>::type
  SetLocation(T& layer, const arma::mat& location)
  {
    layer.Location(location);
  }

  template<typename T>
  typename std::enable_if<
      !HasLocationCheck<T, void(T::*)(const arma::mat&)>::value, void>::type
  SetLocation(T& /* layer */, const arma::mat& /* location */)
  {
    // Nothing to do here.
  }

  /**
   * Save the network layer activations.
   */
  template<size_t I = 0, typename... Tp>
  typename std::enable_if<I < sizeof...(Tp), void>::type
  SaveActivations(boost::ptr_vector<MatType>& activations,
                  std::tuple<Tp...>& network,
                  size_t& activationCounter)
  {
    Save(I, activations, std::get<I>(network),
        std::get<I>(network).InputParameter());

    activationCounter++;
    SaveActivations<I + 1, Tp...>(activations, network, activationCounter);
  }

  template<size_t I = 0, typename... Tp>
  typename std::enable_if<I == sizeof...(Tp), void>::type
  SaveActivations(boost::ptr_vector<MatType>& /* activations */,
                  std::tuple<Tp...>& /* network */,
                  size_t& /* activationCounter */)
  {
    // Nothing to do here.
  }

  /**
   * Distinguish between recurrent layer and non-recurrent layer when storing
   * the activations.
   */
  template<typename T, typename P>
  typename std::enable_if<
      HasRecurrentParameterCheck<T, P&(T::*)()>::value, void>::type
  Save(const size_t /* layerNumber */,
       boost::ptr_vector<MatType>& activations,
       T& layer,
       P& /* unused */)
  {
    activations.push_back(new MatType(layer.RecurrentParameter()));
  }

  template<typename T, typename P>
  typename std::enable_if<
      !HasRecurrentParameterCheck<T, P&(T::*)()>::value, void>::type
  Save(const size_t /* layerNumber */,
       boost::ptr_vector<MatType>& activations,
       T& layer,
       P& /* unused */)
  {
    activations.push_back(new MatType(layer.OutputParameter()));
  }

  template<size_t I = 0, typename DataTypeA, typename DataTypeB, typename... Tp>
  typename std::enable_if<I < sizeof...(Tp), void>::type
  SaveActivations(boost::ptr_vector<DataTypeA>& activationsA,
                  boost::ptr_vector<DataTypeB>& activationsB,
                  size_t& dataTypeACounter,
                  size_t& dataTypeBCounter,
                  std::tuple<Tp...>& network)
  {
    Save(activationsA, activationsB, dataTypeACounter, dataTypeBCounter,
        std::get<I>(network), std::get<I>(network).OutputParameter());

    SaveActivations<I + 1, DataTypeA, DataTypeB, Tp...>(
        activationsA, activationsB, dataTypeACounter, dataTypeBCounter,
        network);
  }

  template<size_t I = 0, typename DataTypeA, typename DataTypeB, typename... Tp>
  typename std::enable_if<I == sizeof...(Tp), void>::type
  SaveActivations(boost::ptr_vector<DataTypeA>& /* activationsA */,
                  boost::ptr_vector<DataTypeB>& /* activationsB */,
                  size_t& /* dataTypeACounter */,
                  size_t& /* dataTypeBCounter */,
                  std::tuple<Tp...>& /* network */)
  {
    // Nothing to do here.
  }

  template<typename T, typename DataTypeA, typename DataTypeB>
  void Save(boost::ptr_vector<DataTypeA>& activationsA,
        boost::ptr_vector<DataTypeB>& /* activationsB */,
       size_t& dataTypeACounter,
       size_t& /* dataTypeBCounter */,
       T& layer,
       DataTypeA& /* unused */)
  {
    activationsA.push_back(new DataTypeA(layer.OutputParameter()));
    dataTypeACounter++;
  }

  template<typename T, typename DataTypeA, typename DataTypeB>
  void Save(boost::ptr_vector<DataTypeA>& /* activationsA */,
            boost::ptr_vector<DataTypeB>& activationsB,
            size_t& /* dataTypeACounter */,
            size_t& dataTypeBCounter,
            T& layer,
            DataTypeB& /* unused */)
  {
    activationsB.push_back(new DataTypeB(layer.OutputParameter()));
    dataTypeBCounter++;
  }

  /**
   * Load the network layer activations.
   */
  template<size_t I = 0, typename DataType, typename... Tp>
  typename std::enable_if<I == sizeof...(Tp), void>::type
  LoadActivations(DataType& input,
                  boost::ptr_vector<MatType>& /* activations */,
                  size_t& /* activationCounter */,
                  std::tuple<Tp...>& network)
  {
    std::get<0>(network).InputParameter() = input;
    LinkParameter(network);
  }

  template<size_t I = 0, typename DataType, typename... Tp>
  typename std::enable_if<I < sizeof...(Tp), void>::type
  LoadActivations(DataType& input,
                  boost::ptr_vector<MatType>& activations,
                  size_t& activationCounter,
                  std::tuple<Tp...>& network)
  {
    Load(--activationCounter, activations,
        std::get<sizeof...(Tp) - I - 1>(network),
        std::get<I>(network).InputParameter());

    LoadActivations<I + 1, DataType, Tp...>(input, activations,
        activationCounter, network);
  }

  /**
   * Distinguish between recurrent layer and non-recurrent layer when storing
   * the activations.
   */
  template<typename T, typename P>
  typename std::enable_if<
      HasRecurrentParameterCheck<T, P&(T::*)()>::value, void>::type
  Load(const size_t layerNumber,
       boost::ptr_vector<MatType>& activations,
       T& layer,
       P& /* output */)
  {
    layer.RecurrentParameter() = activations[layerNumber];
  }

  template<typename T, typename P>
  typename std::enable_if<
      !HasRecurrentParameterCheck<T, P&(T::*)()>::value, void>::type
  Load(const size_t layerNumber,
       boost::ptr_vector<MatType>& activations,
       T& layer,
       P& /* output */)
  {
    layer.OutputParameter() = activations[layerNumber];
  }

  template<size_t I = 0,
           typename DataType,
           typename DataTypeA,
           typename DataTypeB,
           typename... Tp>
  typename std::enable_if<I < sizeof...(Tp), void>::type
  LoadActivations(DataType& input,
                  boost::ptr_vector<DataTypeA>& activationsA,
                  boost::ptr_vector<DataTypeB>& activationsB,
                  size_t& dataTypeACounter,
                  size_t& dataTypeBCounter,
                  std::tuple<Tp...>& network)
  {
    Load(activationsA,
         activationsB,
         dataTypeACounter,
         dataTypeBCounter,
         std::get<sizeof...(Tp) - I - 1>(network),
         std::get<sizeof...(Tp) - I - 1>(network).OutputParameter());

    LoadActivations<I + 1, DataType, DataTypeA, DataTypeB, Tp...>(
        input, activationsA, activationsB, dataTypeACounter, dataTypeBCounter,
        network);
  }

  template<size_t I = 0,
           typename DataType,
           typename DataTypeA,
           typename DataTypeB,
           typename... Tp>
  typename std::enable_if<I == sizeof...(Tp), void>::type
  LoadActivations(DataType& input,
                  boost::ptr_vector<DataTypeA>& /* activationsA */,
                  boost::ptr_vector<DataTypeB>& /* activationsB */,
                  size_t& /* dataTypeACounter */,
                  size_t& /* dataTypeBCounter */,
                  std::tuple<Tp...>& network)
  {
    std::get<0>(network).InputParameter() = input;
    LinkParameter(network);
  }

  template<typename T, typename DataTypeA, typename DataTypeB>
  void Load(boost::ptr_vector<DataTypeA>& activationsA,
            boost::ptr_vector<DataTypeB>& /* activationsB */,
            size_t& dataTypeACounter,
            size_t& /* dataTypeBCounter */,
            T& layer,
            DataTypeA& /* output */)
  {
    layer.OutputParameter() = activationsA[--dataTypeACounter];
  }

  template<typename T, typename DataTypeA, typename DataTypeB>
  void Load(boost::ptr_vector<DataTypeA>& /* activationsA */,
            boost::ptr_vector<DataTypeB>& activationsB,
            size_t& /* dataTypeACounter */,
            size_t& dataTypeBCounter,
            T& layer,
            DataTypeB& /* output */)
  {
    layer.OutputParameter() = activationsB[--dataTypeBCounter];
  }

  /**
   * Run a single iteration of the feed forward algorithm, using the given
   * input and target vector, store the calculated error into the error
   * vector.
   */
  template<size_t I = 0, typename DataType, typename... Tp>
  void Forward(const DataType& input, std::tuple<Tp...>& t)
  {
    std::get<I>(t).InputParameter() = input;
    std::get<I>(t).Forward(std::get<I>(t).InputParameter(),
        std::get<I>(t).OutputParameter());

    ForwardTail<I + 1, Tp...>(t);
  }

  template<size_t I = 1, typename... Tp>
  typename std::enable_if<I == sizeof...(Tp), void>::type
  ForwardTail(std::tuple<Tp...>& network)
  {
    LinkParameter(network);
  }

  template<size_t I = 1, typename... Tp>
  typename std::enable_if<I < sizeof...(Tp), void>::type
  ForwardTail(std::tuple<Tp...>& t)
  {
    std::get<I>(t).Forward(std::get<I - 1>(t).OutputParameter(),
        std::get<I>(t).OutputParameter());

    ForwardTail<I + 1, Tp...>(t);
  }

  /**
   * Run a single iteration of the backward algorithm, using the given
   * input and target vector, store the calculated error into the error
   * vector.
   */
  template<size_t I = 1, typename DataType, typename... Tp>
  typename std::enable_if<sizeof...(Tp) == 1, void>::type
  Backward(const DataType& error, std::tuple<Tp ...>& t)
  {
    std::get<sizeof...(Tp) - I>(t).Backward(
      std::get<sizeof...(Tp) - I>(t).OutputParameter(), error,
      std::get<sizeof...(Tp) - I>(t).Delta());
  }

  template<size_t I = 1, typename DataType, typename... Tp>
  typename std::enable_if<I < sizeof...(Tp), void>::type
  Backward(const DataType& error, std::tuple<Tp ...>& t)
  {
    std::get<sizeof...(Tp) - I>(t).Backward(
        std::get<sizeof...(Tp) - I>(t).OutputParameter(), error,
        std::get<sizeof...(Tp) - I>(t).Delta());

    BackwardTail<I + 1, DataType, Tp...>(error, t);
  }

  template<size_t I = 1, typename DataType, typename... Tp>
  typename std::enable_if<I == (sizeof...(Tp)), void>::type
  BackwardTail(const DataType& /* error */, std::tuple<Tp...>& t)
  {
    std::get<sizeof...(Tp) - I>(t).Backward(
        std::get<sizeof...(Tp) - I>(t).OutputParameter(),
        std::get<sizeof...(Tp) - I + 1>(t).Delta(),
        std::get<sizeof...(Tp) - I>(t).Delta());
  }

  template<size_t I = 1, typename DataType, typename... Tp>
  typename std::enable_if<I < (sizeof...(Tp)), void>::type
  BackwardTail(const DataType& error, std::tuple<Tp...>& t)
  {
    std::get<sizeof...(Tp) - I>(t).Backward(
        std::get<sizeof...(Tp) - I>(t).OutputParameter(),
        std::get<sizeof...(Tp) - I + 1>(t).Delta(),
        std::get<sizeof...(Tp) - I>(t).Delta());

    BackwardTail<I + 1, DataType, Tp...>(error, t);
  }

  /**
   * Link the calculated activation with the correct layer.
   */
  template<size_t I = 1, typename... Tp>
  typename std::enable_if<I == sizeof...(Tp), void>::type
  LinkParameter(std::tuple<Tp ...>& /* network */) { /* Nothing to do here */ }

  template<size_t I = 1, typename... Tp>
  typename std::enable_if<I < sizeof...(Tp), void>::type
  LinkParameter(std::tuple<Tp...>& network)
  {
    if (!LayerTraits<typename std::remove_reference<
        decltype(std::get<I>(network))>::type>::IsBiasLayer)
    {
      std::get<I>(network).InputParameter() = std::get<I - 1>(
          network).OutputParameter();
    }

    LinkParameter<I + 1, Tp...>(network);
  }

  /**
   * Iterate through all layer modules and update the the gradient using the
   * layer defined optimizer.
   */
  template<typename InputType, typename ErrorType, typename... Tp>
  void UpdateGradients(const InputType& input,
                       const ErrorType& error,
                       std::tuple<Tp...>& network)
  {
     Update(std::get<0>(network),
           input,
           std::get<1>(network).Delta(),
           std::get<1>(network).OutputParameter());

     UpdateGradients<1, ErrorType, Tp...>(error, network);
  }

  template<size_t I = 0, typename ErrorType, typename... Tp>
  typename std::enable_if<I < (sizeof...(Tp) - 1), void>::type
  UpdateGradients(const ErrorType& error, std::tuple<Tp...>& network)
  {
    Update(std::get<I>(network),
           std::get<I>(network).InputParameter(),
           std::get<I + 1>(network).Delta(),
           std::get<I>(network).OutputParameter());

    UpdateGradients<I + 1, ErrorType, Tp...>(error, network);
  }

  template<size_t I = 0, typename ErrorType, typename... Tp>
  typename std::enable_if<I == (sizeof...(Tp) - 1), void>::type
  UpdateGradients(const ErrorType& error, std::tuple<Tp...>& network)
  {
    Update(std::get<I>(network),
       std::get<I>(network).InputParameter(),
       error,
       std::get<I>(network).OutputParameter());
  }

  template<typename LayerType,
           typename InputType,
           typename ErrorType,
           typename GradientType>
  typename std::enable_if<
      HasGradientCheck<LayerType,
          void(LayerType::*)(const InputType&,
                             const ErrorType&,
                             GradientType&)>::value, void>::type
  Update(LayerType& layer,
         const InputType& input,
         const ErrorType& error,
         GradientType& /* gradient */)
  {
    layer.Gradient(input, error, layer.Gradient());
  }

  template<typename LayerType,
           typename InputType,
           typename ErrorType,
           typename GradientType>
  typename std::enable_if<
      !HasGradientCheck<LayerType,
          void(LayerType::*)(const InputType&,
                             const ErrorType&,
                             GradientType&)>::value, void>::type
  Update(LayerType& /* layer */,
         const InputType& /* input */,
         const ErrorType& /* error */,
         GradientType& /* gradient */)
  {
    // Nothing to do here
  }

  //! The locator network.
  LocatorType locator;

  //! The location sensor network.
  LocationSensorType locationSensor;

  //! The glimpse sensor network.
  GlimpseSensorType glimpseSensor;

  //! The glimpse network.
  GlimpseType glimpse;

  //! The start network.
  StartType start;

  //! The feedback network.
  FeedbackType feedback;

  //! The transfer network.
  TransferType transfer;

  //! The classifier network.
  ClassifierType classifier;

  //! The reward predictor network.
  RewardPredictorType rewardPredictor;

  //! The number of steps for the back-propagate through time.
  size_t nStep;

  //! Locally stored network input size.
  size_t inputSize;

  //! The current evaluation mode (training or testing).
  bool deterministic;

  //! The index of the current step.
  size_t step;

  //! The activation storage we are using to perform the feed backward pass for
  //! the glimpse network.
  boost::ptr_vector<arma::mat> glimpseActivations;

  //! The activation storage we are using to perform the feed backward pass for
  //! the locator network.
  boost::ptr_vector<arma::mat> locatorActivations;

  //! The activation storage we are using to perform the feed backward pass for
  //! the feedback network.
  boost::ptr_vector<arma::mat> feedbackActivations;

  //! The activation storage we are using to save the feedback network input.
  boost::ptr_vector<arma::mat> feedbackActivationsInput;

  //! The activation storage we are using to perform the feed backward pass for
  //! the transfer network.
  boost::ptr_vector<arma::mat> transferActivations;

  //! The activation storage we are using to perform the feed backward pass for
  //! the location sensor network.
  boost::ptr_vector<arma::mat> locationSensorActivations;

  //! The activation storage we are using to perform the feed backward pass for
  //! the glimpse sensor network.
  boost::ptr_vector<arma::mat> glimpseSensorMatActivations;
  boost::ptr_vector<arma::cube> glimpseSensorCubeActivations;

  //! The activation storage we are using to perform the feed backward pass for
  //! the locator input.
  boost::ptr_vector<arma::cube> locatorInput;

  //! The storage we are using to save the location.
  boost::ptr_vector<arma::mat> location;

  //! The current number of activations in the glimpse sensor network.
  size_t glimpseSensorMatCounter;
  size_t glimpseSensorCubeCounter;

  //! The current number of activations in the glimpse network.
  size_t glimpseActivationsCounter;

  //! The current number of activations in the glimpse start network.
  size_t startActivationsCounter;

  //! The current number of activations in the feedback network.
  size_t feedbackActivationsCounter;

  //! The current number of activations in the transfer network.
  size_t transferActivationsCounter;

  //! The current number of activations in the locator network.
  size_t locatorActivationsCounter;

  //! The current number of activations in the location sensor network.
  size_t locationSensorActivationsCounter;

  //! The current number of activations in the glimpse sensor network.
  size_t glimpseSensorMatActivationsCounter;
  size_t glimpseSensorCubeActivationsCounter;

  //! The current number of location for the location storage.
  size_t locationCounter;

  //! Matrix of (trained) parameters.
  arma::mat parameter;

  //! The matrix of data points (predictors).
  arma::mat predictors;

  //! The matrix of responses to the input data points.
  arma::mat responses;

  //! The number of separable functions (the number of predictor points).
  size_t numFunctions;

  //! Storage the merge the reward input.
  arma::field<arma::mat> rewardInput;

  //! The current input.
  arma::cube input;

  //! The current target.
  arma::mat target;

  //! Locally stored performance functions.
  NegativeLogLikelihoodLayer<> negativeLogLikelihoodFunction;
  VRClassRewardLayer<> vRClassRewardFunction;

  //! Locally stored size of the locator network.
  size_t locatorSize;

  //! Locally stored size of the location sensor network.
  size_t locationSensorSize;

  //! Locally stored size of the glimpse sensor network.
  size_t glimpseSensorSize;

  //! Locally stored size of the glimpse network.
  size_t glimpseSize;

  //! Locally stored size of the start network.
  size_t startSize;

  //! Locally stored size of the feedback network.
  size_t feedbackSize;

  //! Locally stored size of the transfer network.
  size_t transferSize;

  //! Locally stored size of the classifier network.
  size_t classifierSize;

  //! Locally stored size of the reward predictor network.
  size_t rewardPredictorSize;

  //! Locally stored recurrent gradient.
  arma::mat recurrentGradient;

  //! Locally stored action error.
  arma::mat actionError;

  //! Locally stored current location.
  arma::mat evaluationLocation;
}; // class RecurrentNeuralAttention

} // namespace ann
} // namespace mlpack

// Include implementation.
#include "rmva_impl.hpp"

#endif


#include <Functions/FunctionFactory.h>
#include <Functions/FunctionBinaryArithmetic.h>
#include <Functions/GCDLCMImpl.h>

#include <boost/integer/common_factor.hpp>

namespace DB
{

namespace
{

struct NameGCD { static constexpr auto name = "gcd"; };

template <typename A, typename B>
struct GCDImpl : public GCDLCMImpl<A, B, GCDImpl<A, B>, NameGCD>
{
    using ResultType = typename GCDLCMImpl<A, B, GCDImpl, NameGCD>::ResultType;

    static ResultType applyImpl(A a, B b)
    {
        using Int = typename NumberTraits::ToInteger<ResultType>::Type;
        return boost::integer::gcd(Int(a), Int(b)); // NOLINT(clang-analyzer-core.UndefinedBinaryOperatorResult)
    }
};

using FunctionGCD = BinaryArithmeticOverloadResolver<GCDImpl, NameGCD, false, false>;

}

void registerFunctionGCD(FunctionFactory & factory)
{
    factory.registerFunction<FunctionGCD>();
}

}


#ifndef STAN_MATH_REV_MAT_FUN_TRACE_GEN_QUAD_FORM_HPP
#define STAN_MATH_REV_MAT_FUN_TRACE_GEN_QUAD_FORM_HPP

#include <boost/utility/enable_if.hpp>
#include <boost/type_traits.hpp>
#include <stan/math/prim/mat/fun/Eigen.hpp>
#include <stan/math/prim/mat/fun/typedefs.hpp>
#include <stan/math/rev/core.hpp>
#include <stan/math/rev/scal/fun/value_of.hpp>
#include <stan/math/prim/mat/fun/value_of.hpp>
#include <stan/math/rev/mat/fun/typedefs.hpp>
#include <stan/math/prim/mat/fun/trace_gen_quad_form.hpp>
#include <stan/math/prim/mat/err/check_multiplicable.hpp>
#include <stan/math/prim/mat/err/check_square.hpp>

namespace stan {
  namespace math {
    namespace {
      template <typename TD, int RD, int CD,
                typename TA, int RA, int CA,
                typename TB, int RB, int CB>
      class trace_gen_quad_form_vari_alloc : public chainable_alloc {
      public:
        trace_gen_quad_form_vari_alloc(const Eigen::Matrix<TD, RD, CD>& D,
                                       const Eigen::Matrix<TA, RA, CA>& A,
                                       const Eigen::Matrix<TB, RB, CB>& B)
          : D_(D), A_(A), B_(B)
        { }

        double compute() {
          return trace_gen_quad_form(value_of(D_),
                                     value_of(A_),
                                     value_of(B_));
        }

        Eigen::Matrix<TD, RD, CD>  D_;
        Eigen::Matrix<TA, RA, CA>  A_;
        Eigen::Matrix<TB, RB, CB>  B_;
      };

      template <typename TD, int RD, int CD,
                typename TA, int RA, int CA,
                typename TB, int RB, int CB>
      class trace_gen_quad_form_vari : public vari {
      protected:
        static inline void
        computeAdjoints(double adj,
                        const Eigen::Matrix<double, RD, CD>& D,
                        const Eigen::Matrix<double, RA, CA>& A,
                        const Eigen::Matrix<double, RB, CB>& B,
                        Eigen::Matrix<var, RD, CD> *varD,
                        Eigen::Matrix<var, RA, CA> *varA,
                        Eigen::Matrix<var, RB, CB> *varB) {
          Eigen::Matrix<double, CA, CB> AtB;
          Eigen::Matrix<double, RA, CB> BD;
          if (varB || varA)
            BD.noalias() = B*D;
          if (varB || varD)
            AtB.noalias() = A.transpose()*B;

          if (varB) {
            Eigen::Matrix<double, RB, CB> adjB(adj*(A*BD + AtB*D.transpose()));
            for (int j = 0; j < B.cols(); j++)
              for (int i = 0; i < B.rows(); i++)
                (*varB)(i, j).vi_->adj_ += adjB(i, j);
          }
          if (varA) {
            Eigen::Matrix<double, RA, CA> adjA(adj*(B*BD.transpose()));
            for (int j = 0; j < A.cols(); j++)
              for (int i = 0; i < A.rows(); i++)
                (*varA)(i, j).vi_->adj_ += adjA(i, j);
          }
          if (varD) {
            Eigen::Matrix<double, RD, CD> adjD(adj*(B.transpose()*AtB));
            for (int j = 0; j < D.cols(); j++)
              for (int i = 0; i < D.rows(); i++)
                (*varD)(i, j).vi_->adj_ += adjD(i, j);
          }
        }

      public:
        explicit
        trace_gen_quad_form_vari(trace_gen_quad_form_vari_alloc
                                 <TD, RD, CD, TA, RA, CA, TB, RB, CB> *impl)
          : vari(impl->compute()), impl_(impl) { }

        virtual void chain() {
          computeAdjoints(adj_,
                          value_of(impl_->D_),
                          value_of(impl_->A_),
                          value_of(impl_->B_),
                          reinterpret_cast<Eigen::Matrix<var, RD, CD> *>
                          (boost::is_same<TD, var>::value?(&impl_->D_):NULL),
                          reinterpret_cast<Eigen::Matrix<var, RA, CA> *>
                          (boost::is_same<TA, var>::value?(&impl_->A_):NULL),
                          reinterpret_cast<Eigen::Matrix<var, RB, CB> *>
                          (boost::is_same<TB, var>::value?(&impl_->B_):NULL));
        }

        trace_gen_quad_form_vari_alloc<TD, RD, CD, TA, RA, CA, TB, RB, CB>
        *impl_;
      };
    }

    template <typename TD, int RD, int CD,
              typename TA, int RA, int CA,
              typename TB, int RB, int CB>
    inline typename
    boost::enable_if_c< boost::is_same<TD, var>::value ||
    boost::is_same<TA, var>::value ||
    boost::is_same<TB, var>::value,
                        var >::type
      trace_gen_quad_form(const Eigen::Matrix<TD, RD, CD>& D,
                          const Eigen::Matrix<TA, RA, CA>& A,
                          const Eigen::Matrix<TB, RB, CB>& B) {
      check_square("trace_gen_quad_form", "A", A);
      check_square("trace_gen_quad_form", "D", D);
      check_multiplicable("trace_gen_quad_form",
                          "A", A,
                          "B", B);
      check_multiplicable("trace_gen_quad_form",
                          "B", B,
                          "D", D);

      trace_gen_quad_form_vari_alloc<TD, RD, CD, TA, RA, CA, TB, RB, CB>
        *baseVari
        = new trace_gen_quad_form_vari_alloc<TD, RD, CD, TA, RA, CA, TB, RB, CB>
        (D, A, B);

      return var(new trace_gen_quad_form_vari
                 <TD, RD, CD, TA, RA, CA, TB, RB, CB>(baseVari));
    }

  }
}
#endif


#include <algorithm>
#include <opencv2/opencv.hpp>
#include <Eigen/Dense>
#include "nv_core.h"
#include "nv_ml.h"
#include "nv_ip.h"
#include "nv_num.h"
#include "nv_face_detect.h"
#include "nv_face_feature.h"
#include "nv_face_detect_internal.h"
#ifdef _OPENMP
#include <omp.h>
#endif

#define NV_FACE_DETECT_MAX_CANDIDATES 8192

int
nv_face_detect(nv_face_position_t *face_pos,
			   int maxface,
			   const nv_matrix_t *gray_integral,
			   const nv_matrix_t *edge_integral,
			   const CvRect *image_size,
			   const nv_mlp_t *dir_mlp,
			   const nv_mlp_t *detector_mlp,
			   const nv_mlp_t **bagging_mlp, int bagging_mlps,
			   const nv_mlp_t *parts_mlp,
			   float step,
			   float scale_factor,
			   float min_window_size,
			   float threshold
			   )
{
	nv_candidate candidates[NV_FACE_DETECT_MAX_CANDIDATES] = {}; // max
	const float stride = step / 32.F;
	float scale = min_window_size / 32.0F;
	int ncandidate = 0;
	int nface;
#ifdef _OPENMP
	int threads = omp_get_num_procs();
#else
	int threads = 1;
#endif
	while (std::min(image_size->width, image_size->height) / scale > min_window_size) {
		float window = (32.0F * scale);
		int ye = cvRound((image_size->height - window) / (stride * window));
		int xe = cvRound((image_size->width - window) / (stride * window));

#ifdef _OPENMP
#pragma omp parallel for num_threads(threads) schedule(dynamic, 1)
#endif
		for (int i = 0; i < ye * xe; ++i) {
#ifdef _OPENMP
			int thread_idx = omp_get_thread_num();
#else
			int thread_idx = 0;
#endif
			int yi = i / xe;
			int xi = i % xe;
			float y = yi * (image_size->height - window) / ye;
			float x = xi * (image_size->width - window) / xe;
			cv::Rect roi(cvRound(x), cvRound(y), cvRound(x + window) - cvRound(x), cvRound(y + window) - cvRound(y));
			Eigen::Matrix<float, NV_FACE_HAARLIKE_DIM, 1> haar;

			// エッジで枝刈り
			float area = NV_MAT3D_V(edge_integral, roi.y + roi.height, roi.x + roi.width, 0) + NV_MAT3D_V(edge_integral, roi.y, roi.x, 0)
				- NV_MAT3D_V(edge_integral, roi.y + roi.height, roi.x, 0) - NV_MAT3D_V(edge_integral, roi.y, roi.x + roi.width, 0);
			if (area > window*6266.88F - 104448.F || area <= 52224.F || area <= (window - 64)*2611.2F) {
				continue;
			}

			// 特徴量抽出
			nv_face_haarlike(NV_NORMALIZE_MAX, haar, gray_integral, roi);

			// 顔方向判定
			int label = nv_mlp_predict_label(dir_mlp, haar);
			if (!(label == 0 )) {
				continue; // 0 = -30°〜30° 以外だったらはじく
			}

			// 顔判別1
			double z;
			double z1 = nv_mlp_predict_d(detector_mlp, haar);
			if (z1 > 0.1) {
				if (bagging_mlps == 0) {
					z = z1;
				} else {
					// 顔判別2
					z = nv_mlp_bagging_predict_d(bagging_mlp, bagging_mlps, haar);
				}
				if (z > threshold) {
					// 顔
#ifdef _OPENMP
#pragma omp critical
#endif
					if (NV_FACE_DETECT_MAX_CANDIDATES > ncandidate) {
						candidates[ncandidate].rect = roi;
						candidates[ncandidate].z = z;
						candidates[ncandidate].flag = 1;
						candidates[ncandidate].parts = nullptr;
						++ncandidate;
					}
				}
			}

		}
		scale *= scale_factor;
	}

	// 重複領域の除去
	qsort(candidates, ncandidate, sizeof(nv_candidate), nv_candidate_cmp);
	for (int i = ncandidate-1; i >= 0; --i) {
		if (candidates[i].flag == 0) {
			continue;
		}
		for (int j = i - 1; j >= 0; --j) {
			if (candidates[j].flag == 0) {
				continue;
			}

			float intersect = (candidates[i].rect & candidates[j].rect).area() / static_cast<float>(candidates[j].rect.area());
			if (intersect > 0.1F) {
				if (candidates[i].z == candidates[j].z) {
					if (candidates[i].rect.width > candidates[j].rect.width) {
						candidates[i].flag = 0;
						break;
					}
						candidates[j].flag = 0;

				} else {
					if (candidates[i].z <= candidates[j].z) {
						candidates[i].flag = 0;
						break;
					}
						candidates[j].flag = 0;

				}
			}
		}
	}

	// 部品推定
#ifdef _OPENMP
#pragma omp parallel for num_threads(threads) schedule(dynamic, 1)
#endif
	for (int i = 0; i < std::min(ncandidate, maxface); ++i) {
		if (candidates[i].flag != 0) {
#ifdef _OPENMP
			int thread_idx = omp_get_thread_num();
#else
			int thread_idx = 0;
#endif
			Eigen::Matrix<float, NV_FACE_HAARLIKE_DIM, 1> haar;
			nv_face_haarlike(NV_NORMALIZE_NORM, haar, gray_integral, candidates[i].rect);
			candidates[i].parts = nv_matrix_alloc(parts_mlp->output, 1);
			nv_mlp_regression(parts_mlp, haar, candidates[i].parts);
		}
	}

	// 結果作成
	nface = 0;
	for (int i = 0; i < ncandidate && i < maxface; ++i) {
		if (candidates[i].flag != 0) {
			float d = candidates[i].rect.width;

			face_pos[nface].likelihood = static_cast<float>(candidates[i].z);
			face_pos[nface].face = cvRect(candidates[i].rect);
			face_pos[nface].right_eye.x = cvRound(candidates[i].rect.x + d * (NV_MAT_V(candidates[i].parts, 0, 0) - (NV_MAT_V(candidates[i].parts, 0, 2))));
			face_pos[nface].right_eye.y = cvRound(candidates[i].rect.y + d * (NV_MAT_V(candidates[i].parts, 0, 1) - (NV_MAT_V(candidates[i].parts, 0, 3))));
			face_pos[nface].right_eye.width = cvRound(d * NV_MAT_V(candidates[i].parts, 0, 2) * 2.0F);
			face_pos[nface].right_eye.height = cvRound(d * NV_MAT_V(candidates[i].parts, 0, 3) * 2.0F);
			face_pos[nface].left_eye.x = cvRound(candidates[i].rect.x + d * (NV_MAT_V(candidates[i].parts, 0, 4) - (NV_MAT_V(candidates[i].parts, 0, 6))));
			face_pos[nface].left_eye.y = cvRound(candidates[i].rect.y + d * (NV_MAT_V(candidates[i].parts, 0, 5) - (NV_MAT_V(candidates[i].parts, 0, 7))));
			face_pos[nface].left_eye.width = cvRound(d * NV_MAT_V(candidates[i].parts, 0, 6) * 2.0F);
			face_pos[nface].left_eye.height = cvRound(d * NV_MAT_V(candidates[i].parts, 0, 7) * 2.0F);
			face_pos[nface].nose.x = cvRound(candidates[i].rect.x + d * (NV_MAT_V(candidates[i].parts, 0, 8) - 1.0F * (1.0F / 32.0F)));
			face_pos[nface].nose.y = cvRound(candidates[i].rect.y + d * (NV_MAT_V(candidates[i].parts, 0, 9) - 1.0F * (1.0F / 32.0F)));
			face_pos[nface].nose.width = cvRound(d / 16.F);
			face_pos[nface].nose.height = cvRound(d / 16.F);
			face_pos[nface].mouth.x = cvRound(candidates[i].rect.x + d * (NV_MAT_V(candidates[i].parts, 0, 10) - (NV_MAT_V(candidates[i].parts, 0, 12))));
			face_pos[nface].mouth.y = cvRound(candidates[i].rect.y + d * (NV_MAT_V(candidates[i].parts, 0, 11) - (NV_MAT_V(candidates[i].parts, 0, 13))));
			face_pos[nface].mouth.width = cvRound(d * NV_MAT_V(candidates[i].parts, 0, 12) * 2.0F);
			face_pos[nface].mouth.height = cvRound(d * NV_MAT_V(candidates[i].parts, 0, 13) * 2.0F);
			face_pos[nface].chin.x = cvRound(candidates[i].rect.x + d * (NV_MAT_V(candidates[i].parts, 0, 14) - 1.0F * (1.0F / 32.0F)));
			face_pos[nface].chin.y = cvRound(candidates[i].rect.y + d * (NV_MAT_V(candidates[i].parts, 0, 15) - 1.0F * (1.0F / 32.0F)));
			face_pos[nface].chin.width = cvRound(d / 16.F);
			face_pos[nface].chin.height = cvRound(d / 16.F);
			++nface;
		}
		if (candidates[i].parts != nullptr) {
			nv_matrix_free(&candidates[i].parts);
		}
	}

	return nface;
}


#include "stdafx.h"
#include "qmath.h"
#include "config.h"

// each test module could contain no more then one 'main' file with init function defined
// alternatively you could define init function yourself
#include <boost/test/unit_test.hpp>

// These are sample tests that show the different features of the framework

using namespace math;

namespace {

BOOST_AUTO_TEST_CASE(angle)
{
    anglef a(3 * anglef::_2pi);

	auto b = math::normalized(a);

   // BOOST_CHECK(equals(b, 0.0f));

}

}


#include <iostream>

#include <Eigen/Dense>
#include <gtest/gtest.h>

#include "dart/dynamics/Skeleton.hpp"
#include "dart/dynamics/FreeJoint.hpp"
#include "dart/dynamics/RevoluteJoint.hpp"

#include "TestHelpers.hpp"
#include "GradientTestUtils.hpp"

using namespace dart;
using namespace dart::dynamics;

#define ALL_TESTS

#ifdef ALL_TESTS
TEST(JOINT_JACOBIANS, REVOLUTE_JOINT)
{
  std::shared_ptr<World> world = World::create();
  SkeletonPtr box = Skeleton::create("box");
  std::pair<RevoluteJoint*, BodyNode*> pair
      = box->createJointAndBodyNodePair<RevoluteJoint>(nullptr);
  RevoluteJoint* boxJoint = pair.first;
  boxJoint->setAxis(Eigen::Vector3s::Random());

  Eigen::Isometry3s fromParent = Eigen::Isometry3s::Identity();
  fromParent.translation() = Eigen::Vector3s::UnitX();
  boxJoint->setTransformFromParentBodyNode(fromParent);

  Eigen::Isometry3s fromChild = Eigen::Isometry3s::Identity();
  fromChild.translation() = Eigen::Vector3s::UnitX() * -3;
  fromChild = fromChild.rotate(Eigen::AngleAxis<s_t>(M_PI_2, Eigen::Vector3s::UnitX()));
  boxJoint->setTransformFromChildBodyNode(fromChild);
  world->addSkeleton(box);

  EXPECT_TRUE(verifyJointVelocityJacobians(world));
  EXPECT_TRUE(verifyJointPositionJacobians(world));
}
#endif

#ifdef ALL_TESTS
TEST(JOINT_JACOBIANS, FREE_JOINT)
{
  std::shared_ptr<World> world = World::create();
  SkeletonPtr box = Skeleton::create("box");
  std::pair<FreeJoint*, BodyNode*> pair
      = box->createJointAndBodyNodePair<FreeJoint>(nullptr);
  FreeJoint* boxJoint = pair.first;

  Eigen::Isometry3s fromParent = Eigen::Isometry3s::Identity();
  // fromParent.translation() = Eigen::Vector3s::UnitX();
  boxJoint->setTransformFromParentBodyNode(fromParent);

  Eigen::Isometry3s fromChild = Eigen::Isometry3s::Identity();
  // fromChild.translation() = Eigen::Vector3s::UnitX() * -3;
  // fromChild = fromChild.rotate(Eigen::AngleAxis<s_t>(M_PI_2, Eigen::Vector3s::UnitX()));
  boxJoint->setTransformFromChildBodyNode(fromChild);
  world->addSkeleton(box);

  // box->setPositions(Eigen::Vector6s::Random());

  EXPECT_TRUE(verifyJointVelocityJacobians(world));
  EXPECT_TRUE(verifyJointPositionJacobians(world));
}
#endif


// Copyright (c) by respective owners including Yahoo!, Microsoft, and
// individual contributors. All rights reserved. Released under a BSD (revised)
// license as described in the file LICENSE.

#include <boost/test/unit_test.hpp>
#include <boost/test/test_tools.hpp>

#include "test_common.h"
#include "simulator.h"
#include "constant.h"  // FNV_prime
#include "vw_math.h"

#include <functional>
#include <map>

using simulator::callback_map;
using simulator::cb_sim;

constexpr float AUTO_ML_FLOAT_TOL = 0.0001f;

namespace vw_hash_helpers
{
// see parse_example.cc:maybeFeature(..) for other cases
size_t get_hash_for_feature(vw& all, const std::string& ns, const std::string& feature)
{
  std::uint64_t hash_ft = VW::hash_feature(all, feature, VW::hash_space(all, ns));
  std::uint64_t ft = hash_ft & all.parse_mask;
  // apply multiplier like setup_example
  ft *= (static_cast<uint64_t>(all.wpp) << all.weights.stride_shift());

  return ft;
}

// see gd.cc:audit_feature(..)
size_t hash_to_index(parameters& weights, size_t hash)
{
  hash = hash & weights.mask();
  hash = hash >> weights.stride_shift();

  return hash;
}

// craft feature index for interaction
// see: interactions_predict.h:process_quadratic_interaction(..)
size_t interaction_to_index(parameters& weights, size_t one, size_t two)
{
  // FNV_prime from constant.h
  return hash_to_index(weights, (FNV_prime * one) ^ two);
}
}  // namespace vw_hash_helpers

using namespace vw_hash_helpers;

// 0) runs after 1331 learned examples from simulator.h
// 1) clears (set to zero) offset 1
// 2) copies offset 2 -> offset 1
// n) asserts weights before/after every operation
// NOTE: interactions are currently 0 for offset 0 since
// config 0 is hard-coded to be empty interactions for now.
bool weights_offset_test(cb_sim&, vw& all, multi_ex& ec)
{
  const size_t offset_to_clear = 1;
  auto& weights = all.weights.dense_weights;

  std::vector<std::uint64_t> feature_indexes;
  // hardcoded features that correspond to simulator.h
  feature_indexes.emplace_back(hash_to_index(all.weights, get_hash_for_feature(all, "Action", "article=music")));
  feature_indexes.emplace_back(hash_to_index(all.weights, get_hash_for_feature(all, "Action", "article=politics")));
  feature_indexes.emplace_back(hash_to_index(all.weights, get_hash_for_feature(all, "User", "user=Anna")));

  const size_t interaction_index = interaction_to_index(all.weights,
      get_hash_for_feature(all, "Action", "article=sports"), get_hash_for_feature(all, "Action", "article=sports"));

  const float expected_w0 = 0.0102325846f;
  const float expected_w1 = 0.0230506323f;
  const float expected_w2 = 0.0141550414f;
  const float ZERO = 0.f;

  for (auto index : feature_indexes)
  {
    BOOST_CHECK_NE(ZERO, weights.strided_index(index));
    float w1 = weights.strided_index(index + offset_to_clear);
    float w2 = weights.strided_index(index + offset_to_clear + 1);
    BOOST_CHECK_NE(ZERO, w1);
    BOOST_CHECK_NE(ZERO, w2);
  }

  BOOST_CHECK(VW::math::are_same_rel(expected_w0, weights.strided_index(interaction_index), AUTO_ML_FLOAT_TOL));
  BOOST_CHECK(VW::math::are_same_rel(
      expected_w1, weights.strided_index(interaction_index + offset_to_clear), AUTO_ML_FLOAT_TOL));
  BOOST_CHECK(VW::math::are_same_rel(
      expected_w2, weights.strided_index(interaction_index + offset_to_clear + 1), AUTO_ML_FLOAT_TOL));

  // all weights of offset 1 will be set to zero
  weights.clear_offset(offset_to_clear, all.wpp);

  for (auto index : feature_indexes)
  {
    BOOST_CHECK_NE(ZERO, weights.strided_index(index));
    float w1 = weights.strided_index(index + offset_to_clear);
    float w2 = weights.strided_index(index + offset_to_clear + 1);
    BOOST_CHECK_EQUAL(ZERO, w1);
    BOOST_CHECK_NE(ZERO, w2);
    BOOST_CHECK_NE(w1, w2);
  }

  BOOST_CHECK(VW::math::are_same_rel(expected_w0, weights.strided_index(interaction_index), AUTO_ML_FLOAT_TOL));
  BOOST_CHECK_EQUAL(ZERO, weights.strided_index(interaction_index + offset_to_clear));
  BOOST_CHECK(VW::math::are_same_rel(
      expected_w2, weights.strided_index(interaction_index + offset_to_clear + 1), AUTO_ML_FLOAT_TOL));

  // copy from offset 2 to offset 1
  weights.copy_offsets(offset_to_clear + 1, offset_to_clear, all.wpp);

  for (auto index : feature_indexes)
  {
    BOOST_CHECK_NE(ZERO, weights.strided_index(index));
    float w1 = weights.strided_index(index + offset_to_clear);
    float w2 = weights.strided_index(index + offset_to_clear + 1);
    BOOST_CHECK_NE(ZERO, w1);
    BOOST_CHECK_NE(ZERO, w2);
    BOOST_CHECK_EQUAL(w1, w2);
  }

  BOOST_CHECK(VW::math::are_same_rel(expected_w0, weights.strided_index(interaction_index), AUTO_ML_FLOAT_TOL));
  float actual_w1 = weights.strided_index(interaction_index + offset_to_clear);
  float actual_w2 = weights.strided_index(interaction_index + offset_to_clear + 1);
  BOOST_CHECK(VW::math::are_same_rel(expected_w2, actual_w1, AUTO_ML_FLOAT_TOL));
  BOOST_CHECK(VW::math::are_same_rel(expected_w2, actual_w2, AUTO_ML_FLOAT_TOL));
  BOOST_CHECK_EQUAL(actual_w1, actual_w2);

  // Ensure weights are non-zero for another live interaction
  const size_t interaction_index_other = interaction_to_index(all.weights,
      get_hash_for_feature(all, "Action", "article=sports"), get_hash_for_feature(all, "User", "user=Anna"));

  BOOST_CHECK_NE(ZERO, weights.strided_index(interaction_index_other));
  BOOST_CHECK_NE(ZERO, weights.strided_index(interaction_index_other + 1));
  BOOST_CHECK_NE(ZERO, weights.strided_index(interaction_index_other + 2));

  // Ensure weights are 0 for non-live interactions
  const size_t interaction_index_empty = interaction_to_index(all.weights,
      get_hash_for_feature(all, "User", "user=Anna"), get_hash_for_feature(all, "Action", "article=sports"));

  BOOST_CHECK_EQUAL(ZERO, weights.strided_index(interaction_index_empty));
  BOOST_CHECK_EQUAL(ZERO, weights.strided_index(interaction_index_empty + 1));
  BOOST_CHECK_EQUAL(ZERO, weights.strided_index(interaction_index_empty + 2));

  // VW::automl::helper::print_weights_nonzero(all, 0, all->weights.dense_weights);
  return true;
}

BOOST_AUTO_TEST_CASE(automl_weight_operations)
{
  const size_t seed = 10;
  const size_t num_iterations = 1331;
  callback_map test_hooks;

  // fn test/assert
  test_hooks.emplace(num_iterations, weights_offset_test);

  auto ctr = simulator::_test_helper_hook(
      "--automl 3 --priority_type least_exclusion --cb_explore_adf --quiet --epsilon 0.2 --random_seed 5", test_hooks,
      num_iterations, seed);

  BOOST_CHECK_GT(ctr.back(), 0.4f);
}


#pragma once
#include <trajopt_utils/macros.h>
TRAJOPT_IGNORE_WARNINGS_PUSH
#include <Eigen/Core>
#include <osqp.h>
TRAJOPT_IGNORE_WARNINGS_POP

#include <trajopt_sco/solver_interface.hpp>
#include <trajopt_utils/macros.h>

namespace sco
{
/**
 * OSQPModel uses the BSD solver OSQP to solve a linearly constrained QP.
 * OSQP solves a problem in the form:
 * ```
 * min   1/2*x'Px + q'x
 * s.t.  l <= Ax <= u
 * ```
 *
 * More informations about the solver are available at:
 * https://osqp.org/docs/
 */
class OSQPModel : public Model
{
  OSQPSettings osqp_settings_; /**< OSQP Settings */
                               /** OSQPData. Some fields here (`osp_data_.A` and `osp_data_.P`) are
                                *  automatically allocated by OSQP, but deallocated by us. */
  OSQPData osqp_data_;
  /** OSQP Workspace. Memory here is managed by OSQP */
  OSQPWorkspace* osqp_workspace_;

  /** Updates OSQP quadratic cost matrix from QuadExpr expression.
   *  Transforms QuadExpr objective_ into the OSQP CSC matrix P_ */
  void updateObjective();

  /** Updates qpOASES constraints from AffExpr expression.
   *  Transforms AffExpr cntr_exprs_ and box bounds lbs_ and ubs_ into the
   *  OSQP CSC matrix A_, and vectors lbA_ and ubA_ */
  void updateConstraints();

  /** Creates or updates the solver and its workspace */
  void createOrUpdateSolver();

  VarVector vars_;                 /**< model variables */
  CntVector cnts_;                 /**< model's constraints sizes */
  DblVec lbs_, ubs_;               /**< variables bounds */
  AffExprVector cnt_exprs_;        /**< constraints expressions */
  ConstraintTypeVector cnt_types_; /**< constraints types */
  DblVec solution_;                /**< optimizizer's solution for current model */

  std::vector<c_int> P_row_indices_;     /**< row indices for P, CSC format */
  std::vector<c_int> P_column_pointers_; /**< column pointers for P, CSC format */
  DblVec P_csc_data_;                    /**< P values in CSC format */
  Eigen::VectorXd q_;                    /**< linear part of the objective */

  std::vector<c_int> A_row_indices_;     /**< row indices for constraint matrix, CSC format */
  std::vector<c_int> A_column_pointers_; /**< column pointers for constraint matrix, CSC format */
  DblVec A_csc_data_;                    /**< constraint matrix values in CSC format */
  DblVec l_, u_;                         /**< linear constraints upper and lower limits */

  QuadExpr objective_; /**< objective QuadExpr expression */

public:
  OSQPModel();
  virtual ~OSQPModel();

  Var addVar(const std::string& name) override;
  Cnt addEqCnt(const AffExpr&, const std::string& name) override;
  Cnt addIneqCnt(const AffExpr&, const std::string& name) override;
  Cnt addIneqCnt(const QuadExpr&, const std::string& name) override;
  void removeVars(const VarVector& vars) override;
  void removeCnts(const CntVector& cnts) override;

  void update() override;
  void setVarBounds(const VarVector& vars, const DblVec& lower, const DblVec& upper) override;
  DblVec getVarValues(const VarVector& vars) const override;
  virtual CvxOptStatus optimize() override;
  virtual void setObjective(const AffExpr&) override;
  virtual void setObjective(const QuadExpr&) override;
  virtual void writeToFile(const std::string& fname) override;
  virtual VarVector getVars() const override;
};
}


#include <boost/graph/bron_kerbosch_all_cliques.hpp>