#include <string>
#include <assert.h>
#include <vector>
#include <numeric>
#include <algorithm>
#include <cctype>
#include <locale>
#include <codecvt>

#include <boost/algorithm/string/join.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/range/iterator_range.hpp>
#include <boost/optional.hpp>

namespace collections {

using namespace std;
namespace bs = boost;

namespace {

    typedef basic_string<char32_t, char_traits<char32_t>, allocator<char32_t>> wide_string;
    //typedef std::codecvt<char32_t, char, std::mbstate_t> wide_string_codec;
    typedef std::codecvt_utf8 < char32_t > wide_string_codec;
    typedef std::wstring_convert<wide_string_codec, char32_t > wide_string_converter;
    typedef bs::iterator_range<const char32_t *> wstring_range;

    float charactersPerLine(int total, int maxCharsPerLine) {
        jc_assert(maxCharsPerLine > 0);
        float result = (total) / (1.f + (float)total / maxCharsPerLine);
        return result;
    }

    struct line
    {
        vector<wstring_range> words;

        int charCount() const {
            return std::accumulate(words.begin(), words.end(), 0, [](int val, const wstring_range& str) {
                return val + (int)str.size();
            })
                + (words.size() > 0 ? words.size() - 1 : 0);
        }

        void addWord(const wstring_range& word) {
            words.push_back(word);
        }

        string toUTF8String(wide_string_converter& conv) const {
            std::string result;
            for (const auto& str : words) {
                result.append(conv.to_bytes(str.begin(), str.end()));
                result += ' ';
            }

            return result;
        }
    };

    struct line_set
    {
        vector<line> lines;
        float idealCpl;

        line& operator[] (int idx) {
            return lines[idx];
        }

        line& top()  {
            return lines.back();
        }

        line& newLine() {
            addLine(line());
            return top();
        }

        void addLine(const line& ln) {
            lines.push_back(ln);
        }

        bool isLast(int lineIdx) const {
            return lineIdx == (lines.size() - 1);
        }

        bool isFirst(int lineIdx) const {
            return lineIdx == 0;
        }

        void incrLength(int lineIdx) {
            if (isFirst(lineIdx)) {

                if (lines.size() >= 2) {
                    decrLength(1);
                }

                return ;
            }

            auto& from =  lines[lineIdx - 1].words;

            if (from.empty()) {
                return ;
            }

            auto word = from.back();
            from.pop_back();

            auto& to = lines[lineIdx].words;
            to.insert(to.begin(), word);
        }

        void decrLength(int lineIdx) {
            if (isFirst(lineIdx)) {

                if (lines.size() >= 2) {
                    incrLength(1);
                }

                return ;
            }

            auto& from = lines[lineIdx].words;

            if (from.empty()) {
                return ;
            }

            auto word = from.front();
            from.erase(from.begin());

            auto& to = lines[lineIdx - 1].words;
            to.push_back(word);
        }

        float meanSquare() const {
            float avg = average();

            return std::accumulate(lines.begin(), lines.end(), 0.f, [=](float val, const line& ln) {
                return val + powf(ln.charCount() - avg, 2.f);
            })
                / (float)lines.size();
        }

        float charDiffIn(int lineIdx) const {
            return charDiffIn(lines[lineIdx]);
        }

        float charDiffIn(const line& ln) const {
            return ln.charCount() - average();
        }

        float average() const {
            return charCount() / (float)lines.size();
        }

        int charCount() const {
            return std::accumulate(lines.begin(), lines.end(), 0, [](int val, const line& ln) {
                return val + ln.charCount();
            });
        }

    /*
        int minIdx() const {
            return std::min_element(lines.cbegin(), lines.cend(), [=](const line& ln, const line& smallest){
                return charDiffIn(ln) < charDiffIn(smallest);
            })
                - lines.begin();
        }
    */
    /*

        vector<int> sortedIndices() const {
            vector<int> indices;

            int idx = 0;
            std::transform(lines.begin(), lines.end(), std::back_inserter(indices), [&](const line& ln) {
                return idx++;
            });

            std::sort(indices.begin(), indices.end(), [=](int left, int right) {
                return fabs(charDiffIn(left)) < fabs(charDiffIn(right));
            });

            return indices;
        }*/

    /*
        int maxIdx() const {
            return std::max_element(lines.cbegin(), lines.cend(), [=](const line& ln, const line& smallest){
                return charDiffIn(ln) < charDiffIn(smallest);
            })
                - lines.begin();
        }*/

        vector<string> utf8Strings(wide_string_converter& conv) const {
            vector<string> result;

            std::transform(lines.begin(), lines.end(), std::back_inserter(result), [&](const line& ln) {
                return ln.toUTF8String(conv);
            });

            return result;
        }
    };

    bool is_blank_or_space(char32_t c) {
        // from https://www.cs.tut.fi/~jkorpela/chars/spaces.html
        switch (c)
        {
        case 0x20:
        case 0xa0:
        case '\n':
        case '\r':
        case '\t':
        case '\b':
        case '\f':

        case 0x2000:
        case 0x2001:
        case 0x2003:
        case 0x2004:
        case 0x2005:
        case 0x2006:
        case 0x2007:
        case 0x2008:
        case 0x2009:
        case 0x200a:
        case 0x200b:

        case 0x202f:
        case 0x205f:

        case 0x3000:
        case 0xfeff:
            return true;
        default:
            return false;
        }
    }

    vector<wstring_range> split_range(wstring_range::iterator beg, wstring_range::iterator end) {
        vector<wstring_range> strings;
		return boost::split(strings, boost::make_iterator_range(beg, end), &is_blank_or_space);
    }

    line_set initialSet(const wstring_range& data, int charsPerLine = 40) {

        float cpl = charactersPerLine(data.size(), charsPerLine);

        line_set result;

        result.idealCpl = cpl;

        //auto last = data.begin();
        auto first = data.begin();

        while (first != data.end())
        {
            auto& line = result.newLine();

            if ((data.end() - first) >= cpl ) {

				auto nearestBreak = [first, cpl, &data]() {
					auto middle = first + (int)cpl;
					auto left = middle, right = middle;

					while (left > first && is_blank_or_space(*left) == false) {
						--left;
					}

					while (right < data.end() && is_blank_or_space(*right) == false) {
						++right;
					}

					return (left != first && middle - left < (right - middle) * 1.2) ? left : right;
				};

				auto selected = nearestBreak();
				line.words = split_range(first, selected);

                first = selected;
            }
            else {
				line.words = split_range(first, data.end());

                first = data.end();
            }
        }

        return result;

    }

    struct operation {
        line_set *lset;
        int lineIdx;
        bool increase;

        operation() {
            lset = nullptr;
            lineIdx = 0;
            increase = false;
        }

        void doIncr(bool incr, int lnIdx, line_set& set) {
            lineIdx = lnIdx;
            increase = incr;
            lset = &set;

            if (incr) {
                set.incrLength(lnIdx);
            } else {
                set.decrLength(lnIdx);
            }
        }

        void revert() {
            doIncr(!increase, lineIdx, *lset);
        }
    };

}

boost::optional<vector<string>> wrap_string(const char *csource, int charsPerLine)
{
    if (!csource || charsPerLine <= 0) {
        // invalid input
        return boost::none;
    }

    wide_string_converter converter;
    wide_string_converter::wide_string wstr;

    try {
        wstr = converter.from_bytes(csource);
    }
    catch (const std::range_error&) {
        // invalid input - non UTF-8 source string probably
        return boost::none;
    }

    if (wstr.empty()) {
        return vector<string>();
    }

    wstring_range range(&wstr.front(), &wstr.back() + 1);

    line_set set = initialSet(range, charsPerLine);

    operation setOpr;

    float delta = set.meanSquare();

    int loop = 0;
    while (loop < 40) {
        ++loop;

        float oldDelta = set.meanSquare();

        for (size_t i = 0; i < set.lines.size(); ++i) {

            bool needIncr = set.charDiffIn(i) < 0;

            float oldDelta = set.meanSquare();
            setOpr.doIncr(needIncr, i, set);
            float newDelta = set.meanSquare();

            if (newDelta > oldDelta) {
                setOpr.revert();
            } else {
                i = i;
            }

        }

        float newDelta = set.meanSquare();

        if (fabs(oldDelta - newDelta) < 0.00001f) {
            break;
        }
    }

    return set.utf8Strings(converter);
}
}


#ifndef BART_SRC_DOMAIN_FINITE_ELEMENT_MOCK_HPP_
#define BART_SRC_DOMAIN_FINITE_ELEMENT_MOCK_HPP_

#include "domain/finite_element/finite_element_i.hpp"

#include <deal.II/fe/fe_values.h>

#include "test_helpers/gmock_wrapper.h"

namespace bart::domain::finite_element {

template <int dim>
class FiniteElementMock : public FiniteElementI<dim> {
 public:
  using typename FiniteElementI<dim>::DealiiVector;
  MOCK_METHOD(int, polynomial_degree, (), (const, override));
  MOCK_METHOD(int, dofs_per_cell, (), (const, override));
  MOCK_METHOD(int, n_cell_quad_pts, (), (const, override));
  MOCK_METHOD(int, n_face_quad_pts, (), (const, override));
  MOCK_METHOD(bool, SetCell, (const domain::CellPtr<dim> &));
  MOCK_METHOD(bool, SetFace, (const domain::CellPtr<dim> &to_set, const domain::FaceIndex), (override));
  MOCK_METHOD(double, ShapeValue, (const int, const int), (const, override));
  MOCK_METHOD(double, FaceShapeValue, (const int, const int), (const, override));
  MOCK_METHOD((dealii::Tensor<1, dim>), ShapeGradient, (const int, const int), (const, override));
  MOCK_METHOD(double, Jacobian, (const int), (const, override));
  MOCK_METHOD(double, FaceJacobian, (const int), (const, override));
  MOCK_METHOD((dealii::Tensor<1, dim>), FaceNormal, (), (const, override));
  MOCK_METHOD(std::vector<double>, ValueAtQuadrature, (const DealiiVector&), (const, override));
  MOCK_METHOD(std::vector<double>, ValueAtFaceQuadrature, (const DealiiVector&), (const, override));
  MOCK_METHOD((dealii::FiniteElement<dim, dim>*), finite_element, (), (override));
  MOCK_METHOD(dealii::FEValues<dim>*, values, (), (override));
  MOCK_METHOD(dealii::FEFaceValues<dim>*, face_values, (), (override));
  MOCK_METHOD(dealii::FEFaceValues<dim>*, neighbor_face_values, (), (override));
};

} // namespace bart::domain::finite_element

#endif //BART_SRC_DOMAIN_FINITE_ELEMENT_MOCK_HPP_


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

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

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

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

 /*!

    @ingroup group-predicates
    Function object implementing is_not_invalid capabilities

    Returns @ref True if x is not inf, -inf or nan, else returns @ref False.

    This is a convenient alias of @ref is_finite
  **/
  const boost::dispatch::functor<tag::is_not_invalid_> is_not_invalid = {};
} }
#endif

#include <boost/simd/function/scalar/is_finite.hpp>
#include <boost/simd/function/simd/is_not_invalid.hpp>

#endif


/*
* Copyright (C) 2017 Incognito (Edited by ProMetheus)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <streamer/config.hpp>
#include "../natives.h"

#include "../core.h"
#include "../utility.h"

#include <streamer/map-icons.hpp>

#include <boost/geometry.hpp>
#include <boost/geometry/geometries/geometries.hpp>
#include <boost/intrusive_ptr.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/unordered_map.hpp>
#include <boost/unordered_set.hpp>

#include <Eigen/Core>

STREAMER_BEGIN_NS

int CreateDynamicMapIcon(
	float x,
	float y,
	float z,
	int type,
	int color,
	int worldid,
	int interiorid,
	int playerid,
	float streamDistance,
	int style,
	int areaid,
	int priority
) {
	if (core->getData()->getGlobalMaxItems(STREAMER_TYPE_MAP_ICON) == core->getData()->mapIcons.size()) {
		return 0;
	}
	int mapIconId = Item::MapIcon::identifier.get();
	Item::SharedMapIcon mapIcon(new Item::MapIcon);
	//mapIcon->amx = amx;
	mapIcon->mapIconId = mapIconId;
	mapIcon->inverseAreaChecking = false;
	mapIcon->originalComparableStreamDistance = -1.0f;
	mapIcon->positionOffset = Eigen::Vector3f::Zero();
	mapIcon->streamCallbacks = false;
	mapIcon->position = Eigen::Vector3f(x, y, z);
	mapIcon->type = type;
	mapIcon->color = color;

	Utility::addToContainer(mapIcon->worlds, worldid);
	Utility::addToContainer(mapIcon->interiors, interiorid);
	Utility::addToContainer(mapIcon->players, playerid);

	mapIcon->comparableStreamDistance = streamDistance < STREAMER_STATIC_DISTANCE_CUTOFF ? streamDistance : streamDistance * streamDistance;
	mapIcon->streamDistance = streamDistance;
	mapIcon->style = style;
	Utility::addToContainer(mapIcon->areas, areaid);
	mapIcon->priority = priority;
	core->getGrid()->addMapIcon(mapIcon);
	core->getData()->mapIcons.insert(std::make_pair(mapIconId, mapIcon));
	return static_cast<cell>(mapIconId);
}

int DestroyDynamicMapIcon(int id) {
	boost::unordered_map<int, Item::SharedMapIcon>::iterator m = core->getData()->mapIcons.find(id);
	if (m != core->getData()->mapIcons.end()) {
		Utility::destroyMapIcon(m);
		return 1;
	}
	return 0;
}

int IsValidDynamicMapIcon(int id) {
	boost::unordered_map<int, Item::SharedMapIcon>::iterator m = core->getData()->mapIcons.find(id);
	if (m != core->getData()->mapIcons.end()) {
		return 1;
	}
	return 0;
}

STREAMER_END_NS


#include <algorithm>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <map>
#include <numeric>
#include <sstream>
#include <stdint.h>
#include <string>
#include <vector>
#include <cfloat>
#include <tr1/unordered_map>
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
#include <limits>
#include <lap/lap.h>

#include <boost/static_assert.hpp>

using namespace boost::lambda;
using namespace std;
using namespace lap;

template <typename P, typename N>
struct PositionNormal
{
  vec<P,3> position;
  vec<N,3> normal;

  PositionNormal()
  {}

  template <typename U> PositionNormal(const U& rhs):
    position(rhs.position), normal(rhs.normal) { }
};

template <>
struct PositionNormal<int16_t, int16_t>
{
  vec<int16_t, 3> position;
  uint8_t _padding[2];
  vec<int16_t, 3> normal;
  PositionNormal(){}

  template <typename U> PositionNormal(const U& rhs):
    position(rhs.position), normal(rhs.normal) { }
};

template <typename P, typename N, typename T>
struct PositionNormalColorUV
{
  vec<P,3> position;
  vec<N,3> normal;
  vec<T,2> uv;
  vec<uint8_t,4> color;

  PositionNormalColorUV()
  {}

  template <typename U>
    PositionNormalColorUV(const U& rhs):
      position(rhs.position),
      normal(rhs.normal),
      uv(rhs.uv),
      color(rhs.color)
    { }
};

template <typename P, typename N, typename T>
struct PositionNormalUV
{
  vec<P,3> position;
  vec<N,3> normal;
  vec<T,2> uv;
  PositionNormalUV()
  {}

  template <typename U>
    PositionNormalUV(const U& rhs):
      position(rhs.position),
      normal(rhs.normal),
      uv(rhs.uv)
    { }
};

void vertexAttribPointer(uint32_t index, int size, uint32_t type, bool normalized, size_t stride,
                                  const void * pointer)
{
  std::cout << "vertexAttribPointer("
    << index << ", "
    << size << ", "
    << type << ", "
    << normalized << ", "
    << stride << ", "
    << pointer << ")\n";

}
template <typename T>
uint32_t componentType();

template <> uint32_t componentType<float>() { return 123; }
template <> uint32_t componentType<short>() { return 245; }

#define BUFFER_OFFSET(i) ((char *)NULL + (i))

template <typename P, typename N>
void vertexPointer(PositionNormal<P,N>* vs)
{
  vertexAttribPointer(0, 3, componentType<P>(), false, sizeof(PositionNormal<P,N>),
    BUFFER_OFFSET(0));

  vertexAttribPointer(1, 3, componentType<N>(), false, sizeof(PositionNormal<P,N>),
    BUFFER_OFFSET(sizeof(P)));
}

void testVertexPointer()
{
  PositionNormal<float,short> v;
  v.position = float3(1, -2, 3);
  v.normal = vec<short,3>(0, 1, 0);
  vertexPointer(&v);
}

typedef PositionNormal<float,float> PositionFNormalF;
typedef PositionNormal<int16_t,int16_t> Position16Normal16;

template <typename P, typename N>
std::ostream& operator<<(std::ostream& os, const PositionNormal<P, N>& rhs)
{
  os << rhs.position << ", ";
  os << rhs.normal;
  return os;
}

template <typename U, int N>
vec<float, N> compress(const vec<U, N>& rhs)
{
  vec<float, N> result;
  for (uint32_t i = 0; i < N; ++i)
  {
    result[i] = (float)rhs[i] / std::numeric_limits<U>::max();
  }
  return result;
}

template <typename T, int N>
vec<T, N> expand(const vec<float, N>& rhs)
{
  vec<T, N> result;
  for (uint32_t i = 0; i < N; ++i)
  {
    result[i] = rhs[i] * std::numeric_limits<T>::max();
  }
  return result;
}

void testAlignment()
{
  PositionNormal<short, short> pn16[2];
  pn16[0].position = vec<short, 3>(12, 15, 20);
  pn16[0].normal = vec<short, 3>(0, 1, 0);

  pn16[1].position = vec<short, 3>(5, 7, 9);
  pn16[1].normal = vec<short, 3>(1, 0, 0);

  cout << "&pn16[0] " << &pn16[0] << ", &pn16[0].p "
    << (uint8_t*)&pn16[0].position - (uint8_t*)&pn16[0] << ", &pn16[0].n "
        << (uint8_t*)&pn16[0].normal - (uint8_t*)&pn16[0] << endl;

  cout << "&pn16[1] " << &pn16[1] << ", &pn16[1].p "
    << (uint8_t*)&pn16[1].position - (uint8_t*)&pn16[1] << ", &pn16[1].n "
        << (uint8_t*)&pn16[1].normal - (uint8_t*)&pn16[1] << endl;

}

void testMeshAlignCopy()
{
  const char* modelFile = "/Users/daniel/content/models/test/box_pn.obj";
   shared_ptr<Mesh<VertexPN> > m =
     meshFromObj<VertexPN>(obj::ObjTranslator().importFile(modelFile));

   cout << "m\n" << *m << endl;

   Mesh<PositionNormal<short, short> > m16 = *m;
   cout << "m16\n" << m16 << endl;

}

float rand16()
{
  return (2.0f * ((random() % 0xFFFF) / 65535.0f) - 1.0f) * 32767.0f;

}

PositionNormal<float, float> makeRandPN()
{
  PositionNormal<float, float> pn;
  pn.position = vec<float, 3>(rand16(), rand16(), rand16());
  pn.normal = vec<float, 3>(rand16(), rand16(), rand16());
  return pn;
}

void testAlignCopy()
{
  PositionNormal<float, float> pn;
  pn.position = vec<float, 3>(-3.5, 10, 999);
  pn.normal = vec<float, 3>(43, -10, 77.7);

  cout << "pn " << pn << endl;

  PositionNormal<short, short> pn16(pn);
  cout << "pn16 " << pn16 << endl;

  std::vector<PositionNormal<float, float> > pns(4);
  generate(pns.begin(), pns.end(), makeRandPN);
  for_each(pns.begin(), pns.end(), cout << _1 << ' ');
  cout << endl;
  std::vector<PositionNormal<short, short> > pns16(pns.begin(), pns.end());
  for_each(pns16.begin(), pns16.end(), cout << _1 << ' ');
  cout << endl;

}

void testExpand()
{
  vec<float, 2> a(-1.0f, 1.0f);
  vec<int16_t, 2> b = expand<int16_t>(a);
  cout << "b " << b << endl;
}

int main(int argc, char **argv)
{
  float3 a;
  a[0] = 3; a[1] = 3; a[2] = 3;
  float3 b;

  b[0] = 2; b[1] = 3; b[2] = 2;

  float3 c;
  c[0] = 3; c[1] = 3; c[2] = 3;

  cout << "a " << a << ", b " << b << ", c " << c << endl;
  cout << "a == b: " << (a == b) << ", b == c: " << (a == c) << endl;

  cout << "b < a: " << (b < a) << endl;

  typedef std::tr1::unordered_map<float3, int> Float3Map;

  //  Float3Map float3Map;
  //  std::map<float3, int> myMap;
  std::tr1::unordered_map<float3, int> float3Map;

  for (int i = 0; i < 10; ++i)
  {
    float3 z;
    z[0] = rand() % 100 - 50;
    z[1] = rand() % 100 - 50;
    z[2] = rand() % 100 - 50;
    float3Map[z] = i;
  }

  //  for_each(float3Map.begin(), float3Map.end(),
  //     cout << bind(&std::pair<float3,int>::first, _1) << endl);

  for (Float3Map::const_iterator i = float3Map.begin(); i != float3Map.end(); ++i)
  {
    cout << i->first << endl;
  }

  vector<vec<short, 3> > s3;
  std::transform(float3Map.begin(), float3Map.end(), std::back_inserter(s3),
      bind(&Float3Map::value_type::first, _1));

  cout << endl;
  for_each(s3.begin(), s3.end(), cout << _1 << '\n');

  {
    vec<float, 2> x(3.0f, -5.0f);
    cout << "x " << x << endl;
    float3 y(-2, 1, 99.0f);
    cout << "y " << y << endl;

    vec<float, 4> w(1, -2, 8, -7.0f);
    vec<float, 4> z = w;
    z[2] = .3f;
    cout << "z " << z << endl;
  }

  {
    PositionFNormalF x;
    x.position = float3(1, 2, 3);
    x.normal = float3(1, 0, 0);
    cout << "x " << x << endl;
    Position16Normal16 y = x;
    cout << "y " << y << endl;

  }
  testExpand();

  testVertexPointer();

  testAlignment();

  testAlignCopy();

  testMeshAlignCopy();
  return 0;
}


#include <scorum/protocol/asset.hpp>
#include <boost/rational.hpp>
#include <boost/multiprecision/cpp_int.hpp>

/*

The bounds on asset serialization are as follows:

index : field
0     : decimals
1..6  : symbol
   7  : \0
*/

namespace scorum {
namespace protocol {
typedef boost::multiprecision::int128_t int128_t;

void asset::_check_symbol()
{
    FC_ASSERT(SCORUM_SYMBOL == _symbol || SP_SYMBOL == _symbol,
              "Invalid asset symbol received. ${1} not either ${2} or ${3}.",
              ("1", _symbol)("2", SCORUM_SYMBOL)("3", SP_SYMBOL));
}

void asset::_set_decimals(uint8_t d)
{
    FC_ASSERT(d < 15);
    auto a = (char*)&_symbol;
    a[0] = d;
}

uint8_t asset::decimals() const
{
    auto a = (const char*)&_symbol;
    uint8_t result = uint8_t(a[0]);
    FC_ASSERT(result < 15);
    return result;
}

std::string asset::symbol_name() const
{
    auto a = (const char*)&_symbol;
    FC_ASSERT(a[7] == 0);
    return &a[1];
}

int64_t asset::precision() const
{
    static int64_t table[] = { 1,
                               10,
                               100,
                               1000,
                               10000,
                               100000,
                               1000000,
                               10000000,
                               100000000ll,
                               1000000000ll,
                               10000000000ll,
                               100000000000ll,
                               1000000000000ll,
                               10000000000000ll,
                               100000000000000ll };
    uint8_t d = decimals();
    return table[d];
}

std::string asset::to_string() const
{
    int64_t prec = precision();
    std::string result = fc::to_string(amount.value / prec);
    if (prec > 1)
    {
        auto fract = amount.value % prec;
        // prec is a power of ten, so for example when working with
        // 7.005 we have fract = 5, prec = 1000.  So prec+fract=1005
        // has the correct number of zeros and we can simply trim the
        // leading 1.
        result += "." + fc::to_string(prec + fract).erase(0, 1);
    }
    return result + " " + symbol_name();
}

asset asset::from_string(const std::string& from)
{
    try
    {
        std::string s = fc::trim(from);
        auto space_pos = s.find(" ");
        auto dot_pos = s.find(".");

        FC_ASSERT(space_pos != std::string::npos);

        asset result;
        result._symbol = uint64_t(0);
        auto sy = (char*)&result._symbol;

        if (dot_pos != std::string::npos)
        {
            FC_ASSERT(space_pos > dot_pos);

            auto intpart = s.substr(0, dot_pos);
            auto fractpart = "1" + s.substr(dot_pos + 1, space_pos - dot_pos - 1);
            result._set_decimals(fractpart.size() - 1);

            result.amount = fc::to_int64(intpart);
            result.amount.value *= result.precision();
            result.amount.value += fc::to_int64(fractpart);
            result.amount.value -= result.precision();
        }
        else
        {
            auto intpart = s.substr(0, space_pos);
            result.amount = fc::to_int64(intpart);
            result._set_decimals(0);
        }
        auto symbol = s.substr(space_pos + 1);
        size_t symbol_size = symbol.size();

        if (symbol_size > 0)
        {
            FC_ASSERT(symbol_size <= 6);
            memcpy(sy + 1, symbol.c_str(), symbol_size);
        }

        result._check_symbol();
        return result;
    }
    FC_CAPTURE_AND_RETHROW((from))
}
}
} // scorum::protocol


#ifndef ALLOCGC_BITSET_HPP
#define ALLOCGC_BITSET_HPP

#include <cstddef>
#include <cstring>
#include <atomic>
#include <array>
#include <limits>
#include <stdexcept>

#include <boost/integer/static_log2.hpp>
#include <boost/optional.hpp>

#include <liballocgc/details/utils/math.hpp>
#include <iostream>

namespace allocgc { namespace details { namespace utils {

namespace internals {

typedef unsigned long long ull;

class bitset_block
{
public:
    bitset_block()
        : m_val(0)
    {}

    bitset_block(const bitset_block&) = default;

    ull load() const
    {
        return m_val;
    }
    void store(ull val)
    {
        m_val = val;
    }

    void fetch_and(ull mask)
    {
        m_val &= mask;
    }

    void fetch_or(ull mask)
    {
        m_val |= mask;
    }

    void fetch_xor(ull mask)
    {
        m_val ^= mask;
    }
private:
    ull m_val;
};

class sync_bitset_block
{
public:
    sync_bitset_block()
        : m_val(0)
    {}

    sync_bitset_block(const sync_bitset_block& other)
        : m_val(other.load())
    {}

    ull load() const
    {
        return m_val.load(std::memory_order_acquire);
    }

    void store(ull val)
    {
        m_val.store(val, std::memory_order_release);
    }

    void fetch_and(ull mask)
    {
        m_val.fetch_and(mask, std::memory_order_acq_rel);
    }

    void fetch_or(ull mask)
    {
        m_val.fetch_or(mask, std::memory_order_acq_rel);
    }

    void fetch_xor(ull mask)
    {
        m_val.fetch_xor(mask, std::memory_order_acq_rel);
    }
private:
    std::atomic<ull> m_val;
};

template <size_t N, typename Block>
class bitset
{
    static const size_t BLOCK_SIZE = CHAR_BIT * sizeof(Block);
    static const size_t LOG2_BLOCK_SIZE = boost::static_log2<BLOCK_SIZE>::value;
    static const size_t BLOCK_CNT = (N + BLOCK_SIZE - 1) / BLOCK_SIZE;

    static_assert(check_pow2(BLOCK_SIZE), "bitset block size must be power of two");
public:
    bitset() = default;
    bitset(const bitset& other) = default;

    template <typename Block_>
    bitset(const bitset<N, Block_>& other)
    {
        for (size_t i = 0; i < BLOCK_CNT; ++i) {
            m_blocks[i].store(other.m_blocks[i].load());
        }
    }

    bool get(size_t i) const
    {
        ull mask = ONE << bit_offset(i);
        return m_blocks[block_idx(i)].load() & mask;
    }

    void set(size_t i)
    {
        ull mask = ONE << bit_offset(i);
        m_blocks[block_idx(i)].fetch_or(mask);
    }

    void reset(size_t i)
    {
        ull mask = ONE << bit_offset(i);
        m_blocks[block_idx(i)].fetch_and(~mask);
    }

    void set(size_t i, bool val)
    {
        val ? set(i) : reset(i);
    }

    bitset& set_all()
    {
        for (auto& block: m_blocks) {
            block.store(MAX);
        }
        return *this;
    }

    bitset& reset_all()
    {
        for (auto& block: m_blocks) {
            block.store(ZERO);
        }
        return *this;
    }

    bool all() const
    {
        bool b = true;
        for (auto& block: m_blocks) {
            b &= (block.load() == MAX);
        }
        return b;
    }

    bool any() const
    {
        bool b = false;
        for (auto& block: m_blocks) {
            b |= (block.load() != 0);
        }
        return b;
    }

    bool none() const
    {
        bool b = true;
        for (auto& block: m_blocks) {
            b &= (block.load() == 0);
        }
        return b;
    }

    size_t count() const
    {
        size_t cnt = 0;
        for (auto& block: m_blocks) {
            ull n = block.load();
            while (n > 0) {
                ++cnt;
                n &= n - 1;
            }
        }
        return cnt;
    }

    size_t size() const
    {
        return N;
    }

    boost::optional<size_t> most_significant_bit() const
    {
        for (size_t i = BLOCK_CNT - 1; i > 0; --i) {
            ull val = m_blocks[i].load();
            if (val != 0) {
                return boost::make_optional(msb(val) + i * BLOCK_SIZE);
            }
        }
        ull val = m_blocks[0].load();
        return val != 0 ? boost::make_optional(msb(val)) : boost::optional<size_t>();
    }

    boost::optional<size_t> least_significant_bit() const
    {
        for (size_t i = 0; i < BLOCK_CNT - 1; ++i) {
            ull val = m_blocks[i].load();
            if (val != 0) {
                return boost::make_optional(lsb(val) + i * BLOCK_SIZE);
            }
        }
        ull val = m_blocks[BLOCK_CNT - 1].load();
        return val != 0 ? boost::make_optional(lsb(val) + (BLOCK_CNT - 1) * BLOCK_SIZE) : boost::optional<size_t>();
    }

    bitset& operator<<=(size_t pos)
    {
        size_t blk_shift  = block_idx(pos);
        size_t bits_shift = bit_offset(pos);
        size_t bits_carry = BLOCK_SIZE - bits_shift;

        for (size_t i = blk_shift + 1; i < BLOCK_CNT; ++i) {
            ull v = (m_blocks[i].load() << bits_shift) | (m_blocks[i - 1].load() >> bits_carry);
            m_blocks[i + blk_shift].store(v);
        }
        m_blocks[blk_shift].store(m_blocks[0].load() << bits_shift);
        for (size_t i = 0; i < blk_shift; ++i) {
            m_blocks[i].store(0);
        }

        return *this;
    }

    bitset operator<<(size_t pos) const
    {
        return bitset(*this) <<= pos;
    }

    bitset& operator>>=(size_t pos)
    {
        size_t blk_shift  = block_idx(pos);
        size_t bits_shift = bit_offset(pos);
        size_t bits_carry = BLOCK_SIZE - bits_shift;

        if (blk_shift < BLOCK_CNT) {
            m_blocks[BLOCK_CNT - blk_shift - 1].store(m_blocks[BLOCK_CNT - 1].load() >> bits_shift);
            for (size_t i = 0; i < BLOCK_CNT - blk_shift - 1; ++i) {
                ull v = (m_blocks[i + blk_shift].load() >> bits_shift) | (m_blocks[i + blk_shift + 1].load() << bits_carry);
                m_blocks[i].store(v);
            }
        }
        for (size_t i = BLOCK_CNT - 1; i > BLOCK_CNT - blk_shift - 1; --i) {
            m_blocks[i].store(0);
        }

        return *this;
    }

    bitset operator>>(size_t pos) const
    {
        return bitset(*this) >>= pos;
    }

    bitset& operator~()
    {
        for (size_t i = 0; i < BLOCK_CNT; ++i) {
            m_blocks[i].store(~m_blocks[i].load());
        }
        return *this;
    }

    bitset& operator|=(const bitset& other)
    {
        for (size_t i = 0; i < BLOCK_CNT; ++i) {
            m_blocks[i].fetch_or(other.m_blocks[i].load());
        }
        return *this;
    }

    bitset& operator&=(const bitset& other)
    {
        for (size_t i = 0; i < BLOCK_CNT; ++i) {
            m_blocks[i].fetch_and(other.m_blocks[i].load());
        }
        return *this;
    }

    friend bitset operator|(const bitset& a, const bitset& b)
    {
        return bitset(a) |= b;
    }

    friend bitset operator&(const bitset& a, const bitset& b)
    {
        return bitset(a) &= b;
    }

    void swap(bitset& other)
    {
        for (size_t i = 0; i < BLOCK_CNT; ++i) {
            ull tmp = m_blocks[i].load();
            m_blocks[i].store(other.m_blocks[i].load());
            other.m_blocks[i].store(tmp);
        }
    }

    friend void swap(bitset& a, bitset& b)
    {
        a.swap(b);
    }

    template <size_t N_, typename Block_>
    friend class bitset;
private:
    static const ull ZERO = 0;
    static const ull ONE  = 1;
    static const ull MAX  = std::numeric_limits<ull>::max();

    static constexpr size_t block_idx(size_t i)
    {
        return i >> LOG2_BLOCK_SIZE;
    }

    static constexpr size_t bit_offset(size_t i)
    {
        return i & (BLOCK_SIZE - 1);
    }

    std::array<Block, BLOCK_CNT> m_blocks;
};

}

template <size_t N>
using bitset = internals::bitset<N, internals::bitset_block>;

template <size_t N>
using sync_bitset = internals::bitset<N, internals::sync_bitset_block>;

}}}

#endif //ALLOCGC_BITSET_HPP


// Copyright (c) 2020 Graphcore Ltd. All rights reserved.
#define BOOST_TEST_MODULE MatMulGradPatternTest

#include <../random_util.hpp>
#include <boost/test/unit_test.hpp>
#include <filereader.hpp>
#include <popart/builder.hpp>
#include <popart/dataflow.hpp>
#include <popart/devicemanager.hpp>
#include <popart/graph.hpp>
#include <popart/inputshapeinfo.hpp>
#include <popart/ndarraywrapper.hpp>
#include <popart/op/identity.hpp>
#include <popart/op/l1.hpp>
#include <popart/op/matmul.hpp>
#include <popart/op/reshape.hpp>
#include <popart/op/transpose.hpp>
#include <popart/opmanager.hpp>
#include <popart/popx/devicex.hpp>
#include <popart/session.hpp>
#include <popart/sgd.hpp>
#include <popart/tensor.hpp>
#include <popart/tensordata.hpp>
#include <popart/tensorinfo.hpp>
#include <popart/tensornames.hpp>
#include <popart/tensors.hpp>
#include <popart/testdevice.hpp>

#include <algorithm>
#include <chrono>
#include <map>
#include <tuple>
#include <vector>

using namespace popart;

// Compute two MatMuls and their backward passes, make sure the
// MatMul Reshape/Transpose introduced by the MatMulGradPattern are scheduled
// as late as possible.
BOOST_AUTO_TEST_CASE(MatMulGradPatternScheduleTest_0) {

  // The matrix sizes are important to ensure the order in which we expect
  // the SGDVarUpdates to happen under optimal tensor liveness scheduling.
  // The current configuration should ensure the maximum distance between
  // tensor producer and consumer is 8.
  int64_t M = 32;
  int64_t N = 24;
  int64_t O = 16;
  int64_t P = 8;
  int64_t K = 20;

  // we will generate random initializations
  int seed = 1337;
  DefaultRandomEngine eng(seed);
  UniformRealDistribution<float> fdis(-4.f, +4.f);

  auto bder        = Builder::create();
  auto aiOnnx      = bder->aiOnnxOpset9();
  auto aiGraphcore = bder->aiGraphcoreOpset1();

  // Tensor A
  TensorInfo A_info{"FLOAT", std::vector<int64_t>{K, P, O}};
  std::vector<float> v_A_init(A_info.nelms());
  for (auto &val : v_A_init) {
    val = fdis(eng);
  }
  TensorId A_id =
      bder->addInitializedInputTensor({v_A_init.data(), A_info}, "A");

  // Tensor B
  TensorInfo B_info{"FLOAT", std::vector<int64_t>{K, O, N}};
  std::vector<float> v_B_init(B_info.nelms());
  for (auto &val : v_B_init) {
    val = fdis(eng);
  }
  TensorId B_id =
      bder->addInitializedInputTensor({v_B_init.data(), B_info}, "B");

  // Tensor C
  TensorInfo C_info{"FLOAT", std::vector<int64_t>{K, N, M}};
  std::vector<float> v_C_init(C_info.nelms());
  for (auto &val : v_C_init) {
    val = fdis(eng);
  }
  TensorId C_id =
      bder->addInitializedInputTensor({v_C_init.data(), C_info}, "C");

  TensorId D_id = bder->customOp(
      Onnx::AiOnnx::OpSet11::MatMul, 11, {A_id, B_id}, 1, {}, "MatMul")[0];

  TensorId E_id = bder->customOp(
      Onnx::AiOnnx::OpSet11::MatMul, 11, {D_id, C_id}, 1, {}, "MatMul")[0];

  auto l1            = bder->aiGraphcoreOpset1().l1loss({E_id}, 0.1);
  auto proto         = bder->getModelProto();
  auto modelProto    = io::getModelFromString(proto);
  auto art           = AnchorReturnType("All");
  int batchesPerStep = 1;
  auto dataFlow      = DataFlow(batchesPerStep, {{B_id, art}});

  std::map<popart::TensorId, popart::IArray &> inputs  = {};
  std::map<popart::TensorId, popart::IArray &> anchors = {};

  auto optimizer = popart::ConstSGD(0.01f);

  auto opts = SessionOptions();
  // Disable outlining
  opts.enableOutlining = false;

  auto patterns = popart::Patterns(PatternsLevel::Default);
  // Disable inplacing since this could affect the scheduler
  patterns.enableInPlace(false);

  auto device = createTestDevice(TEST_TARGET);
  auto session =
      popart::TrainingSession::createFromOnnxModel(proto,
                                                   dataFlow,
                                                   l1,
                                                   optimizer,
                                                   device,
                                                   popart::InputShapeInfo(),
                                                   opts,
                                                   patterns);
  session->prepareDevice();
  popart::StepIO stepio(inputs, anchors);

  // Verify schedule order
  auto schedule = session->getIr().getMainGraph().getOpSchedule(
      {}, RequireOptimalSchedule::Yes);

  auto schedulePosition = [&](Op *op) {
    return std::distance(schedule.begin(),
                         std::find(schedule.begin(), schedule.end(), op));
  };

  // Check that the schedule is tight: No early transposes or reshapes
  for (int64_t i = 0; i < schedule.size(); ++i) {
    Op *op = schedule.at(i);
    for (auto &kv : op->input->tensorMap()) {
      if (kv.second->hasProducer()) {
        Op *producer     = kv.second->getProducer();
        int64_t pos      = schedulePosition(producer);
        int64_t distance = i - pos;
        logging::trace("Distance producer-consumer: {} ({}-{})",
                       distance,
                       producer->debugName(),
                       op->debugName());
        if (producer->isConvertibleTo<ReshapeBaseOp>() ||
            producer->isConvertibleTo<TransposeBaseOp>()) {
          // All ReshapeOp & TransposeOp as tight to their consumers as possible
          BOOST_CHECK(distance <= 2);
        }
        // All distances lower than or equal to 8
        BOOST_CHECK(distance <= 8);
      }
    }
  }
}


#include <boost/geometry.hpp>
#include <boost/geometry/geometries/register/point.hpp>
#include <boost/geometry/index/rtree.hpp>
#include <limits>
#include "m1.h"
#include "StreetsDatabaseAPI.h"
#include "OSMDatabaseAPI.h"
#include <math.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include "graphics.h"
#include "iterator"
#include "m3.h"
#include <thread>
#include "global.h"

const double INF = 99999;

global globalVar;
namespace bg = boost::geometry;
namespace bgi = boost::geometry::index;

double maxlat;
double minlat;
double maxlon;
double minlon;
double xmin;
double xmax;
double ymin;
double ymax;
t_point LatLon_to_real_XY1(LatLon & position);
vector<LatLon> wayToNodes(unsigned wayID);
std::vector<double> find_landmarks_to_all_ints_cost(const unsigned intersect_id_start,
        const double turn_penalty);
std::vector<double> find_ints_to_all_landmarks_cost(const unsigned intersect_id_start,
        const double turn_penalty);
void setScale();

extern void highlight_intersection(unsigned intersection_id);

// Declaring the structure for the r-tree

// cite from stack-over-flow:
// https://stackoverflow.com/questions/42182537/how-can-i-use-the-rtree-of-the-boost-library-in-c?rq=1
// author: founder of boost library
// Date: 2011

struct MyLatLon {

    MyLatLon() {
    }

    MyLatLon(double lat_, double lon_) : ll(lat_, lon_) {
    }

    double get_lat() const {
        return ll.lat();
    }

    double get_lon() const {
        return ll.lon();
    }

    void set_lat(float v) {
        ll = LatLon(v, ll.lon());
    }

    void set_lon(float v) {
        ll = LatLon(ll.lat(), v);
    }

    LatLon ll;
};

// Define the data stored in r-tree
BOOST_GEOMETRY_REGISTER_POINT_2D_GET_SET(MyLatLon, double,
        bg::cs::spherical_equatorial<bg::degree>,
        get_lon, get_lat, set_lon, set_lat)
// Creating 2 r-trees for intersections and points of interests
typedef std::pair<MyLatLon, unsigned> point_pair;
bgi::rtree<point_pair, bgi::quadratic < 16 >> int_tree;
bgi::rtree<point_pair, bgi::quadratic < 16 >> interest_tree;
// pair the data for r-tree

///   End of citation

double polygonArea(unsigned featureID);
int OSMIDToWayIndex(OSMID osmid);
int OSMIDToNodeIndex(OSMID osmid);
int OSMIDToRelationIndex(OSMID osmid);

bool load_map(std::string map_path) {

    //reset max and min
    xmin = 999;
    xmax = -999;
    ymin = 999;
    ymax = -999;
    maxlat = -999;
    minlat = 999;
    maxlon = -999;
    minlon = 999;

    //Indicates whether the map has loaded
    globalVar.OSMpath = map_path.substr(0, map_path.size() - 11).append("osm.bin");

    globalVar.load_successful = loadStreetsDatabaseBIN(map_path);
    if (!globalVar.load_successful) return false;
    //successfully
    //Make sure this is updated to reflect whether

    //Load the map database

    loadOSMDatabaseBIN(globalVar.OSMpath);
    // Getting max and min latitude of a map

    //Now build the new street segments vector
    for (unsigned i = 0; i < getNumberOfStreetSegments(); i++) {

        //create a new vector
        Street_Seg newSS;
        if (getStreetSegmentInfo(i).speedLimit > globalVar.max_speed)
            globalVar.max_speed = getStreetSegmentInfo(i).speedLimit / 3.6;
        newSS.length = globalVar.find_Length(i);
        newSS.weight = newSS.length * 3.6 / getStreetSegmentInfo(i).speedLimit;

        globalVar.seg_weight.push_back(newSS.length * 3.6 / getStreetSegmentInfo(i).speedLimit);

        //insert the new street segment structure into vector
        globalVar.ssArray.push_back(newSS);

        globalVar.seg_street_ID.push_back(getStreetSegmentInfo(i).streetID);

    }

    // cout << globalVar.max_speed << endl;

    //build street vector
    //first create a list of empty streets
    for (unsigned i = 0; i < getNumberOfStreets(); i++) {
        Street newS;
        newS.length = 0.0;
        globalVar.s_id_array.push_back(newS);
    }

    for (unsigned wayIndex = 0; wayIndex < getNumberOfWays(); wayIndex++) {
        const OSMWay* temp = getWayByIndex(wayIndex);
        pair<OSMID, unsigned> way(temp->id(), wayIndex);
        globalVar.OSMIDToWayIndex.insert(way);
    }

    for (unsigned nodeIndex = 0; nodeIndex < getNumberOfNodes(); nodeIndex++) {
        const OSMNode* temp = getNodeByIndex(nodeIndex);
        pair<OSMID, unsigned> node(temp->id(), nodeIndex);
        globalVar.OSMIDToNodeIndex.insert(node);
    }

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

        if (getIntersectionPosition(i).lat() > maxlat)
            maxlat = getIntersectionPosition(i).lat();

        if (getIntersectionPosition(i).lat() < minlat)
            minlat = getIntersectionPosition(i).lat();

        if (getIntersectionPosition(i).lon() > maxlon)
            maxlon = getIntersectionPosition(i).lon();

        if (getIntersectionPosition(i).lon() < minlon)
            minlon = getIntersectionPosition(i).lon();

    }
    globalVar.latavg = (maxlat + minlat) / 2;
    setScale();

    //for the inner loop to sort the most selected

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

        double x = DEG_TO_RAD * getIntersectionPosition(i).lon() * cos(DEG_TO_RAD * globalVar.latavg);
        double y = DEG_TO_RAD * getIntersectionPosition(i).lat();
        //Store data into the r-tree for intersections
        double pos[2] = {getIntersectionPosition(i).lat(), getIntersectionPosition(i).lon()};
        int_tree.insert(std::make_pair(MyLatLon(pos[0], pos[1]), i));

        xmax = max(xmax, x);
        xmin = min(xmin, x);
        ymin = min(ymin, y);
        ymax = max(ymax, y);

        //Now build the intersections vector
        Intersection newIn;
        unsigned num = getIntersectionStreetSegmentCount(i);
        vector<unsigned> ssids;
        vector<unsigned> intints;
        vector<unsigned> validseg;
        vector<unsigned> seg_street_ID;
        vector<double> weight;

        vector<unsigned> intints_nodup;
        vector<unsigned> validseg_nodup;
        vector<unsigned> seg_street_ID_nodup;
        vector<double> weight_nodup;

        vector<unsigned> validseg_rev;
        vector<unsigned> seg_street_ID_rev;
        vector<double> weight_rev;
        vector<unsigned> intints_rev;

        vector<unsigned>::iterator it;

        for (unsigned j = 0; j < num; j++) {
            unsigned newSS = getIntersectionStreetSegment(i, j);
            newIn.ss_ids.push_back(newSS);
            ssids.push_back(newSS);

            //find which intersection can directly go to
            if (i == getStreetSegmentInfo(newSS).from) {

                newIn.weight.push_back(globalVar.ssArray[newSS].weight);
                newIn.in_ids.push_back(getStreetSegmentInfo(newSS).to);
                newIn.valid_seg.push_back(newSS);

                validseg.push_back(newSS);
                seg_street_ID.push_back(getStreetSegmentInfo(newSS).streetID);
                intints.push_back(getStreetSegmentInfo(newSS).to);
                weight.push_back(globalVar.ssArray[newSS].weight);

                it = find(intints_nodup.begin(), intints_nodup.end(), getStreetSegmentInfo(newSS).to);
                //No duplicated intersection found
                if (it == intints_nodup.end()) {
                    intints_nodup.push_back(getStreetSegmentInfo(newSS).to);
                    validseg_nodup.push_back(newSS);
                    seg_street_ID_nodup.push_back(getStreetSegmentInfo(newSS).streetID);
                    weight_nodup.push_back(globalVar.ssArray[newSS].weight);

                }                    //There is duplicated intersection, so update the one to have the
                    //fastest street segment
                else {
                    unsigned index = distance(intints_nodup.begin(), it);

                    if (weight_nodup[index] > globalVar.ssArray[newSS].weight) {
                        weight_nodup[index] = globalVar.ssArray[newSS].weight;
                        validseg_nodup[index] = newSS;
                        seg_street_ID_nodup.push_back(getStreetSegmentInfo(newSS).streetID);

                    }
                }

            } else if (i == getStreetSegmentInfo(newSS).to && !getStreetSegmentInfo(newSS).oneWay) {
                newIn.weight.push_back(globalVar.ssArray[newSS].weight);
                newIn.in_ids.push_back(getStreetSegmentInfo(newSS).from);
                newIn.valid_seg.push_back(newSS);

                validseg.push_back(newSS);
                seg_street_ID.push_back(getStreetSegmentInfo(newSS).streetID);
                intints.push_back(getStreetSegmentInfo(newSS).from);
                weight.push_back(globalVar.ssArray[newSS].weight);

                it = find(intints_nodup.begin(), intints_nodup.end(), getStreetSegmentInfo(newSS).from);
                //No duplicated intersection found
                if (it == intints_nodup.end()) {
                    intints_nodup.push_back(getStreetSegmentInfo(newSS).from);
                    validseg_nodup.push_back(newSS);
                    seg_street_ID_nodup.push_back(getStreetSegmentInfo(newSS).streetID);
                    weight_nodup.push_back(globalVar.ssArray[newSS].weight);

                }//There is duplicated intersection, so update the one to have the
                    //fastest street segment
                else {
                    unsigned index = distance(intints_nodup.begin(), it);

                    if (weight_nodup[index] > globalVar.ssArray[newSS].weight) {
                        weight_nodup[index] = globalVar.ssArray[newSS].weight;
                        seg_street_ID_nodup.push_back(getStreetSegmentInfo(newSS).streetID);
                        validseg_nodup[index] = newSS;
                    }
                }

            }

            if (i == getStreetSegmentInfo(newSS).to) {
                validseg_rev.push_back(newSS);
                seg_street_ID_rev.push_back(getStreetSegmentInfo(newSS).streetID);
                intints_rev.push_back(getStreetSegmentInfo(newSS).from);
                weight_rev.push_back(globalVar.ssArray[newSS].weight);

            } else if (i == getStreetSegmentInfo(newSS).from && !getStreetSegmentInfo(newSS).oneWay) {

                validseg_rev.push_back(newSS);
                seg_street_ID_rev.push_back(getStreetSegmentInfo(newSS).streetID);
                intints_rev.push_back(getStreetSegmentInfo(newSS).to);
                weight_rev.push_back(globalVar.ssArray[newSS].weight);

            }

            unsigned newS = getStreetSegmentInfo(newSS).streetID;
            newIn.s_ids.push_back(newS);
            newIn.s_names.insert(getStreetName(newS));
            newIn.x = x;
            newIn.y = y;
        }
        /****************Store intersections to intersections related information******/
        globalVar.siArray.push_back(newIn);
        globalVar.int_intids.push_back(intints);
        globalVar.int_ssid.push_back(ssids);
        globalVar.int_valid_seg.push_back(validseg);
        globalVar.int_seg_street_ID.push_back(seg_street_ID);
        globalVar.int_weight.push_back(weight);

        /****************Store intersections to intersections, with no duplications****/
        globalVar.int_intids_nodup.push_back(intints_nodup);
        globalVar.int_ssid_nodup.push_back(validseg_nodup);
        globalVar.int_seg_street_ID_nodup.push_back(seg_street_ID_nodup);
        globalVar.int_weight_nodup.push_back(weight_nodup);

        /********Store the intersections to invalid intersections related information**/
        globalVar.int_intids_rev.push_back(intints_rev);
        globalVar.int_valid_seg_rev.push_back(validseg_rev);
        globalVar.int_seg_street_ID_rev.push_back(seg_street_ID_rev);
        globalVar.int_weight_rev.push_back(weight_rev);

        /******************************************************************************/
        //Store related intersections ID array into street ID
        for (unsigned j = 0; j < globalVar.siArray[i].s_ids.size(); j++) {

            globalVar.s_id_array[globalVar.siArray[i].s_ids[j]].intersection_ids.insert(i);

        }
    }

    globalVar.int_shortest_segment.resize(getNumberOfIntersections());

    for (unsigned intFrom = 0; intFrom < getNumberOfIntersections(); intFrom++) {

        vector<unsigned> valid_intersections = globalVar.int_intids[intFrom];
        int num_of_intTo = valid_intersections.size();

        globalVar.int_shortest_segment[intFrom].resize(num_of_intTo);

        vector<unsigned> valid_segments = globalVar.int_valid_seg[intFrom];
        //Traversing "To" and "To" for nested loop, and

        for (int validTo_index = 0; validTo_index < num_of_intTo; validTo_index++) {

            //intersection ID "TO"
            unsigned intTo = valid_intersections[validTo_index];
            double selected_cost = 100000;
            int shortest_segID = -1;

            for (unsigned validSeg_index = 0; validSeg_index < valid_segments.size(); validSeg_index++) {

                StreetSegmentInfo info = getStreetSegmentInfo(valid_segments[validSeg_index]);

                if (info.oneWay && (info.to != intTo)) {

                    continue;
                } else if (info.to == intTo || info.from == intTo) {

                    //store current segment cost
                    double current_cost = globalVar.int_weight[intFrom][validSeg_index];

                    if (current_cost < selected_cost) {

                        shortest_segID = valid_segments[validSeg_index];
                        selected_cost = current_cost;

                    }

                }

            }
            globalVar.int_shortest_segment[intFrom][validTo_index] = shortest_segID;

        }

    }

    globalVar.int_shortest_segment_rev.resize(getNumberOfIntersections());

    for (unsigned intFrom = 0; intFrom < getNumberOfIntersections(); intFrom++) {

        vector<unsigned> valid_intersections = globalVar.int_intids_rev[intFrom];
        int num_of_intTo = valid_intersections.size();

        globalVar.int_shortest_segment_rev[intFrom].resize(num_of_intTo);

        vector<unsigned> valid_segments = globalVar.int_valid_seg_rev[intFrom];
        //Traversing "To" and "To" for nested loop, and

        for (int validTo_index = 0; validTo_index < num_of_intTo; validTo_index++) {

            //intersection ID "TO"
            unsigned intTo = valid_intersections[validTo_index];
            double selected_cost = 100000;
            int shortest_segID = -1;

            for (unsigned validSeg_index = 0; validSeg_index < valid_segments.size(); validSeg_index++) {

                StreetSegmentInfo info = getStreetSegmentInfo(valid_segments[validSeg_index]);

                if (info.oneWay && (info.from != intTo)) {

                    continue;
                } else if (info.to == intTo || info.from == intTo) {

                    //store current segment cost
                    double current_cost = globalVar.int_weight_rev[intFrom][validSeg_index];

                    if (current_cost < selected_cost) {

                        shortest_segID = valid_segments[validSeg_index];
                        selected_cost = current_cost;

                    }

                }

            }
            globalVar.int_shortest_segment_rev[intFrom][validTo_index] = shortest_segID;

        }

    }

    vector<unsigned> landmarks_ID(LANDMARKS_NUM, 0);

    //Find the cost from every landmark to each point
    //Store the random points
    for (int num = 0; num < LANDMARKS_NUM; num++) {
        unsigned random_intersection_index = rand() % (getNumberOfIntersections() - 1);

        // highlight_intersection(random_intersection_index);

        landmarks_ID[num] = random_intersection_index;

        vector<double> G_Value = find_landmarks_to_all_ints_cost(random_intersection_index, 0);

        globalVar.landmarks_to_int.push_back(G_Value);

    }

    for (int num = 0; num < LANDMARKS_NUM; num++) {

        vector<double> G_Value = find_ints_to_all_landmarks_cost(landmarks_ID[num], 0);

        globalVar.int_to_landmarks.push_back(G_Value);

    }

    /**************storing intersections with "&" and without *********************/
    /**************"<unknown>" for fuzzy search************************************/
    for (unsigned num = 0; num < getNumberOfIntersections(); num++) {

        if ((getIntersectionName(num).find(" & ") != string::npos)
                && (getIntersectionName(num).find("<unknown>") == string::npos)) {

            globalVar.intersectionName_fuzzy.insert(getIntersectionName(num));

        }
    }

    /****************structure used to combine points of interests*****************/
    /*********************and street names for fuzzy search************************/

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

        globalVar.street_pointOfInterest_names_fuzzy_only.insert(getStreetName(i));
    }

    for (unsigned i = 0; i < getNumberOfPointsOfInterest(); i++) {
        globalVar.street_pointOfInterest_names_fuzzy_only.insert(getPointOfInterestName(i));
    }

    for (unsigned i = 0; i < getNumberOfPointsOfInterest(); i++) {
        globalVar.pointOfInterest_intersection_name_fuzzy_only.insert(getPointOfInterestName(i));
    }

    for (unsigned i = 0; i < getNumberOfIntersections(); i++) {
        globalVar.pointOfInterest_intersection_name_fuzzy_only.insert(getIntersectionName(i));
    }

    /********************Now build the street vector.******************************/
    /***************Store street segments ID and street name***********************/

    for (unsigned i = 0; i < getNumberOfStreetSegments(); i++) {
        unsigned currentS = getStreetSegmentInfo(i).streetID;
        globalVar.s_id_array[currentS].name = getStreetName(currentS);
        //add current street segment into street
        globalVar.s_id_array[currentS].street_segment_ids.push_back(i);

    }

    //after loading the street id array
    //we need to calculate its length
    for (unsigned i = 0; i < globalVar.s_id_array.size(); i++) {
        for (unsigned j = 0; j < globalVar.s_id_array[i].street_segment_ids.size();
                j++) {
            globalVar.s_id_array[i].length += globalVar.ssArray[globalVar.s_id_array[i].street_segment_ids[j]].length;
        }
    }

    //Store data into the r-tree for points of interests
    for (unsigned j = 0; j < getNumberOfPointsOfInterest(); j++) {
        double pos[2] = {DEG_TO_RAD * getPointOfInterestPosition(j).
            lon() * cos(DEG_TO_RAD * globalVar.latavg), DEG_TO_RAD * getPointOfInterestPosition(j).lat()};
        interest_tree.insert(std::make_pair(MyLatLon(pos[0], pos[1]), j));
    }

    //Build an unordered map to use street name to access street_ID
    std::unordered_map<std::string, set<unsigned> > ::iterator it;
    std::unordered_map<std::string, vector<unsigned> > ::iterator it1;
    for (unsigned i = 0; i < getNumberOfStreets(); i++) {

        it1 = globalVar.streetName_to_streetID.find(getStreetName(i));
        if (it1 == globalVar.streetName_to_streetID.end()) {

            pair<string, vector<unsigned> >street(getStreetName(i), {
                i
            });
            globalVar.streetName_to_streetID.insert(street);
        } else {
            it1->second.push_back(i);

        }
    }

    //Build an unordered_map to directly store intersections into street name
    for (unsigned i = 0; i < getNumberOfStreets(); i++) {

        it = globalVar.streetName_to_intersectionsID.find(getStreetName(i));
        if (it == globalVar.streetName_to_intersectionsID.end()) {

            pair<string, set<unsigned> >street(getStreetName(i), globalVar.s_id_array[i].intersection_ids);
            globalVar.streetName_to_intersectionsID.insert(street);
        } else {
            it->second.insert(globalVar.s_id_array[i].intersection_ids.begin(), globalVar.s_id_array[i].intersection_ids.end());
        }
    }

    for (unsigned id = 0; id < getNumberOfPointsOfInterest(); id++) {

        string poi = getPointOfInterestName(id);
        vector<unsigned> poiInfo(2);
        poiInfo[0] = id;
        poiInfo[1] = find_closest_intersection(getPointOfInterestPosition(id));
        globalVar.POIName.insert(make_pair(poi, poiInfo));
    }

    ////////////////////////////////Weighted Direct Matrix///////////////////////////

    //resize the 2d vector
    int n = getNumberOfIntersections();
    globalVar.weightedMatrix = new double*[n];
    for (int i = 0; i < n; i++) {
        globalVar.weightedMatrix[i] = new double[n];
    }

    //Make sure this is updated to reflect whether
    //loading the map succeeded or failed

    return globalVar.load_successful;
}

void close_map() {
    //Clean-up your map related data structures here
    if (globalVar.load_successful) {
        globalVar.ssArray.clear();
        globalVar.s_id_array.clear();
        globalVar.siArray.clear();
        globalVar.streetName_to_intersectionsID.clear();
        globalVar.streetName_to_streetID.clear();
        globalVar.OSMIDToWayIndex.clear();
        globalVar.OSMIDToNodeIndex.clear();
        globalVar.OSMIDToRelationIndex.clear();
        globalVar.areaID.clear();
        globalVar.featureID.clear();
        globalVar.hospital.clear();
        globalVar.metroStations.clear();
        globalVar.subwayStations.clear();
        globalVar.subwayWayIndex.clear();
        globalVar.metro.clear();
        globalVar.metroColor.clear();
        globalVar.platinumSegment.clear();
        globalVar.goldSegment.clear();
        globalVar.silverSegment.clear();
        globalVar.restaurant.clear();
        globalVar.restaurantID.clear();
        globalVar.fuelstation.clear();
        globalVar.hospitalID.clear();
        globalVar.POIName.clear();
        globalVar.regularSegment.clear();
        globalVar.minorSegment.clear();
        globalVar.alreadyDrewHighwayTextPos.clear();
        globalVar.alreadyDrewTextPos.clear();
        globalVar.bank.clear();
        globalVar.bankID.clear();
        globalVar.edu.clear();
        globalVar.eduID.clear();
        globalVar.naviRoute_seg.clear();
        globalVar.turn_by_turn.clear();
        globalVar.dongnanxibei.clear();
        globalVar.int_intids.clear();
        globalVar.int_intids_nodup.clear();
        globalVar.int_ssid.clear();
        globalVar.int_ssid_nodup.clear();
        globalVar.int_valid_seg.clear();
        globalVar.int_weight.clear();
        globalVar.int_weight_nodup.clear();
        globalVar.draw_turn.clear();
        globalVar.draw_dongnanxibei.clear();
        globalVar.draw_street_seg.clear();
        globalVar.move_distance.clear();
        globalVar.landmarks_to_int.clear();
        globalVar.int_to_landmarks.clear();
        globalVar.int_intids_rev.clear();
        globalVar.seg_street_ID.clear();
        globalVar.int_seg_street_ID_rev.clear();
        globalVar.int_shortest_segment_rev.clear();
        globalVar.int_seg_street_ID.clear();
        globalVar.int_seg_street_ID_nodup.clear();
        globalVar.int_valid_seg_rev.clear();
        globalVar.int_weight_rev.clear();
        globalVar.areaFeatures.clear();
        closeStreetDatabase();
        closeOSMDatabase();

    }
}

//Returns street id(s) for the given street name
//If no street with this name exists, returns a 0-length vector.

std::vector<unsigned> find_street_ids_from_name(std::string street_name) {
    //declare a street unordered_map iterator
    std::unordered_map <std::string, vector<unsigned> >::iterator itr;

    itr = globalVar.streetName_to_streetID.find(street_name);
    if (itr != globalVar.streetName_to_streetID.end()) {
        return itr -> second;
    } else {
        vector<unsigned> notfind;
        return notfind;
    }
}

//Returns the street segments for the given intersection

std::vector<unsigned> find_intersection_street_segments(unsigned intersection_id) {

    return globalVar.siArray[intersection_id].ss_ids;

}

//Returns the street names at the given intersection (includes duplicate street
//names in returned vector)

std::vector<std::string> find_intersection_street_names(unsigned intersection_id) {
    std::vector<std::string> s_names;

    for (unsigned i = 0; i < globalVar.siArray[intersection_id].s_ids.size(); i++) {
        s_names.push_back(getStreetName(globalVar.siArray[intersection_id].s_ids[i]));
    }

    return s_names;
}

//Returns true if you can get from intersection1 to intersection2 using a single
//street segment (hint: check for 1-way streets too)
//corner case: an intersection is considered to be connected to itself

bool are_directly_connected(unsigned intersection_id1, unsigned intersection_id2) {

    unsigned num = getIntersectionStreetSegmentCount(intersection_id1);

    // get the segments from first intersection
    for (unsigned i = 0; i < num; i++) {
        StreetSegmentIndex newS = getIntersectionStreetSegment(intersection_id1, i);
        if (getStreetSegmentInfo(newS).oneWay) {
            if (intersection_id2 ==
                    getStreetSegmentInfo(newS).to)
                return true;
        } else {
            if (intersection_id2 ==
                    getStreetSegmentInfo(newS).to
                    || intersection_id2 ==
                    getStreetSegmentInfo(newS).from)

                return true;
        }
    }

    return false;
}

//Returns all intersections reachable by traveling down one street segment
//from given intersection (hint: you can't travel the wrong way on a 1-way street)
//the returned vector should NOT contain duplicate intersections

std::vector<unsigned> find_adjacent_intersections(unsigned intersection_id) {

    std::vector<unsigned> in_ids;
    unsigned num = getIntersectionStreetSegmentCount(intersection_id);

    for (unsigned i = 0; i < num; i++) {
        StreetSegmentIndex newS = getIntersectionStreetSegment(intersection_id, i);
        if (intersection_id == getStreetSegmentInfo(newS).from) {
            in_ids.push_back(getStreetSegmentInfo(newS).to);

        } else {

            if (!getStreetSegmentInfo(newS).oneWay) {
                in_ids.push_back(getStreetSegmentInfo(newS).from);
            }
        }

    }
    sort(in_ids.begin(), in_ids.end());
    in_ids.erase(unique(in_ids.begin(), in_ids.end()), in_ids.end());

    return in_ids;
}

//Returns all street segments for the given street

std::vector<unsigned> find_street_street_segments(unsigned street_id) {

    return globalVar.s_id_array[street_id].street_segment_ids;
}

//Returns all intersections along the given street

std::vector<unsigned> find_all_street_intersections(unsigned street_id) {

    std::vector<unsigned> in_ids;
    for (unsigned i = 0; i < globalVar.s_id_array[street_id].street_segment_ids.size(); i++) {
        unsigned a = globalVar.s_id_array[street_id].street_segment_ids[i];
        in_ids.push_back(getStreetSegmentInfo(a).from);
        in_ids.push_back(getStreetSegmentInfo(a).to);
    }

    sort(in_ids.begin(), in_ids.end());
    in_ids.erase(unique(in_ids.begin(), in_ids.end()), in_ids.end());

    return in_ids;
}

//Return all intersection ids for two intersecting streets
//This function will typically return one intersection id.
//However street names are not guaranteed to be unique, so more than 1 intersection id
//may exist

std::vector<unsigned> find_intersection_ids_from_street_names(std::string street_name1,
        std::string street_name2) {

    std::vector<unsigned> in_ids;
    std::set<unsigned> street1_ids;
    std::set<unsigned> street2_ids;
    std::set<unsigned>::iterator it1;
    std::set<unsigned>::iterator it2;

    //reconstructed, added the case where one of the street name does not exist
    if (globalVar.streetName_to_intersectionsID.find(street_name1) !=
            globalVar.streetName_to_intersectionsID.end()) {
        street1_ids = globalVar.streetName_to_intersectionsID.find(street_name1)->second;
    } else {
        return in_ids;
    }

    if (globalVar.streetName_to_intersectionsID.find(street_name2)
            != globalVar.streetName_to_intersectionsID.end()) {
        street2_ids = globalVar.streetName_to_intersectionsID.find(street_name2)->second;
    } else {
        return in_ids;
    }

    for (it1 = street1_ids.begin(); it1 != street1_ids.end(); it1++) {
        for (it2 = street2_ids.begin(); it2 != street2_ids.end(); it2++) {
            if (*it1 == *it2)
                in_ids.push_back(*it1);

        }

    }

    return in_ids;
}

//Returns the distance between two coordinates in meters

double find_distance_between_two_points(LatLon point1, LatLon point2) {
    double distance = 0.0; // initialization
    // acquire coordinates
    double x_point1 = DEG_TO_RAD * point1.lon() *
            cos(DEG_TO_RAD * (point1.lat() / 2 + point2.lat() / 2));
    double x_point2 = DEG_TO_RAD * point2.lon() *
            cos(DEG_TO_RAD * (point1.lat() / 2 + point2.lat() / 2));
    // calculate distance
    distance = EARTH_RADIUS_IN_METERS * sqrt(DEG_TO_RAD *
            (point1.lat() - point2.lat()) * DEG_TO_RAD *
            (point1.lat() - point2.lat())+ (x_point1 - x_point2)
            *(x_point1 - x_point2));

    return distance;
}

//Returns the length of the given street segment in meters

double find_street_segment_length(unsigned street_segment_id) {

    return globalVar.ssArray[street_segment_id].length;
}

//Returns the length of the specified street in meters

double find_street_length(unsigned street_id) {

    return globalVar.s_id_array[street_id].length;
}

//Returns the travel time to drive a street segment in seconds
//(time = distance/speed_limit)

double find_street_segment_travel_time(unsigned street_segment_id) {

    return globalVar.ssArray[street_segment_id].weight;
}

//Returns the nearest point of interest to the given position

unsigned find_closest_point_of_interest(LatLon my_position) {
    double pos[2] = {DEG_TO_RAD * my_position.lon() * cos(DEG_TO_RAD * globalVar.latavg), DEG_TO_RAD * my_position.lat()};

    std::vector<point_pair> result2;
    interest_tree.query(bgi::nearest(MyLatLon(pos[0], pos[1]), 1), std::back_inserter(result2));
    return result2[0].second;
}

//Returns the the nearest intersection to the given position

unsigned find_closest_intersection(LatLon my_position) {

    double pos[2] = {my_position.lat(), my_position.lon()};

    std::vector<point_pair> result2;
    int_tree.query(bgi::nearest(MyLatLon(pos[0], pos[1]), 1), std::back_inserter(result2));

    return result2[0].second;

}

int OSMIDToWayIndex(OSMID osmid) {
    unordered_map<OSMID, unsigned>::iterator it = globalVar.OSMIDToWayIndex.find(osmid);
    if (it == globalVar.OSMIDToWayIndex.end()) {
        return -1;
    }
    return it->second;
}

int OSMIDToNodeIndex(OSMID osmid) {
    unordered_map<OSMID, unsigned>::iterator it = globalVar.OSMIDToNodeIndex.find(osmid);
    if (it == globalVar.OSMIDToNodeIndex.end()) {
        return -1;
    }
    return it->second;
}

int OSMIDToRelationIndex(OSMID osmid) {
    unordered_map<OSMID, unsigned>::iterator it = globalVar.OSMIDToRelationIndex.find(osmid);
    if (it == globalVar.OSMIDToRelationIndex.end()) {
        return -1;
    }
    return it->second;
}

double polygonArea(unsigned featureID) {
    double area = 0;
    unsigned j = getFeaturePointCount(featureID) - 1;

    for (unsigned i = 0; i < getFeaturePointCount(featureID); i++) {
        area = area + (getFeaturePoint(featureID, j).lon() + getFeaturePoint(featureID, i).lon())*
                (getFeaturePoint(featureID, j).lat() - getFeaturePoint(featureID, i).lat());
        j = i;
    }

    return abs(area);
}

t_point LatLon_to_real_XY1(LatLon & position) {
    t_point pt;
    pt.x = DEG_TO_RAD * position.lon() * cos(DEG_TO_RAD * globalVar.latavg);
    pt.y = DEG_TO_RAD * position.lat();
    return pt;
}

vector<LatLon> wayToNodes(unsigned wayID) {
    const OSMWay* tempWay = getWayByIndex(wayID);
    vector<OSMID> Node_refs;
    vector<OSMID> tempRefs = tempWay->ndrefs();

    vector<LatLon> LatLonVector(tempWay->ndrefs().size());

    for (unsigned i = 0; i < tempWay->ndrefs().size(); ++i) {
        unsigned NodeIndex = OSMIDToNodeIndex(tempRefs[i]);
        const OSMNode* tempNode = getNodeByIndex(NodeIndex);

        LatLonVector[i] = tempNode->coords();
    }
    return LatLonVector;
}

void setScale() {
    globalVar.x_min = DEG_TO_RAD * minlon * cos(DEG_TO_RAD * globalVar.latavg);
    globalVar.y_min = DEG_TO_RAD * maxlat;
    globalVar.x_max = DEG_TO_RAD * maxlon * cos(DEG_TO_RAD * globalVar.latavg);
    globalVar.y_max = DEG_TO_RAD * minlat;

    globalVar.x_scale = 1535 / abs(globalVar.x_min - globalVar.x_max);
    globalVar.y_scale = 935 / abs(globalVar.y_min - globalVar.y_max);
}

std::vector<double> find_landmarks_to_all_ints_cost(const unsigned intersect_id_start,
        const double turn_penalty) {
    //to order the intersection and pick the one with smallest
    std::priority_queue<Node, vector<Node>, cmp> openQueue;

    //boost::heap::fibonacci_heap< Node, boost::heap::compare <cmp> > openQueue;

    //Vector to store the current intersection's parent intersection
    std::vector<int> parentInt(getNumberOfIntersections(), -1);

    parentInt[intersect_id_start] = -100;

    std::vector<double> G_Vector(getNumberOfIntersections(), -1);
    G_Vector[intersect_id_start] = 0;

    std::vector<int> parentSeg(getNumberOfIntersections(), -1);

    parentSeg[intersect_id_start] = -100;

    std::vector<bool> closeVector(getNumberOfIntersections(), false);

    //put the starting point position into the open list
    openQueue.push(Node(intersect_id_start, 0));

    while (!openQueue.empty()) {

        IntersectionIndex current_intersection_ID = openQueue.top().intersection_ID;

        if (closeVector[current_intersection_ID] == true) {
            openQueue.pop();
            continue;
        }

        //Delete the intersection ID with lowest F
        openQueue.pop();

        //put the intersection into close Vector
        closeVector[current_intersection_ID] = true;

        //traverse all the valid intersection
        for (unsigned index = 0; index < globalVar.int_valid_seg[current_intersection_ID].size(); ++index) {

            unsigned selected_segment_ID = globalVar.int_valid_seg[current_intersection_ID][index];

            IntersectionIndex potential_intersection_ID = globalVar.int_intids[current_intersection_ID][index];

            if (closeVector[potential_intersection_ID]) {
                continue;
            }

            //value that will be iterated

            //If the current intersection's parent is starting point, then choose the shortest segment,
            //no need to decide turn penalty

            double candidate_G;

            //Then it is necessary to calculate turn penalty

            if (parentInt[current_intersection_ID] != -100) {

                //unsigned prev_street_ID = globalVar.seg_street_ID[parentSeg[current_intersection_ID]];

                candidate_G = G_Vector[current_intersection_ID] + globalVar.ssArray[selected_segment_ID].weight;

                // unsigned current_street_ID = globalVar.int_seg_street_ID[current_intersection_ID][index];

                if (globalVar.seg_street_ID[parentSeg[current_intersection_ID]]
                        != globalVar.int_seg_street_ID[current_intersection_ID][index])
                    candidate_G = candidate_G + turn_penalty;
            } else {

                selected_segment_ID = globalVar.int_shortest_segment[current_intersection_ID][index];

                candidate_G = G_Vector[current_intersection_ID] + globalVar.ssArray[selected_segment_ID].weight;
            }

            if (candidate_G >= G_Vector[potential_intersection_ID] && G_Vector[potential_intersection_ID] != -1)
                continue;

            openQueue.push(Node(potential_intersection_ID, candidate_G));

            //Finally store all the iterative values
            parentInt[potential_intersection_ID] = current_intersection_ID;
            parentSeg[potential_intersection_ID] = selected_segment_ID;
            G_Vector[potential_intersection_ID] = candidate_G;

        }
    }

    return G_Vector;

}

vector<double> find_ints_to_all_landmarks_cost(const unsigned intersect_id_start,
        const double turn_penalty) {

    //to order the intersection and pick the one with smallest
    std::priority_queue<Node, vector<Node>, cmp> openQueue;

    //boost::heap::fibonacci_heap< Node, boost::heap::compare <cmp> > openQueue;

    //Vector to store the current intersection's parent intersection
    std::vector<int> parentInt(getNumberOfIntersections(), -1);

    parentInt[intersect_id_start] = -100;

    std::vector<double> G_Vector(getNumberOfIntersections(), -1);
    G_Vector[intersect_id_start] = 0;

    std::vector<int> parentSeg(getNumberOfIntersections(), -1);

    parentSeg[intersect_id_start] = -100;

    std::vector<bool> closeVector(getNumberOfIntersections(), false);

    //put the starting point position into the open list
    openQueue.push(Node(intersect_id_start, 0));

    while (!openQueue.empty()) {

        IntersectionIndex current_intersection_ID = openQueue.top().intersection_ID;

        if (closeVector[current_intersection_ID] == true) {
            openQueue.pop();
            continue;
        }

        //Delete the intersection ID with lowest F
        openQueue.pop();

        //put the intersection into close Vector
        closeVector[current_intersection_ID] = true;

        //traverse all the valid intersection
        for (unsigned index = 0; index < globalVar.int_valid_seg_rev[current_intersection_ID].size(); ++index) {

            unsigned selected_segment_ID = globalVar.int_valid_seg_rev[current_intersection_ID][index];

            IntersectionIndex potential_intersection_ID = globalVar.int_intids_rev[current_intersection_ID][index];

            if (closeVector[potential_intersection_ID]) {
                continue;
            }

            //value that will be iterated

            //If the current intersection's parent is starting point, then choose the shortest segment,
            //no need to decide turn penalty

            double candidate_G;

            //Then it is necessary to calculate turn penalty

            if (parentInt[current_intersection_ID] != -100) {

                //unsigned prev_street_ID = globalVar.seg_street_ID[parentSeg[current_intersection_ID]];

                candidate_G = G_Vector[current_intersection_ID] + globalVar.ssArray[selected_segment_ID].weight;

                // unsigned current_street_ID = globalVar.int_seg_street_ID[current_intersection_ID][index];

                if (globalVar.seg_street_ID[parentSeg[current_intersection_ID]]
                        != globalVar.int_seg_street_ID_rev[current_intersection_ID][index])
                    candidate_G = candidate_G + turn_penalty;
            } else {

                selected_segment_ID = globalVar.int_shortest_segment_rev[current_intersection_ID][index];

                candidate_G = G_Vector[current_intersection_ID] + globalVar.ssArray[selected_segment_ID].weight;

            }

            if (candidate_G >= G_Vector[potential_intersection_ID] && G_Vector[potential_intersection_ID] != -1)
                continue;

            openQueue.push(Node(potential_intersection_ID, candidate_G));

            //Finally store all the iterative values
            parentInt[potential_intersection_ID] = current_intersection_ID;
            parentSeg[potential_intersection_ID] = selected_segment_ID;
            G_Vector[potential_intersection_ID] = candidate_G;

        }

    }

    return G_Vector;
}


/*
    Copyright 2013 Adobe
    Distributed under the Boost Software License, Version 1.0.
    (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
/*************************************************************************************************/

#include <adobe/config.hpp>
#include <adobe/md5.hpp>

#include <boost/filesystem/path.hpp>
#include <boost/version.hpp>

#include <iostream>
#include <fstream>

/****************************************************************************************************/

int main(int argc, char* argv[]) {
    if (argc <= 1) {
        std::cout << "usage: " << argv[0] << " [ file ]" << std::endl;
        std::cout << "       generate the MD5 hash of a file" << std::endl;
        std::cout << "       Adobe Source Libraries v" << ADOBE_VERSION_MAJOR << "."
                  << ADOBE_VERSION_MINOR << "." << ADOBE_VERSION_SUBMINOR << std::endl;
        std::cout << "       Boost v" << BOOST_VERSION / 100000 << "." << BOOST_VERSION / 100 % 1000
                  << "." << BOOST_VERSION % 100 << std::endl;

        return 1;
    }

    bool success(false);

    try {
        adobe::md5_t m;
        boost::filesystem::path file_path(argv[1], boost::filesystem::native);
        std::ifstream stream(file_path.native_file_string().c_str(),
                             std::ios::binary | std::ios::in);

        while (stream.good()) {
            boost::array<std::ifstream::char_type, 256 * 1024> buffer;

            stream.read(&buffer[0], static_cast<std::streamsize>(buffer.size()));

            std::streamsize gcount(stream.gcount());

            if (gcount > 0)
                m.update(&buffer[0], static_cast<std::size_t>(gcount));
        }

        adobe::md5_t::digest_t hash(m.final());
        adobe::md5_t::digest_t::iterator first(hash.begin());
        adobe::md5_t::digest_t::iterator last(hash.end());

        std::cout << "MD5(" << argv[1] << ")= ";

        for (; first != last; ++first) {
            std::cout.width(2);
            std::cout.fill('0');
            std::cout << std::hex << static_cast<int>(*first);
        }

        std::cout << std::endl;

        success = true;
    }
    catch (const std::exception& error) {
        std::cerr << "Exception: " << error.what() << std::endl;
    }
    catch (...) {
        std::cerr << "Unknown exception" << std::endl;
    }

    return success ? 0 : 1;
}


#include "ramp.h"

#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstddef>

#include <boost/algorithm/clamp.hpp>

#include "../shader_core/lerp.h"

csg::ColorRamp::ColorRamp()
{
	// Set a default value mapping from black to white
	points.push_back(ColorRampPoint{ 0.0f, csc::Float3{ 0.0f, 0.0f, 0.0f }, 1.0f });
	points.push_back(ColorRampPoint{ 1.0f, csc::Float3{ 1.0f, 1.0f, 1.0f }, 1.0f });
	sort_points();
}

csg::ColorRamp::ColorRamp(const std::vector<ColorRampPoint>& points) : points{ points }
{
	assert(points.size() >= 2);
	sort_points();
}

csc::Float4 csg::ColorRamp::eval(const float pos) const
{
	// For speed, assume the vector is already sorted
	assert(points.size() >= 2);

	// If the pos is outside our control points, extend the boundary color
	const float pos_begin{ points[0].pos };
	if (pos <= pos_begin) {
		return csc::Float4{ points[0].color, points[0].alpha };
	}
	const float pos_end{ points[points.size() - 1].pos };
	if (pos >= pos_end) {
		return csc::Float4{ points[points.size() - 1].color, points[points.size() - 1].alpha };
	}

	// Find the bounding points
	// We know that a pos both before and after the input position must exist
	csg::ColorRampPoint point_before{ points[0] };
	csg::ColorRampPoint point_after{ points[points.size() - 1] };
	for (const csg::ColorRampPoint& this_point : points) {
		if (this_point.pos > point_before.pos && this_point.pos < pos) {
			point_before = this_point;
		}
		if (this_point.pos < point_after.pos && this_point.pos > pos) {
			point_after = this_point;
		}
	}

	const float fraction{ (pos - point_before.pos) / (point_after.pos - point_before.pos) };

	const csc::Float4 result_before{ point_before.color, point_before.alpha };
	const csc::Float4 result_after{ point_after.color, point_after.alpha };

	return csc::lerp(result_before, result_after, fraction);
}

void csg::ColorRamp::set(const size_t index, ColorRampPoint new_point)
{
	if (index < points.size()) {
		new_point.pos = boost::algorithm::clamp(new_point.pos, 0.0f, 1.0f);
		points[index] = new_point;
		sort_points();
	}
}

void csg::ColorRamp::remove(size_t index)
{
	if (points.size() < 3) {
		// There must be 2 points remaining after deletion
		return;
	}

	if (index >= points.size()) {
		// Illegal index
		return;
	}

	points.erase(points.begin() + index);
	sort_points();
}

bool csg::ColorRamp::similar(const ColorRamp& other, const float margin) const
{
	if (points.size() != other.points.size()) {
		return false;
	}

	for (size_t i = 0; i < points.size(); i++) {
		const ColorRampPoint p1{ points[i] };
		const ColorRampPoint p2{ other.points[i] };
		const float diff_pos{ static_cast<float>(fabs(p1.pos - p2.pos)) };
		const float diff_alpha{ static_cast<float>(fabs(p1.alpha - p2.alpha)) };
		if (diff_pos > margin) {
			return false;
		}
		if (diff_alpha > margin) {
			return false;
		}
		if (p1.color.similar(p2.color, margin) == false) {
			return false;
		}
	}

	return true;
}

void csg::ColorRamp::sort_points()
{
	const auto lt_pos = [](const ColorRampPoint a, const ColorRampPoint b) -> bool {
		if (a.pos < b.pos) return true;
		else if (b.pos < a.pos) return false;

		if (a.color < b.color) return true;
		else if (b.color < a.color) return false;

		if (a.alpha < b.alpha) return true;
		else if (b.alpha < a.alpha) return false;

		return false;
	};
	std::sort(points.begin(), points.end(), lt_pos);
}


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

#define BIP_NUMBER 44

using namespace bc;
using namespace wallet;
using namespace chain;
using namespace machine;

void build_transaction(const wallet::hd_private& hd_deriver_key, const coin_data& coin) {

    //derived0.

    // ******* part 1 *******

    // Instantiate tx object.
    transaction tx;

    // ******* part 2 *******.

    // Version
    uint32_t version = 160u;
    tx.set_version(version);

    // Print version in serialised format.
    auto serialised_version = to_little_endian(tx.version());
    std::cout << encode_base16(to_chunk(serialised_version)) << std::endl;

    //******* part 3 *******

    // Previous TX hash.
    std::string prev_tx_string_0 = "5209723d5612a46836b3ad1f4ccddd254e24b80cbfb72e002b939a6b33798ded";
    hash_digest prev_tx_hash_0;
    decode_hash(prev_tx_hash_0, prev_tx_string_0);

    // Previous UXTO index.
    uint32_t index0 = 9;
    output_point uxto_tospend_0(prev_tx_hash_0, index0);

    // Build input_0 object.
    input input_0;
    input_0.set_previous_output(uxto_tospend_0);
    input_0.set_sequence(0xffffffff);

    // Additional input objects can be created for additional inputs

    // All input objects can then be added to transaction
    tx.inputs().push_back(input_0);        //first input
    // tx.inputs().push_back(input_1);     //second input
                                           //...nth input

    // Input script will be added later.

    // ******* part 4 *******

    // Destination Address
    auto dest_address_raw = "EKLiqAS8154uEEtRGHZ4PJax64o4nC5Jgw";
    payment_address dest_address1(dest_address_raw);

    auto dest_address_raw2 = "EarTiDEmacVgSfFkukqUFBmseeHBCLdrs8";
    payment_address dest_address2(dest_address_raw2);

    // Create Output output script/scriptPubKey from template:
    operation::list output_script_0=script::to_pay_key_hash_pattern(dest_address1.hash());
    operation::list output_script_1=script::to_pay_key_hash_pattern(dest_address2.hash());

    // Define Output amount
    std::string btc_amount_string_0 = "15";
    uint64_t satoshi_amount_0;
    decode_base10(satoshi_amount_0, btc_amount_string_0, btc_decimal_places); // btc_decimal_places = 8

    std::string btc_amount_string_1 = "184.99965400";
    uint64_t satoshi_amount_1;
    decode_base10(satoshi_amount_1, btc_amount_string_1, btc_decimal_places); // btc_decimal_places = 8

    // Create output_0 object
    output output_0(satoshi_amount_0, output_script_0);
    output output_1(satoshi_amount_1, output_script_1);

    // Above can be repeated for other outputs

    // Add outputs to TX
    tx.outputs().push_back(output_1);     //first output
    tx.outputs().push_back(output_0);     //first output
    // tx.outputs().push_back(output_1);   //second output
    // tx.outputs().push_back(output_n);   //...nth output

    // ******* part 5 *******

    // We rebuild our P2PKH script manually:
    operation::list my_own_p2pkh;
    my_own_p2pkh.push_back(operation(opcode::dup));
    my_own_p2pkh.push_back(operation(opcode::hash160));
    operation op_pubkey = operation(to_chunk(dest_address1.hash()));
    my_own_p2pkh.push_back(op_pubkey); //includes hash length prefix
    my_own_p2pkh.push_back(operation(opcode::equalverify));
    my_own_p2pkh.push_back(operation(opcode::checksig));

    // The two operation lists are equivalent
    std::cout << (my_own_p2pkh == output_script_0) << std::endl;

    // ******* part 6 *******

    // Signer: Secret > Pubkey > Address
    //sig.
    auto derived0 = hd_deriver_key.derive_private(0);
    auto sig = derived0.secret();
    ec_private my_private0(sig, ec_private::to_version(
                coin.pubkey_address, coin.secret_key), true);
    ec_compressed pubkey0= my_private0.to_public().point();
    payment_address my_address0 = my_private0.to_payment_address();

    std::cout << "PRIVATE KEY: " << my_private0 << std::endl;
    std::cout << "PAYMENT ADDRESS: " << my_address0 << std::endl;

    // Signature
    endorsement sig_0;
    script prev_script_0 = script::to_pay_key_hash_pattern(my_address0.hash());
    uint8_t input0_index(0u);
    script::create_endorsement(sig_0, sig, prev_script_0, tx,
        input0_index, 0x01, script_version::zero);

    // Create input script
    operation::list sig_script_0;
    sig_script_0.push_back(operation(sig_0));
    sig_script_0.push_back(operation(to_chunk(pubkey0)));
    script my_input_script_0(sig_script_0);

    std::cout << "INPUT SCRIPT: " << encode_base16(my_input_script_0.to_data(false)) << std::endl;

    // Add input script to first input in transaction
    //tx.inputs()[0].set_script(my_input_script_0);

    chain::witness w(my_input_script_0.to_data(false), false);
    std::cout << "WITNESS: " << w.to_string() << std::endl;
    //tx.inputs()[0].set_witness(w);

    // Print serialised transaction
    std::cout << encode_base16(tx.to_data(true, true)) << std::endl;

}

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

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

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

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

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

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

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

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

    build_transaction(m_ext, coin);

    return 0;

}


#include "catch.hpp"

#undef NDEBUG

#include <boost/numeric/ublas/io.hpp>
#include "IntaRNA/AccessibilityVrna.h"

using namespace IntaRNA;

TEST_CASE("AccessibilityVrna", "[AccessibilityVrna]") {

	// setup easylogging++ stuff if not already done
	#include "testEasyLoggingSetup.icc"

  SECTION("ED test short") {

	const std::string seq = "GG";
	RnaSequence rna("test", seq);
	VrnaHandler vrnaHandler(37,"Turner04",false,false);
	AccessibilityVrna acc(rna, 2, NULL,vrnaHandler,2);

	REQUIRE( E_equal( acc.getED(0, 0), 0 ) );
	REQUIRE( E_equal( acc.getED(1, 1), 0 ) );
	REQUIRE( E_equal( acc.getED(0, 1), 0 ) );

  }
}


/*********************************************************************
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2019, University of Stuttgart
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of the University of Stuttgart nor the names
 *     of its contributors may be used to endorse or promote products
 *     derived from this software without specific prior written
 *     permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *********************************************************************/

/* Author: Andreas Orthey */

#include <ompl/multilevel/planners/qrrt/QRRTImpl.h>
#include <ompl/multilevel/datastructures/graphsampler/GraphSampler.h>
#include <ompl/tools/config/SelfConfig.h>
#include <boost/foreach.hpp>

#define foreach BOOST_FOREACH

ompl::multilevel::QRRTImpl::QRRTImpl(const base::SpaceInformationPtr &si, BundleSpace *parent_) : BaseT(si, parent_)
{
    setName("QRRTImpl" + std::to_string(id_));
    setImportance("exponential");
    setGraphSampler("randomvertex");
    getGraphSampler()->disableSegmentBias();
}

ompl::multilevel::QRRTImpl::~QRRTImpl()
{
}

void ompl::multilevel::QRRTImpl::grow()
{
    //(0) If first run, add start configuration
    if (firstRun_)
    {
        init();
        firstRun_ = false;

        findSection();
    }

    //(1) Get Random Sample
    sampleBundleGoalBias(xRandom_->state);

    //(2) Get Nearest in Tree
    const Configuration *xNearest = nearest(xRandom_);

    //(3) Connect Nearest to Random (within range)
    Configuration *xNext = extendGraphTowards_Range(xNearest, xRandom_);

    //(4) If extension was successful, check if we reached goal
    if (xNext && !hasSolution_)
    {
        if (isDynamic())
        {
            double dist;
            bool satisfied = getGoalPtr()->isSatisfied(xNext->state, &dist);
            if (dist < bestCost_.value())
            {
                bestCost_ = base::Cost(dist);
            }
            if (satisfied)
            {
                goalConfigurations_.push_back(xNext);
                hasSolution_ = true;
            }
        }
        else
        {
            bool satisfied = getGoalPtr()->isSatisfied(xNext->state);
            if (satisfied)
            {
                goalConfigurations_.push_back(xNext);
                hasSolution_ = true;
            }
        }
    }
}


//#include <boost/python.hpp>
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
//#include "include/numpy_boost_python.hpp"

#include "diamond_wrapper.hpp"
using namespace boost::python;

void export_reconstruction();
void export_filters();
BOOST_PYTHON_MODULE(parallelbeam)
{
	namespace bp = boost::python;
	np::initialize();
	//To specify that this module is a package
	bp::object package = bp::scope();
	package.attr("__path__") = "parallelbeam";

	export_reconstruction();
	export_filters();
}

void export_reconstruction()
{
	namespace bp = boost::python;
	bp::object reconstructionModule(bp::handle<>(bp::borrowed(PyImport_AddModule("parallelbeam.alg"))));
	// make "from diamond import filters" work
	bp::scope().attr("alg") = reconstructionModule;
	// set the current scope to the new sub-module
    bp::scope reconstruction_scope = reconstructionModule;

  def("cgls",          reconstruct_cgls);
  def("cgls_conv",     reconstruct_cgls2);
  def("sirt",          reconstruct_sirt);
  def("mlem",          reconstruct_mlem);
  def("cgls_tikhonov", reconstruct_cgls_tikhonov);
  def("cgls_TVreg",    reconstruct_cgls_tvreg);

  def("cgls_step",          reconstruct_cgls_step);
  def("sirt_step",          reconstruct_sirt_step);
  def("mlem_step",          reconstruct_mlem_step);
  def("cgls_tikhonov_step", reconstruct_cgls_tikhonov_step);
  def("cgls_TVreg_step",    reconstruct_cgls_tvreg_step);
  def("cgls_conv_step",     reconstruct_cgls2_step);
  // parallel beam forward/backward project
  def("pb_forward_project", pb_forward_project);
  def("pb_backward_project", pb_backward_project);

  def("pb_setup_geometry_from_acquisition", pb_setup_geometry_from_acquisition);
  def("pb_setup_geometry_from_image", pb_setup_geometry_from_image);

  //def("pb_backward_prject", pb_backward_project);

  //def("tvreg", reconstruct_tvreg);
}

void export_filters()
{
	namespace bp = boost::python;
	bp::object filtersModule(bp::handle<>(bp::borrowed(PyImport_AddModule("parallelbeam.filters"))));
	// make "from diamond import filters" work
	bp::scope().attr("filters") = filtersModule;
	// set the current scope to the new sub-module
    bp::scope filters_scope = filtersModule;

	def("aml_ring_artefacts", ring_artefacts_aml);
}