<commit_before>#include "ConditionTreeNode.h"

ConditionTreeNode::ConditionTreeNode(ConditionTreeNode::Mode mode, std::vector<ConditionTreeNode *> children) {
    this->mode = mode;
    this->children = children;
}

ConditionTreeNode::ConditionTreeNode(Condition *val) {
    this->mode = ConditionTreeNode::NONE;
    this->value = val;
}

ConditionTreeNode::Mode ConditionTreeNode::get_mode() {
    return this->mode;
}

std::string ConditionTreeNode::print() {
    std::string res;
    if (mode == AND) {
        res += "(";
        for (ConditionTreeNode *c : this->children) {
            res += c->print();
            res += " && ";
        }
        res.erase(res.size() - 4);
        res += ")";
    } else if (mode == OR) {
        res += "(";
        for (ConditionTreeNode *c : this->children) {
            res += c->print();
            res += " || ";
        }
        res.erase(res.size() - 4);
        res += ")";
    } else {
        std::string not_kw;
        if (this->value->has_keyword_not()) {
            not_kw = "!";
        }
        std::string op;
        switch (this->value->get_operator()) {
            case Condition::EQ:
                op = " == ";
                break;
            case Condition::LESS:
                op = " < ";
                break;
            case Condition::MORE:
                op = " > ";
                break;
            case Condition::NOT_EQ:
                op = " != ";
                break;
            case Condition::LESS_OR_EQ:
                op = " <= ";
                break;
            case Condition::MORE_OR_EQ:
                op = " >= ";
                break;
        }
        std::string rhs;
        if (this->value->get_mode() == this->value->Mode::JOIN) {
            rhs = "c_" + this->value->get_column_right()->get_name();
        } else {
            rhs = this->value->get_parameter()->get_name();
        }
        if (this->value->get_column()->get_type()->get_typecode() != DataType::CHAR) {
            res += not_kw + "(c_" + this->value->get_column()->get_name() + op + rhs + ")";
        } else {
            res += not_kw + "(strcmp(c_" + this->value->get_column()->get_name() + ", " + rhs + ")" + op + "0)";
        }
    }
    return res;
}

void ConditionTreeNode::walk() {
    std::string type;
    switch (this->mode) {
        case NONE:
            type = " single ";
            std::cout << type << this->value->print() << std::endl;
            break;
        case AND:
            type = " AND ";
            std::cout << type << std::endl;
            for (ConditionTreeNode *c : this->children) {
                c->walk();
            }
            break;
        case OR:
            type = " OR ";
            std::cout << type << std::endl;
            for (ConditionTreeNode *c : this->children) {
                c->walk();
            }
            break;
    }
}

ConditionTreeNode::~ConditionTreeNode() {
    switch (this->mode) {
        case NONE:
            delete this->value;
            break;
        case AND:
        case OR:
            for (ConditionTreeNode *c : this->children) {
                delete c;
            }
            break;
    }
}

Condition *ConditionTreeNode::get_value() {
    return this->value;
}

void ConditionTreeNode::set_value(Condition *c) {
    this->value = c;
}

std::vector<ConditionTreeNode *> ConditionTreeNode::get_children() {
    return this->children;
}

void ConditionTreeNode::add_child(ConditionTreeNode *child) {
    this->children.push_back(child);
}

void ConditionTreeNode::set_mode(ConditionTreeNode::Mode m) {
    this->mode = m;
}

std::pair<std::string, std::string> ConditionTreeNode::calculate_pk_bounds() {
    std::pair<std::string, std::string> res;
    std::vector<std::string> lower_bound, upper_bound;
    switch (this->mode) {
        case AND:
            for (ConditionTreeNode *c : this->children) {
                if (c->get_mode() != ConditionTreeNode::NONE) {
                    continue;
                }
                if (c->get_value()->get_column()->get_pk()) {
                    Parameter *p = c->get_value()->get_parameter();
                    switch (c->get_value()->get_operator()) {
                        case Condition::EQ:
                            lower_bound.push_back(p->get_name());
                            upper_bound.push_back(p->get_name());
                            break;
                        case Condition::LESS:
                            // id < ARG => (..., ARG)
                            upper_bound.push_back(p->get_name() + "-1");
                            break;
                        case Condition::MORE:
                            // id > ARG: (ARG, ...)
                            lower_bound.push_back(p->get_name() + "+1");
                            break;
                        case Condition::LESS_OR_EQ:
                            // id <= ARG: (..., ARG]
                            upper_bound.push_back(p->get_name());
                            break;
                        case Condition::MORE_OR_EQ:
                            // id >= ARG: [ARG, ...)
                            lower_bound.push_back(res.first = p->get_name());
                            break;
                        default:
                            break;
                    }
                }
            }
            if (!lower_bound.empty()) {
                if (lower_bound.size() > 1) {
                    std::string max_s;
                    for (auto &s: lower_bound) {
                        if (&s == &lower_bound.back()) {
                            max_s += s;
                            max_s += ")";
                            break;
                        }
                        max_s += "MAX(";
                        max_s += s;
                        max_s += ",";
                    }
                    std::cout << max_s << std::endl;
                    res.first = max_s;
                } else {
                    res.first = lower_bound.back();
                }
            }
            if (!upper_bound.empty()) {
                if (upper_bound.size() > 1) {
                    std::string min_s;
                    for (auto &s: upper_bound) {
                        if (&s == &upper_bound.back()) {
                            min_s += s;
                            min_s += ")";
                            break;
                        }
                        min_s += "MIN(";
                        min_s += s;
                        min_s += ",";
                    }
                    std::cout << min_s << std::endl;
                    res.second = min_s;
                } else {
                    res.second = upper_bound.back();
                }
            }
            break;
        case NONE:
            if (this->value->get_column()->get_pk()) {
                Parameter *p = this->value->get_parameter();
                switch (this->value->get_operator()) {
                    case Condition::EQ:
                        res.first = p->get_name();
                        res.second = p->get_name();
                        break;
                    case Condition::LESS:
                        // id < ARG => (..., ARG)
                        res.second = p->get_name() + "-1";
                        break;
                    case Condition::MORE:
                        // id > ARG: (ARG, ...)
                        res.first = p->get_name() + "+1";
                        break;
                    case Condition::LESS_OR_EQ:
                        // id <= ARG: (..., ARG]
                        res.second = p->get_name();
                        break;
                    case Condition::MORE_OR_EQ:
                        // id >= ARG: [ARG, ...)
                        res.first = p->get_name();
                        break;
                    default:
                        break;
                }
            }
            break;
    }
    return res;
}
<commit_msg>Minor changes<commit_after>#include "ConditionTreeNode.h"

ConditionTreeNode::ConditionTreeNode(ConditionTreeNode::Mode mode, std::vector<ConditionTreeNode *> children) {
    this->mode = mode;
    this->children = children;
}

ConditionTreeNode::ConditionTreeNode(Condition *val) {
    this->mode = ConditionTreeNode::NONE;
    this->value = val;
}

ConditionTreeNode::Mode ConditionTreeNode::get_mode() {
    return this->mode;
}

std::string ConditionTreeNode::print() {
    std::string res;
    if (mode == AND) {
        res += "(";
        for (ConditionTreeNode *c : this->children) {
            res += c->print();
            res += " && ";
        }
        res.erase(res.size() - 4);
        res += ")";
    } else if (mode == OR) {
        res += "(";
        for (ConditionTreeNode *c : this->children) {
            res += c->print();
            res += " || ";
        }
        res.erase(res.size() - 4);
        res += ")";
    } else {
        std::string not_kw;
        if (this->value->has_keyword_not()) {
            not_kw = "!";
        }
        std::string op;
        switch (this->value->get_operator()) {
            case Condition::EQ:
                op = " == ";
                break;
            case Condition::LESS:
                op = " < ";
                break;
            case Condition::MORE:
                op = " > ";
                break;
            case Condition::NOT_EQ:
                op = " != ";
                break;
            case Condition::LESS_OR_EQ:
                op = " <= ";
                break;
            case Condition::MORE_OR_EQ:
                op = " >= ";
                break;
        }
        std::string rhs;
        if (this->value->get_mode() == this->value->Mode::JOIN) {
            rhs = "c_" + this->value->get_column_right()->get_name();
        } else {
            rhs = this->value->get_parameter()->get_name();
        }
        if (this->value->get_column()->get_type()->get_typecode() != DataType::CHAR) {
            res += not_kw + "(c_" + this->value->get_column()->get_name() + op + rhs + ")";
        } else {
            res += not_kw + "(strcmp(c_" + this->value->get_column()->get_name() + ", " + rhs + ")" + op + "0)";
        }
    }
    return res;
}

void ConditionTreeNode::walk() {
    std::string type;
    switch (this->mode) {
        case NONE:
            type = " single ";
            std::cout << type << this->value->print() << std::endl;
            break;
        case AND:
            type = " AND ";
            std::cout << type << std::endl;
            for (ConditionTreeNode *c : this->children) {
                c->walk();
            }
            break;
        case OR:
            type = " OR ";
            std::cout << type << std::endl;
            for (ConditionTreeNode *c : this->children) {
                c->walk();
            }
            break;
    }
}

ConditionTreeNode::~ConditionTreeNode() {
    switch (this->mode) {
        case NONE:
            delete this->value;
            break;
        case AND:
        case OR:
            for (ConditionTreeNode *c : this->children) {
                delete c;
            }
            break;
    }
}

Condition *ConditionTreeNode::get_value() {
    return this->value;
}

void ConditionTreeNode::set_value(Condition *c) {
    this->value = c;
}

std::vector<ConditionTreeNode *> ConditionTreeNode::get_children() {
    return this->children;
}

void ConditionTreeNode::add_child(ConditionTreeNode *child) {
    this->children.push_back(child);
}

void ConditionTreeNode::set_mode(ConditionTreeNode::Mode m) {
    this->mode = m;
}

std::pair<std::string, std::string> ConditionTreeNode::calculate_pk_bounds() {
    std::pair<std::string, std::string> res;
    std::vector<std::string> lower_bound, upper_bound;
    switch (this->mode) {
        case AND:
            for (ConditionTreeNode *c : this->children) {
                if (c->get_mode() != ConditionTreeNode::NONE) {
                    continue;
                }
                if (c->get_value()->get_column()->get_mod() == COLUMN_PRIMARY) {
                    Parameter *p = c->get_value()->get_parameter();
                    switch (c->get_value()->get_operator()) {
                        case Condition::EQ:
                            lower_bound.push_back(p->get_name());
                            upper_bound.push_back(p->get_name());
                            break;
                        case Condition::LESS:
                            // id < ARG => (..., ARG)
                            upper_bound.push_back(p->get_name() + "-1");
                            break;
                        case Condition::MORE:
                            // id > ARG: (ARG, ...)
                            lower_bound.push_back(p->get_name() + "+1");
                            break;
                        case Condition::LESS_OR_EQ:
                            // id <= ARG: (..., ARG]
                            upper_bound.push_back(p->get_name());
                            break;
                        case Condition::MORE_OR_EQ:
                            // id >= ARG: [ARG, ...)
                            lower_bound.push_back(res.first = p->get_name());
                            break;
                        default:
                            break;
                    }
                }
            }
            if (!lower_bound.empty()) {
                if (lower_bound.size() > 1) {
                    std::string max_s;
                    for (auto &s: lower_bound) {
                        if (&s == &lower_bound.back()) {
                            max_s += s;
                            max_s += ")";
                            break;
                        }
                        max_s += "MAX(";
                        max_s += s;
                        max_s += ",";
                    }
                    std::cout << max_s << std::endl;
                    res.first = max_s;
                } else {
                    res.first = lower_bound.back();
                }
            }
            if (!upper_bound.empty()) {
                if (upper_bound.size() > 1) {
                    std::string min_s;
                    for (auto &s: upper_bound) {
                        if (&s == &upper_bound.back()) {
                            min_s += s;
                            min_s += ")";
                            break;
                        }
                        min_s += "MIN(";
                        min_s += s;
                        min_s += ",";
                    }
                    std::cout << min_s << std::endl;
                    res.second = min_s;
                } else {
                    res.second = upper_bound.back();
                }
            }
            break;
        case NONE:
            if (this->value->get_column()->get_mod() == COLUMN_PRIMARY) {
                Parameter *p = this->value->get_parameter();
                switch (this->value->get_operator()) {
                    case Condition::EQ:
                        res.first = p->get_name();
                        res.second = p->get_name();
                        break;
                    case Condition::LESS:
                        // id < ARG => (..., ARG)
                        res.second = p->get_name() + "-1";
                        break;
                    case Condition::MORE:
                        // id > ARG: (ARG, ...)
                        res.first = p->get_name() + "+1";
                        break;
                    case Condition::LESS_OR_EQ:
                        // id <= ARG: (..., ARG]
                        res.second = p->get_name();
                        break;
                    case Condition::MORE_OR_EQ:
                        // id >= ARG: [ARG, ...)
                        res.first = p->get_name();
                        break;
                    default:
                        break;
                }
            }
            break;
    }
    return res;
}
<|endoftext|>


<commit_before>// Copyright (C) 2018 Elviss Strazdins
// This file is part of the Ouzel engine.

#pragma once

#include <list>
#include "scene/Component.hpp"
#include "math/Size2.hpp"
#include "math/Vector2.hpp"
#include "scene/SpriteData.hpp"
#include "core/UpdateCallback.hpp"
#include "graphics/Material.hpp"

namespace ouzel
{
    namespace scene
    {
        class SceneManager;

        class Sprite: public Component
        {
        public:
            static const uint32_t TYPE = Component::SPRITE;

            Sprite();
            Sprite(const SpriteData& spriteData);
            Sprite(const std::string& filename, bool mipmaps = true,
                   uint32_t spritesX = 1, uint32_t spritesY = 1,
                   const Vector2& pivot = Vector2(0.5f, 0.5f));
            Sprite(std::shared_ptr<graphics::Texture> texture,
                   uint32_t spritesX = 1, uint32_t spritesY = 1,
                   const Vector2& pivot = Vector2(0.5f, 0.5f));

            bool init(const SpriteData& spriteData);
            bool init(const std::string& filename, bool mipmaps = true,
                      uint32_t spritesX = 1, uint32_t spritesY = 1,
                      const Vector2& pivot = Vector2(0.5f, 0.5f));
            bool init(std::shared_ptr<graphics::Texture> newTexture,
                      uint32_t spritesX = 1, uint32_t spritesY = 1,
                      const Vector2& pivot = Vector2(0.5f, 0.5f));

            void update(float delta);

            virtual void draw(const Matrix4& transformMatrix,
                              float opacity,
                              const Matrix4& renderViewProjection,
                              const std::shared_ptr<graphics::Texture>& renderTarget,
                              const Rect& renderViewport,
                              bool depthWrite,
                              bool depthTest,
                              bool wireframe,
                              bool scissorTest,
                              const Rect& scissorRectangle) override;

            inline const std::shared_ptr<graphics::Material>& getMaterial() const { return material; }
            inline void setMaterial(const std::shared_ptr<graphics::Material>& newMaterial) { material = newMaterial; }

            inline const Vector2& getOffset() const { return offset; }
            void setOffset(const Vector2& newOffset);

            void play();
            void stop(bool resetAnimation = true);
            void reset();
            inline bool isPlaying() const { return playing; }

            inline const std::map<std::string, SpriteData::Animation>& getAnimations() const { return animations; }
            inline const SpriteData::Animation* getAnimation() const { return currentAnimation->animation; }
            inline std::string getAnimationName() const { return currentAnimation->animation->name; }
            bool hasAnimation(const std::string& animation) const;
            void setAnimation(const std::string& newAnimation, bool repeat = true);
            void addAnimation(const std::string& newAnimation, bool repeat = true);
            void setAnimatonProgress(float percentage);
            void setAnimatonTime(float time);

        protected:
            void updateBoundingBox();

            std::shared_ptr<graphics::Material> material;
            std::map<std::string, SpriteData::Animation> animations;

            struct QueuedAnimation
            {
                const SpriteData::Animation* animation;
                bool repeat;
            };

            std::list<QueuedAnimation> animationQueue;
            std::list<QueuedAnimation>::iterator currentAnimation;

            std::shared_ptr<graphics::Texture> whitePixelTexture;

            Vector2 offset;
            Matrix4 offsetMatrix = Matrix4::IDENTITY;

            bool playing = false;
            bool running = false;
            float currentTime = 0.0f;

            UpdateCallback updateCallback;
        };
    } // namespace scene
} // namespace ouzel
<commit_msg>Rename percentage to progress<commit_after>// Copyright (C) 2018 Elviss Strazdins
// This file is part of the Ouzel engine.

#pragma once

#include <list>
#include "scene/Component.hpp"
#include "math/Size2.hpp"
#include "math/Vector2.hpp"
#include "scene/SpriteData.hpp"
#include "core/UpdateCallback.hpp"
#include "graphics/Material.hpp"

namespace ouzel
{
    namespace scene
    {
        class SceneManager;

        class Sprite: public Component
        {
        public:
            static const uint32_t TYPE = Component::SPRITE;

            Sprite();
            Sprite(const SpriteData& spriteData);
            Sprite(const std::string& filename, bool mipmaps = true,
                   uint32_t spritesX = 1, uint32_t spritesY = 1,
                   const Vector2& pivot = Vector2(0.5f, 0.5f));
            Sprite(std::shared_ptr<graphics::Texture> texture,
                   uint32_t spritesX = 1, uint32_t spritesY = 1,
                   const Vector2& pivot = Vector2(0.5f, 0.5f));

            bool init(const SpriteData& spriteData);
            bool init(const std::string& filename, bool mipmaps = true,
                      uint32_t spritesX = 1, uint32_t spritesY = 1,
                      const Vector2& pivot = Vector2(0.5f, 0.5f));
            bool init(std::shared_ptr<graphics::Texture> newTexture,
                      uint32_t spritesX = 1, uint32_t spritesY = 1,
                      const Vector2& pivot = Vector2(0.5f, 0.5f));

            void update(float delta);

            virtual void draw(const Matrix4& transformMatrix,
                              float opacity,
                              const Matrix4& renderViewProjection,
                              const std::shared_ptr<graphics::Texture>& renderTarget,
                              const Rect& renderViewport,
                              bool depthWrite,
                              bool depthTest,
                              bool wireframe,
                              bool scissorTest,
                              const Rect& scissorRectangle) override;

            inline const std::shared_ptr<graphics::Material>& getMaterial() const { return material; }
            inline void setMaterial(const std::shared_ptr<graphics::Material>& newMaterial) { material = newMaterial; }

            inline const Vector2& getOffset() const { return offset; }
            void setOffset(const Vector2& newOffset);

            void play();
            void stop(bool resetAnimation = true);
            void reset();
            inline bool isPlaying() const { return playing; }

            inline const std::map<std::string, SpriteData::Animation>& getAnimations() const { return animations; }
            inline const SpriteData::Animation* getAnimation() const { return currentAnimation->animation; }
            inline std::string getAnimationName() const { return currentAnimation->animation->name; }
            bool hasAnimation(const std::string& animation) const;
            void setAnimation(const std::string& newAnimation, bool repeat = true);
            void addAnimation(const std::string& newAnimation, bool repeat = true);
            void setAnimatonProgress(float progress);
            void setAnimatonTime(float time);

        protected:
            void updateBoundingBox();

            std::shared_ptr<graphics::Material> material;
            std::map<std::string, SpriteData::Animation> animations;

            struct QueuedAnimation
            {
                const SpriteData::Animation* animation;
                bool repeat;
            };

            std::list<QueuedAnimation> animationQueue;
            std::list<QueuedAnimation>::iterator currentAnimation;

            std::shared_ptr<graphics::Texture> whitePixelTexture;

            Vector2 offset;
            Matrix4 offsetMatrix = Matrix4::IDENTITY;

            bool playing = false;
            bool running = false;
            float currentTime = 0.0f;

            UpdateCallback updateCallback;
        };
    } // namespace scene
} // namespace ouzel
<|endoftext|>


<commit_before>#include <sstream>
#include <iostream>
#include <chrono>
#include <random>

#include <boost/format.hpp>

#include <boost/serialization/serialization.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/vector.hpp>

#include <cereal/binary_archive/binary_archive.hpp>
#include <cereal/binary_archive/vector.hpp>

//! Runs serialization to save data to an ostringstream
/*! Used to time how long it takes to save data to an ostringstream.
    Everything that happens within the save function will be timed, including
    any set-up necessary to perform the serialization.

    @param data The data to save
    @param saveFunction A function taking in an ostringstream and the data and returning void
    @return The ostringstream and the time it took to save the data */
template <class T>
std::chrono::milliseconds
saveData( T const & data, std::function<void(std::ostringstream &, T const&)> saveFunction, std::ostringstream & os )
{
  auto start = std::chrono::high_resolution_clock::now();
  saveFunction( os, data );
  return std::chrono::duration_cast<std::chrono::milliseconds>( std::chrono::high_resolution_clock::now() - start );
}

//! Runs serialization to load data to from an istringstream
/*! Used to time how long it takes to load data from an istringstream.
    Everything that happens within the load function will be timed, including
    any set-up necessary to perform the serialization.

    @param dataStream The saved data stream
    @param loadFunction A function taking in an istringstream and a data reference and returning void
    @return The loaded data and the time it took to save the data */
template <class T>
std::pair<T, std::chrono::milliseconds>
loadData( std::ostringstream const & dataStream, std::function<void(std::istringstream &, T &)> loadFunction )
{
  T data;
  std::istringstream os( dataStream.str() );

  auto start = std::chrono::high_resolution_clock::now();
  loadFunction( os, data );

  return {data, std::chrono::duration_cast<std::chrono::milliseconds>( std::chrono::high_resolution_clock::now() - start )};
}

struct cerealBinary
{
  //! Saves data to a cereal binary archive
  template <class T>
  static void save( std::ostringstream & os, T const & data )
  {
    cereal::BinaryOutputArchive oar(os);
    oar & data;
  }

  //! Loads data to a cereal binary archive
  template <class T>
  static void load( std::istringstream & is, T & data )
  {
    cereal::BinaryInputArchive iar(is);
    iar & data;
  }
};

struct boostBinary
{
  //! Saves data to a boost binary archive
  template <class T>
  static void save( std::ostringstream & os, T const & data )
  {
    boost::archive::binary_oarchive oar(os);
    oar & data;
  }

  //! Loads data to a boost binary archive
  template <class T>
  static void load( std::istringstream & is, T & data )
  {
    boost::archive::binary_iarchive iar(is);
    iar & data;
  }
};

struct binary
{
  typedef boostBinary  boost;
  typedef cerealBinary cereal;
};

//! Times how long it takes to serialize (load and store) some data
/*! Times how long and the size of the serialization object used to serialize
    some data.  Result is output to standard out.

    @tparam SerializationT The serialization struct that has all save and load functions
    @tparam DataT The type of data to test
    @param name The name for this test
    @param data The data to serialize
    @param numAverages The number of times to average
    @param validateData Whether data should be validated (input == output) */
template <class SerializationT, class DataT>
void test( std::string const & name,
            DataT const & data,
            size_t numAverages = 10,
            bool validateData = false )
{
  std::cout << "-----------------------------------" << std::endl;
  std::cout << "Running test: " << name << std::endl;

  std::chrono::milliseconds totalBoostSave{0};
  std::chrono::milliseconds totalBoostLoad{0};

  std::chrono::milliseconds totalCerealSave{0};
  std::chrono::milliseconds totalCerealLoad{0};

  size_t boostSize = 0;
  size_t cerealSize = 0;

  for(size_t i = 0; i < numAverages; ++i)
  {
    // Boost
    {
      std::ostringstream os;
      auto saveResult = saveData<DataT>( data, {SerializationT::boost::template save<DataT>}, os );
      totalBoostSave += saveResult;
      if(!boostSize)
        boostSize = os.tellp();

      auto loadResult = loadData<DataT>( os, {SerializationT::boost::template load<DataT>} );
      totalBoostLoad += loadResult.second;

      if( validateData )
        ; // TODO
    }

    // Cereal
    {
      std::ostringstream os;
      auto saveResult = saveData<DataT>( data, {SerializationT::cereal::template save<DataT>}, os );
      totalCerealSave += saveResult;
      if(!cerealSize)
        cerealSize = os.tellp();

      auto loadResult = loadData<DataT>( os, {SerializationT::cereal::template load<DataT>} );
      totalCerealLoad += loadResult.second;

      if( validateData )
        ; // TODO
    }
  }

  // Averages
  double averageBoostSave = totalBoostSave.count() / static_cast<double>( numAverages );
  double averageBoostLoad = totalBoostLoad.count() / static_cast<double>( numAverages );

  double averageCerealSave = totalCerealSave.count() / static_cast<double>( numAverages );
  double averageCerealLoad = totalCerealLoad.count() / static_cast<double>( numAverages );

  // Percentages relative to boost
  double cerealSaveP = averageCerealSave / averageBoostSave;
  double cerealLoadP = averageCerealLoad / averageBoostLoad;
  double cerealSizeP = cerealSize / static_cast<double>( boostSize );

  std::cout << "  Boost results:" << std::endl;
  std::cout << boost::format("\tsave | time: %06.4fms (%1.2f) size: %20.8fkb (%1.8f) total: %6.1fms")
    % averageBoostSave % 1.0 % (boostSize / 1024.0) % 1.0 % static_cast<double>( totalBoostSave.count() );
  std::cout << std::endl;
  std::cout << boost::format("\tload | time: %06.4fms (%1.2f) total: %6.1fms")
    % averageBoostLoad % 1.0 % static_cast<double>( totalBoostLoad.count() );
  std::cout << std::endl;

  std::cout << "  Cereal results:" << std::endl;
  std::cout << boost::format("\tsave | time: %06.4fms (%1.2f) size: %20.8fkb (%1.8f) total: %6.1fms")
    % averageCerealSave % cerealSaveP % (cerealSize / 1024.0) % cerealSizeP % static_cast<double>( totalCerealSave.count() );
  std::cout << std::endl;
  std::cout << boost::format("\tload | time: %06.4fms (%1.2f) total: %6.1fms")
    % averageCerealLoad % 1.0 % static_cast<double>( totalCerealLoad.count() );
  std::cout << std::endl;
}

template<class T>
typename std::enable_if<std::is_floating_point<T>::value, T>::type
random_value(std::mt19937 & gen)
{ return std::uniform_real_distribution<T>(-10000.0, 10000.0)(gen); }

template<class T>
typename std::enable_if<std::is_integral<T>::value, T>::type
random_value(std::mt19937 & gen)
{ return std::uniform_int_distribution<T>(std::numeric_limits<T>::lowest(), std::numeric_limits<T>::max())(gen); }

template<class T>
typename std::enable_if<std::is_same<T, std::string>::value, std::string>::type
random_value(std::mt19937 & gen)
{
  std::string s(std::uniform_int_distribution<int>(3, 30)(gen), ' ');
  for(char & c : s)
    c = std::uniform_int_distribution<char>(' ', '~')(gen);
  return s;
}

template<class C>
std::basic_string<C> random_basic_string(std::mt19937 & gen)
{
  std::basic_string<C> s(std::uniform_int_distribution<int>(3, 30)(gen), ' ');
  for(C & c : s)
    c = std::uniform_int_distribution<C>(' ', '~')(gen);
  return s;
}

template <size_t N>
std::string random_binary_string(std::mt19937 & gen)
{
  std::string s(N, ' ');
  for(auto & c : s )
    c = std::uniform_int_distribution<char>('0', '1')(gen);
  return s;
}

struct PoDStruct
{
  int32_t a;
  int64_t b;
  float c;
  double d;

  template <class Archive>
  void serialize( Archive & ar )
  {
    ar & a & b & c & d;
  };

  template <class Archive>
  void serialize( Archive & ar, const unsigned int version )
  {
    ar & a & b & c & d;
  };
};

int main()
{
  std::random_device rd;
  std::mt19937 gen(rd());
  auto rngC = [&](){ return random_value<uint8_t>(gen); };
  auto rngD = [&](){ return random_value<double>(gen); };

  auto vectorDoubleTest = [&](size_t s, bool randomize)
  {
    std::ostringstream name;
    name << "Vector(double) size " << s;

    std::vector<double> data(s);
    if(randomize)
      for( auto & d : data )
        d = rngD();

    test<binary>( name.str(), data );
  };

  auto vectorCharTest = [&](size_t s, bool randomize)
  {
    std::ostringstream name;
    name << "Vector(uint8_t) size " << s;

    std::vector<uint8_t> data(s);
    if(randomize)
      for( auto & d : data )
        d = rngC();

    test<binary>( name.str(), data );
  };

  const bool randomize = false;

  vectorDoubleTest(1, randomize); // 8B
  vectorDoubleTest(16, randomize); // 128B
  vectorDoubleTest(1024, randomize); // 8KB
  vectorDoubleTest(1024*1024, randomize); // 8MB

  vectorCharTest(1024*1024*1024, randomize); // 1 GB

  auto vectorPoDStructTest = [&](size_t s)
  {
    std::ostringstream name;
    name << "Vector(PoDStruct) size " << s;

    std::vector<PoDStruct> data(s);
    test<binary>( name.str(), data );
  };

  vectorPoDStructTest(1);
  vectorPoDStructTest(64);
  vectorPoDStructTest(1024);
  vectorPoDStructTest(1024*1024);
  vectorPoDStructTest(1024*1024*64);

  return 0;
}
<commit_msg>fixed issue with cereal load percentage.  adding derived class performance<commit_after>#include <sstream>
#include <iostream>
#include <chrono>
#include <random>

#include <boost/format.hpp>

#include <boost/serialization/serialization.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/base_object.hpp>

#include <cereal/binary_archive/binary_archive.hpp>
#include <cereal/binary_archive/vector.hpp>

//! Runs serialization to save data to an ostringstream
/*! Used to time how long it takes to save data to an ostringstream.
    Everything that happens within the save function will be timed, including
    any set-up necessary to perform the serialization.

    @param data The data to save
    @param saveFunction A function taking in an ostringstream and the data and returning void
    @return The ostringstream and the time it took to save the data */
template <class T>
std::chrono::milliseconds
saveData( T const & data, std::function<void(std::ostringstream &, T const&)> saveFunction, std::ostringstream & os )
{
  auto start = std::chrono::high_resolution_clock::now();
  saveFunction( os, data );
  return std::chrono::duration_cast<std::chrono::milliseconds>( std::chrono::high_resolution_clock::now() - start );
}

//! Runs serialization to load data to from an istringstream
/*! Used to time how long it takes to load data from an istringstream.
    Everything that happens within the load function will be timed, including
    any set-up necessary to perform the serialization.

    @param dataStream The saved data stream
    @param loadFunction A function taking in an istringstream and a data reference and returning void
    @return The loaded data and the time it took to save the data */
template <class T>
std::pair<T, std::chrono::milliseconds>
loadData( std::ostringstream const & dataStream, std::function<void(std::istringstream &, T &)> loadFunction )
{
  T data;
  std::istringstream os( dataStream.str() );

  auto start = std::chrono::high_resolution_clock::now();
  loadFunction( os, data );

  return {data, std::chrono::duration_cast<std::chrono::milliseconds>( std::chrono::high_resolution_clock::now() - start )};
}

struct cerealBinary
{
  //! Saves data to a cereal binary archive
  template <class T>
  static void save( std::ostringstream & os, T const & data )
  {
    cereal::BinaryOutputArchive oar(os);
    oar & data;
  }

  //! Loads data to a cereal binary archive
  template <class T>
  static void load( std::istringstream & is, T & data )
  {
    cereal::BinaryInputArchive iar(is);
    iar & data;
  }
};

struct boostBinary
{
  //! Saves data to a boost binary archive
  template <class T>
  static void save( std::ostringstream & os, T const & data )
  {
    boost::archive::binary_oarchive oar(os);
    oar & data;
  }

  //! Loads data to a boost binary archive
  template <class T>
  static void load( std::istringstream & is, T & data )
  {
    boost::archive::binary_iarchive iar(is);
    iar & data;
  }
};

struct binary
{
  typedef boostBinary  boost;
  typedef cerealBinary cereal;
};

//! Times how long it takes to serialize (load and store) some data
/*! Times how long and the size of the serialization object used to serialize
    some data.  Result is output to standard out.

    @tparam SerializationT The serialization struct that has all save and load functions
    @tparam DataT The type of data to test
    @param name The name for this test
    @param data The data to serialize
    @param numAverages The number of times to average
    @param validateData Whether data should be validated (input == output) */
template <class SerializationT, class DataT>
void test( std::string const & name,
            DataT const & data,
            size_t numAverages = 10,
            bool validateData = false )
{
  std::cout << "-----------------------------------" << std::endl;
  std::cout << "Running test: " << name << std::endl;

  std::chrono::milliseconds totalBoostSave{0};
  std::chrono::milliseconds totalBoostLoad{0};

  std::chrono::milliseconds totalCerealSave{0};
  std::chrono::milliseconds totalCerealLoad{0};

  size_t boostSize = 0;
  size_t cerealSize = 0;

  for(size_t i = 0; i < numAverages; ++i)
  {
    // Boost
    {
      std::ostringstream os;
      auto saveResult = saveData<DataT>( data, {SerializationT::boost::template save<DataT>}, os );
      totalBoostSave += saveResult;
      if(!boostSize)
        boostSize = os.tellp();

      auto loadResult = loadData<DataT>( os, {SerializationT::boost::template load<DataT>} );
      totalBoostLoad += loadResult.second;

      if( validateData )
        ; // TODO
    }

    // Cereal
    {
      std::ostringstream os;
      auto saveResult = saveData<DataT>( data, {SerializationT::cereal::template save<DataT>}, os );
      totalCerealSave += saveResult;
      if(!cerealSize)
        cerealSize = os.tellp();

      auto loadResult = loadData<DataT>( os, {SerializationT::cereal::template load<DataT>} );
      totalCerealLoad += loadResult.second;

      if( validateData )
        ; // TODO
    }
  }

  // Averages
  double averageBoostSave = totalBoostSave.count() / static_cast<double>( numAverages );
  double averageBoostLoad = totalBoostLoad.count() / static_cast<double>( numAverages );

  double averageCerealSave = totalCerealSave.count() / static_cast<double>( numAverages );
  double averageCerealLoad = totalCerealLoad.count() / static_cast<double>( numAverages );

  // Percentages relative to boost
  double cerealSaveP = averageCerealSave / averageBoostSave;
  double cerealLoadP = averageCerealLoad / averageBoostLoad;
  double cerealSizeP = cerealSize / static_cast<double>( boostSize );

  std::cout << "  Boost results:" << std::endl;
  std::cout << boost::format("\tsave | time: %06.4fms (%1.2f) size: %20.8fkb (%1.8f) total: %6.1fms")
    % averageBoostSave % 1.0 % (boostSize / 1024.0) % 1.0 % static_cast<double>( totalBoostSave.count() );
  std::cout << std::endl;
  std::cout << boost::format("\tload | time: %06.4fms (%1.2f) total: %6.1fms")
    % averageBoostLoad % 1.0 % static_cast<double>( totalBoostLoad.count() );
  std::cout << std::endl;

  std::cout << "  Cereal results:" << std::endl;
  std::cout << boost::format("\tsave | time: %06.4fms (%1.2f) size: %20.8fkb (%1.8f) total: %6.1fms")
    % averageCerealSave % cerealSaveP % (cerealSize / 1024.0) % cerealSizeP % static_cast<double>( totalCerealSave.count() );
  std::cout << std::endl;
  std::cout << boost::format("\tload | time: %06.4fms (%1.2f) total: %6.1fms")
    % averageCerealLoad % cerealLoadP % static_cast<double>( totalCerealLoad.count() );
  std::cout << std::endl;
}

template<class T>
typename std::enable_if<std::is_floating_point<T>::value, T>::type
random_value(std::mt19937 & gen)
{ return std::uniform_real_distribution<T>(-10000.0, 10000.0)(gen); }

template<class T>
typename std::enable_if<std::is_integral<T>::value, T>::type
random_value(std::mt19937 & gen)
{ return std::uniform_int_distribution<T>(std::numeric_limits<T>::lowest(), std::numeric_limits<T>::max())(gen); }

template<class T>
typename std::enable_if<std::is_same<T, std::string>::value, std::string>::type
random_value(std::mt19937 & gen)
{
  std::string s(std::uniform_int_distribution<int>(3, 30)(gen), ' ');
  for(char & c : s)
    c = std::uniform_int_distribution<char>(' ', '~')(gen);
  return s;
}

template<class C>
std::basic_string<C> random_basic_string(std::mt19937 & gen)
{
  std::basic_string<C> s(std::uniform_int_distribution<int>(3, 30)(gen), ' ');
  for(C & c : s)
    c = std::uniform_int_distribution<C>(' ', '~')(gen);
  return s;
}

template <size_t N>
std::string random_binary_string(std::mt19937 & gen)
{
  std::string s(N, ' ');
  for(auto & c : s )
    c = std::uniform_int_distribution<char>('0', '1')(gen);
  return s;
}

struct PoDStruct
{
  int32_t a;
  int64_t b;
  float c;
  double d;

  template <class Archive>
  void serialize( Archive & ar )
  {
    ar & a & b & c & d;
  };

  template <class Archive>
  void serialize( Archive & ar, const unsigned int version )
  {
    ar & a & b & c & d;
  };
};

struct PoDChild : PoDStruct
{
  PoDChild() : v(1024)
  { }

  std::vector<float> v;

  template <class Archive>
  void serialize( Archive & ar )
  {
    ar & static_cast<PoDStruct>(*this);
    ar & v;
  };

  template <class Archive>
  void serialize( Archive & ar, const unsigned int version )
  {
    ar & boost::serialization::base_object<PoDStruct>(*this);
    ar & v;
  };
};

int main()
{
  std::random_device rd;
  std::mt19937 gen(rd());
  auto rngC = [&](){ return random_value<uint8_t>(gen); };
  auto rngD = [&](){ return random_value<double>(gen); };
  const bool randomize = false;

  //########################################
  auto vectorDoubleTest = [&](size_t s, bool randomize)
  {
    std::ostringstream name;
    name << "Vector(double) size " << s;

    std::vector<double> data(s);
    if(randomize)
      for( auto & d : data )
        d = rngD();

    test<binary>( name.str(), data );
  };

  vectorDoubleTest(1, randomize); // 8B
  vectorDoubleTest(16, randomize); // 128B
  vectorDoubleTest(1024, randomize); // 8KB
  vectorDoubleTest(1024*1024, randomize); // 8MB

  //########################################
  auto vectorCharTest = [&](size_t s, bool randomize)
  {
    std::ostringstream name;
    name << "Vector(uint8_t) size " << s;

    std::vector<uint8_t> data(s);
    if(randomize)
      for( auto & d : data )
        d = rngC();

    test<binary>( name.str(), data );
  };

  //vectorCharTest(1024*1024*1024, randomize); // 1 GB

  //########################################
  auto vectorPoDStructTest = [&](size_t s)
  {
    std::ostringstream name;
    name << "Vector(PoDStruct) size " << s;

    std::vector<PoDStruct> data(s);
    test<binary>( name.str(), data );
  };

  vectorPoDStructTest(1);
  vectorPoDStructTest(64);
  vectorPoDStructTest(1024);
  vectorPoDStructTest(1024*1024);
  //vectorPoDStructTest(1024*1024*64);

  //########################################
  auto vectorPoDChildTest = [&](size_t s)
  {
    std::ostringstream name;
    name << "Vector(PoDChild) size " << s;

    std::vector<PoDChild> data(s);
    test<binary>( name.str(), data );
  };

  vectorPoDChildTest(1024*64);

  return 0;
}
<|endoftext|>


<commit_before>//
//  PlanetRendererBuilder.cpp
//  G3MiOSSDK
//
//  Created by Mari Luz Mateo on 22/11/12.
//
//

#include "PlanetRendererBuilder.hpp"
#include "WMSLayer.hpp"
//#include "MultiLayerTileTexturizer.hpp"
#include "DefaultTileTexturizer.hpp"
#include "PlanetTileTessellator.hpp"
#include "LayerBuilder.hpp"
#include "DownloadPriority.hpp"
#include "ElevationDataProvider.hpp"
#include "TileRasterizer.hpp"
#include "TileRenderingListener.hpp"

#include "CompositeTileRasterizer.hpp"

PlanetRendererBuilder::PlanetRendererBuilder() :
_showStatistics(false),
_renderDebug(false),
_useTilesSplitBudget(true),
_forceFirstLevelTilesRenderOnStart(true),
_incrementalTileQuality(false),
_quality(QUALITY_LOW),
_parameters(NULL),
_layerSet(NULL),
_texturizer(NULL),
_tileTessellator(NULL),
_visibleSectorListeners(NULL),
_stabilizationMilliSeconds(NULL),
_tileDownloadPriority(DownloadPriority::HIGHER),
_elevationDataProvider(NULL),
_verticalExaggeration(0),
_renderedSector(NULL),
_renderTileMeshes(true),
_logTilesPetitions(false),
_tileRenderingListener(NULL),
_changedInfoListener(NULL)
{
}

PlanetRendererBuilder::~PlanetRendererBuilder() {
  delete _parameters;
  delete _layerSet;
  delete _texturizer;

  const int tileRasterizersSize = _tileRasterizers.size();
  for (int i = 0 ; i < tileRasterizersSize; i++) {
    TileRasterizer* tileRasterizer = _tileRasterizers[i];
    delete tileRasterizer;
  }

  delete _tileTessellator;
  delete _elevationDataProvider;

  delete _renderedSector;

  delete _tileRenderingListener;
}

/**
 * Returns the _tileTessellator.
 *
 * @return _tileTessellator: TileTessellator*
 */
TileTessellator* PlanetRendererBuilder::getTileTessellator() {
  if (!_tileTessellator) {
    _tileTessellator = createTileTessellator();
  }

  return _tileTessellator;
}

TileRasterizer* PlanetRendererBuilder::getTileRasterizer() {
  const int tileRasterizersSize = _tileRasterizers.size();

  if (tileRasterizersSize == 0) {
    return NULL;
  }

  if (tileRasterizersSize == 1) {
    return _tileRasterizers[0];
  }

  CompositeTileRasterizer* result = new CompositeTileRasterizer();
  for (int i = 0; i < tileRasterizersSize; i++) {
    result->addTileRasterizer(_tileRasterizers[i]);
  }
  return result;
}

/**
 * Returns the _texturizer.
 *
 * @return _texturizer: TileTexturizer*
 */
TileTexturizer* PlanetRendererBuilder::getTexturizer() {
  if (!_texturizer) {
    _texturizer = new MultiLayerTileTexturizer();
//#warning Diego at work!
//    _texturizer = new DefaultTileTexturizer();
  }

  return _texturizer;
}

/**
 * Returns the _layerSet.
 *
 * @return _layerSet: LayerSet*
 */
LayerSet* PlanetRendererBuilder::getLayerSet() {
  if (!_layerSet) {
    _layerSet = createLayerSet();
  }

  return _layerSet;
}

/**
 * Returns the _parameters.
 *
 * @return _parameters: TilesRenderParameters*
 */
TilesRenderParameters* PlanetRendererBuilder::getParameters() {
  if (!_parameters) {
    _parameters = createPlanetRendererParameters();
  }

  return _parameters;
}

/**
 * Returns the showStatistics flag.
 *
 * @return _showStatistics: bool
 */
bool PlanetRendererBuilder::getShowStatistics() {
  return _showStatistics;
}

bool PlanetRendererBuilder::getLogTilesPetitions() {
  return _logTilesPetitions;
}

void PlanetRendererBuilder::setLogTilesPetitions(bool logTilesPetitions) {
  _logTilesPetitions = logTilesPetitions;
}

/**
 * Returns the renderDebug flag.
 *
 * @return _renderDebug: bool
 */
bool PlanetRendererBuilder::getRenderDebug() {
  return _renderDebug;
}

/**
 * Returns the useTilesSplitBudget flag.
 *
 * @return _useTilesSplitBudget: bool
 */
bool PlanetRendererBuilder::getUseTilesSplitBudget() {
  return _useTilesSplitBudget;
}

/**
 * Returns the forceFirstLevelTilesRenderOnStart flag.
 *
 * @return _forceFirstLevelTilesRenderOnStart: bool
 */
bool PlanetRendererBuilder::getForceFirstLevelTilesRenderOnStart() {
  return _forceFirstLevelTilesRenderOnStart;
}

/**
 * Returns the incrementalTileQuality flag.
 *
 * @return _incrementalTileQuality: bool
 */
bool PlanetRendererBuilder::getIncrementalTileQuality() {
  return _incrementalTileQuality;
}

Quality PlanetRendererBuilder::getQuality() const {
  return _quality;
}

void PlanetRendererBuilder::setQuality(Quality quality) {
  _quality = quality;
}

/**
 * Returns the array of visibleSectorListeners.
 */
std::vector<VisibleSectorListener*>* PlanetRendererBuilder::getVisibleSectorListeners() {
  if (!_visibleSectorListeners) {
    _visibleSectorListeners = new std::vector<VisibleSectorListener*>;
  }
  return _visibleSectorListeners;
}

/**
 * Returns the array of stabilization milliseconds related to visible-sector listeners.
 *
 * @return _stabilizationMilliSeconds: std::vector<long long>
 */
std::vector<long long>* PlanetRendererBuilder::getStabilizationMilliSeconds() {
  if (!_stabilizationMilliSeconds) {
    _stabilizationMilliSeconds = new std::vector<long long>;
  }
  return _stabilizationMilliSeconds;
}

/**
 * Returns the _tileDownloadPriority.
 *
 * @return _tileDownloadPriority: long long
 */
long long PlanetRendererBuilder::getTileDownloadPriority() {
  return _tileDownloadPriority;
}

void PlanetRendererBuilder::setTileTessellator(TileTessellator *tileTessellator) {
  if (_tileTessellator) {
    ILogger::instance()->logError("LOGIC ERROR: _tileTessellator already initialized");
    return;
  }
  _tileTessellator = tileTessellator;
}

void PlanetRendererBuilder::addTileRasterizer(TileRasterizer* tileRasterizer) {
  _tileRasterizers.push_back(tileRasterizer);
}

void PlanetRendererBuilder::setTileTexturizer(TileTexturizer *tileTexturizer) {
  if (_texturizer) {
    ILogger::instance()->logError("LOGIC ERROR: _texturizer already initialized");
    return;
  }
  _texturizer = tileTexturizer;
}

void PlanetRendererBuilder::setLayerSet(LayerSet *layerSet) {
  if (_layerSet) {
    ILogger::instance()->logError("LOGIC ERROR: _layerSet already initialized");
    return;
  }
  _layerSet = layerSet;
}

void PlanetRendererBuilder::setPlanetRendererParameters(TilesRenderParameters *parameters) {
  if (_parameters) {
    ILogger::instance()->logError("LOGIC ERROR: _parameters already initialized");
    return;
  }
  _parameters = parameters;
}

void PlanetRendererBuilder::setShowStatistics(const bool showStatistics) {
  _showStatistics = showStatistics;
}

void PlanetRendererBuilder::setRenderDebug(const bool renderDebug) {
  _renderDebug = renderDebug;
}

void PlanetRendererBuilder::setUseTilesSplitBudget(const bool useTilesSplitBudget) {
  _useTilesSplitBudget = useTilesSplitBudget;
}

void PlanetRendererBuilder::setForceFirstLevelTilesRenderOnStart(const bool forceFirstLevelTilesRenderOnStart) {
  _forceFirstLevelTilesRenderOnStart = forceFirstLevelTilesRenderOnStart;
}

void PlanetRendererBuilder::setIncrementalTileQuality(const bool incrementalTileQuality) {
  _incrementalTileQuality = incrementalTileQuality;
}

void PlanetRendererBuilder::addVisibleSectorListener(VisibleSectorListener* listener,
                                                     const TimeInterval& stabilizationInterval) {
  getVisibleSectorListeners()->push_back(listener);
  getStabilizationMilliSeconds()->push_back(stabilizationInterval._milliseconds);
}

void PlanetRendererBuilder::setTileDownloadPriority(long long tileDownloadPriority) {
  _tileDownloadPriority = tileDownloadPriority;
}

void PlanetRendererBuilder::setElevationDataProvider(ElevationDataProvider* elevationDataProvider) {
  if (_elevationDataProvider != NULL) {
    ILogger::instance()->logError("LOGIC ERROR: _elevationDataProvider already initialized");
    return;
  }
  _elevationDataProvider = elevationDataProvider;
}

void PlanetRendererBuilder::setVerticalExaggeration(float verticalExaggeration) {
  if (_verticalExaggeration > 0.0f) {
    ILogger::instance()->logError("LOGIC ERROR: _verticalExaggeration already initialized");
    return;
  }
  _verticalExaggeration = verticalExaggeration;
}

ElevationDataProvider* PlanetRendererBuilder::getElevationDataProvider() {
  return _elevationDataProvider;
}

float PlanetRendererBuilder::getVerticalExaggeration() {
  if (_verticalExaggeration <= 0.0f) {
    _verticalExaggeration = 1.0f;
  }
  return _verticalExaggeration;
}

void PlanetRendererBuilder::setTileRenderingListener(TileRenderingListener* tileRenderingListener) {
  if (_tileRenderingListener != NULL) {
    ILogger::instance()->logError("LOGIC ERROR: TileRenderingListener already set");
    return;
  }

  _tileRenderingListener = tileRenderingListener;
}

ChangedRendererInfoListener* PlanetRendererBuilder::getChangedRendererInfoListener() {
  return _changedInfoListener;
}

void PlanetRendererBuilder::setChangedRendererInfoListener(ChangedRendererInfoListener* changedInfoListener) {
  if (_changedInfoListener != NULL) {
    ILogger::instance()->logError("LOGIC ERROR: ChangedInfoListener in Planet Render Builder already set");
  } else {
    _changedInfoListener = changedInfoListener;
    ILogger::instance()->logError("LOGIC INFO: ChangedInfoListener in Planet Render Builder set OK");
  }
}

TileRenderingListener* PlanetRendererBuilder::getTileRenderingListener() {
  return _tileRenderingListener;
}

PlanetRenderer* PlanetRendererBuilder::create() {
  PlanetRenderer* planetRenderer = new PlanetRenderer(getTileTessellator(),
                                                      getElevationDataProvider(),
                                                      true,
                                                      getVerticalExaggeration(),
                                                      getTexturizer(),
                                                      getTileRasterizer(),
                                                      getLayerSet(),
                                                      getParameters(),
                                                      getShowStatistics(),
                                                      getTileDownloadPriority(),
                                                      getRenderedSector(),
                                                      getRenderTileMeshes(),
                                                      getLogTilesPetitions(),
                                                      getTileRenderingListener(),
                                                      getChangedRendererInfoListener());

  for (int i = 0; i < getVisibleSectorListeners()->size(); i++) {
    planetRenderer->addVisibleSectorListener(getVisibleSectorListeners()->at(i),
                                             TimeInterval::fromMilliseconds(getStabilizationMilliSeconds()->at(i)));
  }

  _parameters = NULL;
  _layerSet = NULL;
  _texturizer = NULL;
  _tileTessellator = NULL;
  delete _visibleSectorListeners;
  _visibleSectorListeners = NULL;
  delete _stabilizationMilliSeconds;
  _stabilizationMilliSeconds = NULL;

  _elevationDataProvider = NULL;

  delete _renderedSector;
  _renderedSector = NULL;

  _tileRenderingListener = NULL;

  _tileRasterizers.clear();

  return planetRenderer;
}

TilesRenderParameters* PlanetRendererBuilder::createPlanetRendererParameters() {
  return new TilesRenderParameters(getRenderDebug(),
                                   getUseTilesSplitBudget(),
                                   getForceFirstLevelTilesRenderOnStart(),
                                   getIncrementalTileQuality(),
                                   getQuality());
}

void PlanetRendererBuilder::setRenderTileMeshes(bool renderTileMeshes) {
  _renderTileMeshes = renderTileMeshes;
}

bool PlanetRendererBuilder::getRenderTileMeshes() {
  return _renderTileMeshes;
}

TileTessellator* PlanetRendererBuilder::createTileTessellator() {
//#warning Testing Terrain Normals
  const bool skirted = true;
  return new PlanetTileTessellator(skirted, getRenderedSector());
}

LayerSet* PlanetRendererBuilder::createLayerSet() {
  return LayerBuilder::createDefaultSatelliteImagery();
}

void PlanetRendererBuilder::setRenderedSector(const Sector& sector) {
  if (_renderedSector != NULL) {
    ILogger::instance()->logError("LOGIC ERROR: _renderedSector already initialized");
    return;
  }
  _renderedSector = new Sector(sector);
}

Sector PlanetRendererBuilder::getRenderedSector() {
  if (_renderedSector == NULL) {
    return Sector::fullSphere();
  }
  return *_renderedSector;
}

GEOTileRasterizer* PlanetRendererBuilder::createGEOTileRasterizer() {
  GEOTileRasterizer* geoTileRasterizer = new GEOTileRasterizer();
  addTileRasterizer(geoTileRasterizer);
  return geoTileRasterizer;
}
<commit_msg>Tile's image creation refactoring - merging into purgatory<commit_after>//
//  PlanetRendererBuilder.cpp
//  G3MiOSSDK
//
//  Created by Mari Luz Mateo on 22/11/12.
//
//

#include "PlanetRendererBuilder.hpp"
#include "WMSLayer.hpp"
#include "MultiLayerTileTexturizer.hpp"
//#include "DefaultTileTexturizer.hpp"
#include "PlanetTileTessellator.hpp"
#include "LayerBuilder.hpp"
#include "DownloadPriority.hpp"
#include "ElevationDataProvider.hpp"
#include "TileRasterizer.hpp"
#include "TileRenderingListener.hpp"

#include "CompositeTileRasterizer.hpp"

PlanetRendererBuilder::PlanetRendererBuilder() :
_showStatistics(false),
_renderDebug(false),
_useTilesSplitBudget(true),
_forceFirstLevelTilesRenderOnStart(true),
_incrementalTileQuality(false),
_quality(QUALITY_LOW),
_parameters(NULL),
_layerSet(NULL),
_texturizer(NULL),
_tileTessellator(NULL),
_visibleSectorListeners(NULL),
_stabilizationMilliSeconds(NULL),
_tileDownloadPriority(DownloadPriority::HIGHER),
_elevationDataProvider(NULL),
_verticalExaggeration(0),
_renderedSector(NULL),
_renderTileMeshes(true),
_logTilesPetitions(false),
_tileRenderingListener(NULL),
_changedInfoListener(NULL)
{
}

PlanetRendererBuilder::~PlanetRendererBuilder() {
  delete _parameters;
  delete _layerSet;
  delete _texturizer;

  const int tileRasterizersSize = _tileRasterizers.size();
  for (int i = 0 ; i < tileRasterizersSize; i++) {
    TileRasterizer* tileRasterizer = _tileRasterizers[i];
    delete tileRasterizer;
  }

  delete _tileTessellator;
  delete _elevationDataProvider;

  delete _renderedSector;

  delete _tileRenderingListener;
}

/**
 * Returns the _tileTessellator.
 *
 * @return _tileTessellator: TileTessellator*
 */
TileTessellator* PlanetRendererBuilder::getTileTessellator() {
  if (!_tileTessellator) {
    _tileTessellator = createTileTessellator();
  }

  return _tileTessellator;
}

TileRasterizer* PlanetRendererBuilder::getTileRasterizer() {
  const int tileRasterizersSize = _tileRasterizers.size();

  if (tileRasterizersSize == 0) {
    return NULL;
  }

  if (tileRasterizersSize == 1) {
    return _tileRasterizers[0];
  }

  CompositeTileRasterizer* result = new CompositeTileRasterizer();
  for (int i = 0; i < tileRasterizersSize; i++) {
    result->addTileRasterizer(_tileRasterizers[i]);
  }
  return result;
}

/**
 * Returns the _texturizer.
 *
 * @return _texturizer: TileTexturizer*
 */
TileTexturizer* PlanetRendererBuilder::getTexturizer() {
  if (!_texturizer) {
    _texturizer = new MultiLayerTileTexturizer();
//#warning Diego at work!
//    _texturizer = new DefaultTileTexturizer();
  }

  return _texturizer;
}

/**
 * Returns the _layerSet.
 *
 * @return _layerSet: LayerSet*
 */
LayerSet* PlanetRendererBuilder::getLayerSet() {
  if (!_layerSet) {
    _layerSet = createLayerSet();
  }

  return _layerSet;
}

/**
 * Returns the _parameters.
 *
 * @return _parameters: TilesRenderParameters*
 */
TilesRenderParameters* PlanetRendererBuilder::getParameters() {
  if (!_parameters) {
    _parameters = createPlanetRendererParameters();
  }

  return _parameters;
}

/**
 * Returns the showStatistics flag.
 *
 * @return _showStatistics: bool
 */
bool PlanetRendererBuilder::getShowStatistics() {
  return _showStatistics;
}

bool PlanetRendererBuilder::getLogTilesPetitions() {
  return _logTilesPetitions;
}

void PlanetRendererBuilder::setLogTilesPetitions(bool logTilesPetitions) {
  _logTilesPetitions = logTilesPetitions;
}

/**
 * Returns the renderDebug flag.
 *
 * @return _renderDebug: bool
 */
bool PlanetRendererBuilder::getRenderDebug() {
  return _renderDebug;
}

/**
 * Returns the useTilesSplitBudget flag.
 *
 * @return _useTilesSplitBudget: bool
 */
bool PlanetRendererBuilder::getUseTilesSplitBudget() {
  return _useTilesSplitBudget;
}

/**
 * Returns the forceFirstLevelTilesRenderOnStart flag.
 *
 * @return _forceFirstLevelTilesRenderOnStart: bool
 */
bool PlanetRendererBuilder::getForceFirstLevelTilesRenderOnStart() {
  return _forceFirstLevelTilesRenderOnStart;
}

/**
 * Returns the incrementalTileQuality flag.
 *
 * @return _incrementalTileQuality: bool
 */
bool PlanetRendererBuilder::getIncrementalTileQuality() {
  return _incrementalTileQuality;
}

Quality PlanetRendererBuilder::getQuality() const {
  return _quality;
}

void PlanetRendererBuilder::setQuality(Quality quality) {
  _quality = quality;
}

/**
 * Returns the array of visibleSectorListeners.
 */
std::vector<VisibleSectorListener*>* PlanetRendererBuilder::getVisibleSectorListeners() {
  if (!_visibleSectorListeners) {
    _visibleSectorListeners = new std::vector<VisibleSectorListener*>;
  }
  return _visibleSectorListeners;
}

/**
 * Returns the array of stabilization milliseconds related to visible-sector listeners.
 *
 * @return _stabilizationMilliSeconds: std::vector<long long>
 */
std::vector<long long>* PlanetRendererBuilder::getStabilizationMilliSeconds() {
  if (!_stabilizationMilliSeconds) {
    _stabilizationMilliSeconds = new std::vector<long long>;
  }
  return _stabilizationMilliSeconds;
}

/**
 * Returns the _tileDownloadPriority.
 *
 * @return _tileDownloadPriority: long long
 */
long long PlanetRendererBuilder::getTileDownloadPriority() {
  return _tileDownloadPriority;
}

void PlanetRendererBuilder::setTileTessellator(TileTessellator *tileTessellator) {
  if (_tileTessellator) {
    ILogger::instance()->logError("LOGIC ERROR: _tileTessellator already initialized");
    return;
  }
  _tileTessellator = tileTessellator;
}

void PlanetRendererBuilder::addTileRasterizer(TileRasterizer* tileRasterizer) {
  _tileRasterizers.push_back(tileRasterizer);
}

void PlanetRendererBuilder::setTileTexturizer(TileTexturizer *tileTexturizer) {
  if (_texturizer) {
    ILogger::instance()->logError("LOGIC ERROR: _texturizer already initialized");
    return;
  }
  _texturizer = tileTexturizer;
}

void PlanetRendererBuilder::setLayerSet(LayerSet *layerSet) {
  if (_layerSet) {
    ILogger::instance()->logError("LOGIC ERROR: _layerSet already initialized");
    return;
  }
  _layerSet = layerSet;
}

void PlanetRendererBuilder::setPlanetRendererParameters(TilesRenderParameters *parameters) {
  if (_parameters) {
    ILogger::instance()->logError("LOGIC ERROR: _parameters already initialized");
    return;
  }
  _parameters = parameters;
}

void PlanetRendererBuilder::setShowStatistics(const bool showStatistics) {
  _showStatistics = showStatistics;
}

void PlanetRendererBuilder::setRenderDebug(const bool renderDebug) {
  _renderDebug = renderDebug;
}

void PlanetRendererBuilder::setUseTilesSplitBudget(const bool useTilesSplitBudget) {
  _useTilesSplitBudget = useTilesSplitBudget;
}

void PlanetRendererBuilder::setForceFirstLevelTilesRenderOnStart(const bool forceFirstLevelTilesRenderOnStart) {
  _forceFirstLevelTilesRenderOnStart = forceFirstLevelTilesRenderOnStart;
}

void PlanetRendererBuilder::setIncrementalTileQuality(const bool incrementalTileQuality) {
  _incrementalTileQuality = incrementalTileQuality;
}

void PlanetRendererBuilder::addVisibleSectorListener(VisibleSectorListener* listener,
                                                     const TimeInterval& stabilizationInterval) {
  getVisibleSectorListeners()->push_back(listener);
  getStabilizationMilliSeconds()->push_back(stabilizationInterval._milliseconds);
}

void PlanetRendererBuilder::setTileDownloadPriority(long long tileDownloadPriority) {
  _tileDownloadPriority = tileDownloadPriority;
}

void PlanetRendererBuilder::setElevationDataProvider(ElevationDataProvider* elevationDataProvider) {
  if (_elevationDataProvider != NULL) {
    ILogger::instance()->logError("LOGIC ERROR: _elevationDataProvider already initialized");
    return;
  }
  _elevationDataProvider = elevationDataProvider;
}

void PlanetRendererBuilder::setVerticalExaggeration(float verticalExaggeration) {
  if (_verticalExaggeration > 0.0f) {
    ILogger::instance()->logError("LOGIC ERROR: _verticalExaggeration already initialized");
    return;
  }
  _verticalExaggeration = verticalExaggeration;
}

ElevationDataProvider* PlanetRendererBuilder::getElevationDataProvider() {
  return _elevationDataProvider;
}

float PlanetRendererBuilder::getVerticalExaggeration() {
  if (_verticalExaggeration <= 0.0f) {
    _verticalExaggeration = 1.0f;
  }
  return _verticalExaggeration;
}

void PlanetRendererBuilder::setTileRenderingListener(TileRenderingListener* tileRenderingListener) {
  if (_tileRenderingListener != NULL) {
    ILogger::instance()->logError("LOGIC ERROR: TileRenderingListener already set");
    return;
  }

  _tileRenderingListener = tileRenderingListener;
}

ChangedRendererInfoListener* PlanetRendererBuilder::getChangedRendererInfoListener() {
  return _changedInfoListener;
}

void PlanetRendererBuilder::setChangedRendererInfoListener(ChangedRendererInfoListener* changedInfoListener) {
  if (_changedInfoListener != NULL) {
    ILogger::instance()->logError("LOGIC ERROR: ChangedInfoListener in Planet Render Builder already set");
  } else {
    _changedInfoListener = changedInfoListener;
    ILogger::instance()->logError("LOGIC INFO: ChangedInfoListener in Planet Render Builder set OK");
  }
}

TileRenderingListener* PlanetRendererBuilder::getTileRenderingListener() {
  return _tileRenderingListener;
}

PlanetRenderer* PlanetRendererBuilder::create() {
  PlanetRenderer* planetRenderer = new PlanetRenderer(getTileTessellator(),
                                                      getElevationDataProvider(),
                                                      true,
                                                      getVerticalExaggeration(),
                                                      getTexturizer(),
                                                      getTileRasterizer(),
                                                      getLayerSet(),
                                                      getParameters(),
                                                      getShowStatistics(),
                                                      getTileDownloadPriority(),
                                                      getRenderedSector(),
                                                      getRenderTileMeshes(),
                                                      getLogTilesPetitions(),
                                                      getTileRenderingListener(),
                                                      getChangedRendererInfoListener());

  for (int i = 0; i < getVisibleSectorListeners()->size(); i++) {
    planetRenderer->addVisibleSectorListener(getVisibleSectorListeners()->at(i),
                                             TimeInterval::fromMilliseconds(getStabilizationMilliSeconds()->at(i)));
  }

  _parameters = NULL;
  _layerSet = NULL;
  _texturizer = NULL;
  _tileTessellator = NULL;
  delete _visibleSectorListeners;
  _visibleSectorListeners = NULL;
  delete _stabilizationMilliSeconds;
  _stabilizationMilliSeconds = NULL;

  _elevationDataProvider = NULL;

  delete _renderedSector;
  _renderedSector = NULL;

  _tileRenderingListener = NULL;

  _tileRasterizers.clear();

  return planetRenderer;
}

TilesRenderParameters* PlanetRendererBuilder::createPlanetRendererParameters() {
  return new TilesRenderParameters(getRenderDebug(),
                                   getUseTilesSplitBudget(),
                                   getForceFirstLevelTilesRenderOnStart(),
                                   getIncrementalTileQuality(),
                                   getQuality());
}

void PlanetRendererBuilder::setRenderTileMeshes(bool renderTileMeshes) {
  _renderTileMeshes = renderTileMeshes;
}

bool PlanetRendererBuilder::getRenderTileMeshes() {
  return _renderTileMeshes;
}

TileTessellator* PlanetRendererBuilder::createTileTessellator() {
//#warning Testing Terrain Normals
  const bool skirted = true;
  return new PlanetTileTessellator(skirted, getRenderedSector());
}

LayerSet* PlanetRendererBuilder::createLayerSet() {
  return LayerBuilder::createDefaultSatelliteImagery();
}

void PlanetRendererBuilder::setRenderedSector(const Sector& sector) {
  if (_renderedSector != NULL) {
    ILogger::instance()->logError("LOGIC ERROR: _renderedSector already initialized");
    return;
  }
  _renderedSector = new Sector(sector);
}

Sector PlanetRendererBuilder::getRenderedSector() {
  if (_renderedSector == NULL) {
    return Sector::fullSphere();
  }
  return *_renderedSector;
}

GEOTileRasterizer* PlanetRendererBuilder::createGEOTileRasterizer() {
  GEOTileRasterizer* geoTileRasterizer = new GEOTileRasterizer();
  addTileRasterizer(geoTileRasterizer);
  return geoTileRasterizer;
}
<|endoftext|>


<commit_before>/*
 * This is part of the FL library, a C++ Bayesian filtering library
 * (https://github.com/filtering-library)
 *
 * Copyright (c) 2014 Jan Issac (jan.issac@gmail.com)
 * Copyright (c) 2014 Manuel Wuthrich (manuel.wuthrich@gmail.com)
 *
 * Max-Planck Institute for Intelligent Systems, AMD Lab
 * University of Southern California, CLMC Lab
 *
 * This Source Code Form is subject to the terms of the MIT License (MIT).
 * A copy of the license can be found in the LICENSE file distributed with this
 * source code.
 */

/**
 * \file gaussian_filter_kf.hpp
 * \date October 2014
 * \author Jan Issac (jan.issac@gmail.com)
 */

#ifndef FL__FILTER__GAUSSIAN__GAUSSIAN_FILTER_KF_HPP
#define FL__FILTER__GAUSSIAN__GAUSSIAN_FILTER_KF_HPP

#include <utility>

#include <fl/util/meta.hpp>
#include <fl/util/traits.hpp>
#include <fl/util/profiling.hpp>

#include <fl/exception/exception.hpp>
#include <fl/filter/filter_interface.hpp>

#include <fl/model/process/linear_state_transition_model.hpp>
#include <fl/model/observation/linear_gaussian_observation_model.hpp>

namespace fl
{

/**
 * \defgroup linear_gaussian_filter Linear Gaussian Filter (Kalman Filter)
 * \ingroup filters
 */

// Gaussian filter forward declaration
template <typename...> class GaussianFilter;

/**
 * \internal
 * \ingroup linear_gaussian_filter
 *
 * Traits of the Linear GaussianFilter (KalmanFilter)
 */
template <typename LinearStateTransitionModel, typename LinearObservationModel>
struct Traits<
           GaussianFilter<
               LinearStateTransitionModel,
               LinearObservationModel>>
{
    typedef typename LinearStateTransitionModel::State State;
    typedef typename LinearStateTransitionModel::Input Input;
    typedef typename LinearObservationModel::Obsrv Obsrv;
    typedef Gaussian<State> Belief;
};

/**
 * \ingroup linear_gaussian_filter
 *
 * \brief GaussianFilter resembles the Kalman filter.
 *
 * \tparam State  State type defining the state space
 * \tparam Input  Process model input type
 * \tparam Obsrv  Observation type of the linear observation Gaussian model
 *
 * The KalmanFilter type is represented by the GaussianFilter using
 * the linear Gaussian Models.
 *
 */
template <
    typename LinearStateTransitionModel,
    typename LinearObservationModel
>
class GaussianFilter<
          LinearStateTransitionModel,
          LinearObservationModel>
    :
    /* Implement the conceptual filter interface */
    public
    FilterInterface<
        GaussianFilter<
            typename ForwardLinearModelOnly<LinearStateTransitionModel>::Type,
            typename ForwardLinearModelOnly<LinearObservationModel>::Type>>
{
public:
    typedef typename LinearStateTransitionModel::State State;
    typedef typename LinearStateTransitionModel::Input Input;
    typedef typename LinearObservationModel::Obsrv Obsrv;

    /**
     * \brief Represents the underlying distribution of the estimated state.
     * In the case of the Kalman filter, the distribution is a simple Gaussian
     * with the dimension of the \c State
     */
    typedef Gaussian<State> Belief;

public:
    /**
     * Creates a linear Gaussian filter (a KalmanFilter)
     *
     * \param process_model         Process model instance
     * \param obsrv_model           Obsrv model instance
     */
    GaussianFilter(const LinearStateTransitionModel& process_model,
                   const LinearObservationModel& obsrv_model)
        : process_model_(process_model),
          obsrv_model_(obsrv_model)
    { }

    /**
     * \brief Overridable default destructor
     */
    virtual ~GaussianFilter() { }

    /**
     * \copydoc FilterInterface::predict
     *
     * KalmanFilter prediction step
     *
     * Given the following matrices
     *
     *  - \f$ A \f$: Dynamics Matrix
     *  - \f$ B \f$: Dynamics Noise Covariance
     *
     * and the current state distribution
     * \f$ {\cal N}(x_t\mid \hat{x}_t, \hat{\Sigma}_{t}) \f$,
     *
     * the prediction steps is the discrete linear mapping
     *
     * \f$ \bar{x}_{t} =  A \hat{x}_t\f$ and
     *
     * \f$ \bar{\Sigma}_{t} = A\hat{\Sigma}_{t}A^T + Q \f$
     */
    virtual void predict(const Belief& prior_belief,
                         const Input& input,
                         Belief& predicted_belief)
    {
        auto A = process_model_.dynamics_matrix();
        auto B = process_model_.input_matrix();
        auto Q = process_model_.noise_covariance();

        predicted_belief.mean(
            A * prior_belief.mean() + B * input);

        predicted_belief.covariance(
            A * prior_belief.covariance() * A.transpose() + Q);
    }

    /**
     * \copydoc FilterInterface::update
     *
     * Given the following matrices
     *
     *  - \f$ H \f$: Sensor Matrix
     *  - \f$ R \f$: Sensor Noise Covariance
     *
     * and the current predicted state distribution
     * \f$ {\cal N}(x_t\mid \bar{x}_t, \bar{\Sigma}_{t}) \f$,
     *
     * the update steps is the discrete linear mapping
     *
     * \f$ \hat{x}_{t+1} =  \bar{x}_t + K (y - H\bar{x}_t)\f$ and
     *
     * \f$ \hat{\Sigma}_{t} = (I - KH) \bar{\Sigma}_{t}\f$
     *
     * with the KalmanGain
     *
     * \f$ K = \bar{\Sigma}_{t}H^T (H\bar{\Sigma}_{t}H^T+R)^{-1}\f$.
     */
    virtual void update(const Belief& predicted_belief,
                        const Obsrv& y,
                        Belief& posterior_belief)
    {
        auto H = obsrv_model_.sensor_matrix();
        auto R = obsrv_model_.noise_covariance();

        auto mean = predicted_belief.mean();
        auto cov_xx = predicted_belief.covariance();

        auto S = (H * cov_xx * H.transpose() + R).eval();
        auto K = (cov_xx * H.transpose() * S.inverse()).eval();

        posterior_belief.mean(mean + K * (y - H * mean));
        posterior_belief.covariance(cov_xx - K * H * cov_xx);
    }

    virtual Belief create_belief() const
    {
        auto belief = Belief(process_model().state_dimension());
        return belief;
    }

    virtual std::string name() const
    {
        return "GaussianFilter<"
                + this->list_arguments(
                            process_model().name(),
                            obsrv_model().name())
                + ">";
    }

    virtual std::string description() const
    {
        return "Linear Gaussian filter (the Kalman Filter) with"
                + this->list_descriptions(
                            process_model().description(),
                            obsrv_model().description());
    }

    LinearStateTransitionModel& process_model() { return process_model_; }
    LinearObservationModel& obsrv_model() { return obsrv_model_; }
    const LinearStateTransitionModel& process_model() const { return process_model_; }
    const LinearObservationModel& obsrv_model() const { return obsrv_model_; }

protected:
    /** \cond internal */
    LinearStateTransitionModel process_model_;
    LinearObservationModel obsrv_model_;
    /** \endcond */
};

}

#endif
<commit_msg>Added accessor process_model and obsrv_model to linear gaussian filter<commit_after>/*
 * This is part of the FL library, a C++ Bayesian filtering library
 * (https://github.com/filtering-library)
 *
 * Copyright (c) 2014 Jan Issac (jan.issac@gmail.com)
 * Copyright (c) 2014 Manuel Wuthrich (manuel.wuthrich@gmail.com)
 *
 * Max-Planck Institute for Intelligent Systems, AMD Lab
 * University of Southern California, CLMC Lab
 *
 * This Source Code Form is subject to the terms of the MIT License (MIT).
 * A copy of the license can be found in the LICENSE file distributed with this
 * source code.
 */

/**
 * \file gaussian_filter_linear.hpp
 * \date October 2014
 * \author Jan Issac (jan.issac@gmail.com)
 */

#ifndef FL__FILTER__GAUSSIAN__GAUSSIAN_FILTER_KF_HPP
#define FL__FILTER__GAUSSIAN__GAUSSIAN_FILTER_KF_HPP

#include <utility>

#include <fl/util/meta.hpp>
#include <fl/util/traits.hpp>
#include <fl/util/profiling.hpp>

#include <fl/exception/exception.hpp>
#include <fl/filter/filter_interface.hpp>

#include <fl/model/process/linear_state_transition_model.hpp>
#include <fl/model/observation/linear_gaussian_observation_model.hpp>

namespace fl
{

/**
 * \defgroup linear_gaussian_filter Linear Gaussian Filter (Kalman Filter)
 * \ingroup filters
 */

// Gaussian filter forward declaration
template <typename...> class GaussianFilter;

/**
 * \internal
 * \ingroup linear_gaussian_filter
 *
 * Traits of the Linear GaussianFilter (KalmanFilter)
 */
template <typename LinearStateTransitionModel, typename LinearObservationModel>
struct Traits<
           GaussianFilter<
               LinearStateTransitionModel,
               LinearObservationModel>>
{
    typedef typename LinearStateTransitionModel::State State;
    typedef typename LinearStateTransitionModel::Input Input;
    typedef typename LinearObservationModel::Obsrv Obsrv;
    typedef Gaussian<State> Belief;
};

/**
 * \ingroup linear_gaussian_filter
 *
 * \brief GaussianFilter resembles the Kalman filter.
 *
 * \tparam State  State type defining the state space
 * \tparam Input  Process model input type
 * \tparam Obsrv  Observation type of the linear observation Gaussian model
 *
 * The KalmanFilter type is represented by the GaussianFilter using
 * the linear Gaussian Models.
 *
 */
template <
    typename LinearStateTransitionModel,
    typename LinearObservationModel
>
class GaussianFilter<
          LinearStateTransitionModel,
          LinearObservationModel>
    :
    /* Implement the conceptual filter interface */
    public
    FilterInterface<
        GaussianFilter<
            typename ForwardLinearModelOnly<LinearStateTransitionModel>::Type,
            typename ForwardLinearModelOnly<LinearObservationModel>::Type>>
{
public:
    typedef typename LinearStateTransitionModel::State State;
    typedef typename LinearStateTransitionModel::Input Input;
    typedef typename LinearObservationModel::Obsrv Obsrv;

    /**
     * \brief Represents the underlying distribution of the estimated state.
     * In the case of the Kalman filter, the distribution is a simple Gaussian
     * with the dimension of the \c State
     */
    typedef Gaussian<State> Belief;

public:
    /**
     * Creates a linear Gaussian filter (a KalmanFilter)
     *
     * \param process_model         Process model instance
     * \param obsrv_model           Obsrv model instance
     */
    GaussianFilter(const LinearStateTransitionModel& process_model,
                   const LinearObservationModel& obsrv_model)
        : process_model_(process_model),
          obsrv_model_(obsrv_model)
    { }

    /**
     * \brief Overridable default destructor
     */
    virtual ~GaussianFilter() { }

    /**
     * \copydoc FilterInterface::predict
     *
     * KalmanFilter prediction step
     *
     * Given the following matrices
     *
     *  - \f$ A \f$: Dynamics Matrix
     *  - \f$ B \f$: Dynamics Noise Covariance
     *
     * and the current state distribution
     * \f$ {\cal N}(x_t\mid \hat{x}_t, \hat{\Sigma}_{t}) \f$,
     *
     * the prediction steps is the discrete linear mapping
     *
     * \f$ \bar{x}_{t} =  A \hat{x}_t\f$ and
     *
     * \f$ \bar{\Sigma}_{t} = A\hat{\Sigma}_{t}A^T + Q \f$
     */
    virtual void predict(const Belief& prior_belief,
                         const Input& input,
                         Belief& predicted_belief)
    {
        auto A = process_model_.dynamics_matrix();
        auto B = process_model_.input_matrix();
        auto Q = process_model_.noise_covariance();

        predicted_belief.mean(
            A * prior_belief.mean() + B * input);

        predicted_belief.covariance(
            A * prior_belief.covariance() * A.transpose() + Q);
    }

    /**
     * \copydoc FilterInterface::update
     *
     * Given the following matrices
     *
     *  - \f$ H \f$: Sensor Matrix
     *  - \f$ R \f$: Sensor Noise Covariance
     *
     * and the current predicted state distribution
     * \f$ {\cal N}(x_t\mid \bar{x}_t, \bar{\Sigma}_{t}) \f$,
     *
     * the update steps is the discrete linear mapping
     *
     * \f$ \hat{x}_{t+1} =  \bar{x}_t + K (y - H\bar{x}_t)\f$ and
     *
     * \f$ \hat{\Sigma}_{t} = (I - KH) \bar{\Sigma}_{t}\f$
     *
     * with the KalmanGain
     *
     * \f$ K = \bar{\Sigma}_{t}H^T (H\bar{\Sigma}_{t}H^T+R)^{-1}\f$.
     */
    virtual void update(const Belief& predicted_belief,
                        const Obsrv& y,
                        Belief& posterior_belief)
    {
        auto H = obsrv_model_.sensor_matrix();
        auto R = obsrv_model_.noise_covariance();

        auto mean = predicted_belief.mean();
        auto cov_xx = predicted_belief.covariance();

        auto S = (H * cov_xx * H.transpose() + R).eval();
        auto K = (cov_xx * H.transpose() * S.inverse()).eval();

        posterior_belief.mean(mean + K * (y - H * mean));
        posterior_belief.covariance(cov_xx - K * H * cov_xx);
    }

    virtual Belief create_belief() const
    {
        auto belief = Belief(process_model().state_dimension());
        return belief;
    }

    virtual std::string name() const
    {
        return "GaussianFilter<"
                + this->list_arguments(
                            process_model().name(),
                            obsrv_model().name())
                + ">";
    }

    virtual std::string description() const
    {
        return "Linear Gaussian filter (the Kalman Filter) with"
                + this->list_descriptions(
                            process_model().description(),
                            obsrv_model().description());
    }

    LinearStateTransitionModel& process_model()
    {
        return process_model_;
    }

    LinearObservationModel& obsrv_model()
    {
        return obsrv_model_;
    }

    const LinearStateTransitionModel& process_model() const
    {
        return process_model_;
    }

    const LinearObservationModel& obsrv_model() const
    {
        return obsrv_model_;
    }

protected:
    /** \cond internal */
    LinearStateTransitionModel process_model_;
    LinearObservationModel obsrv_model_;
    /** \endcond */
};

}

#endif
<|endoftext|>


<commit_before>
// =================================================================================================
// This file is part of the CLBlast project. The project is licensed under Apache Version 2.0. This
// project loosely follows the Google C++ styleguide and uses a tab-size of two spaces and a max-
// width of 100 characters per line.
//
// Author(s):
//   Cedric Nugteren <www.cedricnugteren.nl>
//
// This file demonstrates the use of the SGEMM routine. It is a stand-alone example, but it does
// require the Khronos C++ OpenCL API header file (downloaded by CMake). The example uses C++
// features, but CLBlast can also be used using the regular C-style OpenCL API.
//
// Note that this example is meant for illustration purposes only. CLBlast provides other programs
// for performance benchmarking ('client_xxxxx') and for correctness testing ('test_xxxxx').
//
// =================================================================================================

#include <cstdio>
#include <chrono>
#include <vector>

// Includes the C++ OpenCL API. If not yet available, it can be found here:
// https://www.khronos.org/registry/cl/api/1.1/cl.hpp
#include "cl.hpp"

// Includes the CLBlast library
#include <clblast.h>

// =================================================================================================

// Example use of the single-precision Xgemm routine SGEMM
int main() {

  // OpenCL platform/device settings
  const auto platform_id = 0;
  const auto device_id = 0;

  // Example SGEMM arguments
  const size_t m = 128;
  const size_t n = 64;
  const size_t k = 512;
  const float alpha = 0.7f;
  const float beta = 1.0f;
  const auto a_ld = k;
  const auto b_ld = n;
  const auto c_ld = n;

  // Initializes the OpenCL platform
  auto platforms = std::vector<cl::Platform>();
  cl::Platform::get(&platforms);
  if (platforms.size() == 0 || platform_id >= platforms.size()) { return 1; }
  auto platform = platforms[platform_id];

  // Initializes the OpenCL device (note: example for GPU devices only)
  auto devices = std::vector<cl::Device>();
  platform.getDevices(CL_DEVICE_TYPE_GPU, &devices);
  if (devices.size() == 0 || device_id >= devices.size()) { return 1; }
  auto device = devices[device_id];

  // Creates the OpenCL context, queue, and an event
  auto context = cl::Context({device});
  auto queue = cl::CommandQueue(context, device);
  auto event = cl_event{nullptr};

  // Populate host matrices with some example data
  auto host_a = std::vector<float>(m*k);
  auto host_b = std::vector<float>(n*k);
  auto host_c = std::vector<float>(m*n);
  for (auto &item: host_a) { item = 12.193f; }
  for (auto &item: host_b) { item = -8.199f; }
  for (auto &item: host_c) { item = 0.0f; }

  // Copy the matrices to the device
  auto device_a = cl::Buffer(context, CL_MEM_READ_WRITE, host_a.size()*sizeof(float));
  auto device_b = cl::Buffer(context, CL_MEM_READ_WRITE, host_b.size()*sizeof(float));
  auto device_c = cl::Buffer(context, CL_MEM_READ_WRITE, host_c.size()*sizeof(float));
  queue.enqueueWriteBuffer(device_a, CL_TRUE, 0, host_a.size()*sizeof(float), host_a.data());
  queue.enqueueWriteBuffer(device_b, CL_TRUE, 0, host_b.size()*sizeof(float), host_b.data());
  queue.enqueueWriteBuffer(device_c, CL_TRUE, 0, host_c.size()*sizeof(float), host_c.data());

  // Start the timer
  auto start_time = std::chrono::steady_clock::now();

  // Call the SGEMM routine. Note that the type of alpha and beta (float) determine the precision.
  auto queue_plain = queue();
  auto status = Gemm(clblast::Layout::kRowMajor,
                     clblast::Transpose::kNo, clblast::Transpose::kNo,
                     m, n, k,
                     alpha,
                     device_a(), 0, a_ld,
                     device_b(), 0, b_ld,
                     beta,
                     device_c(), 0, c_ld,
                     &queue_plain, &event);

  // Record the execution time
  clWaitForEvents(1, &event);
  auto elapsed_time = std::chrono::steady_clock::now() - start_time;
  auto time_ms = std::chrono::duration<double,std::milli>(elapsed_time).count();

  // Example completed. See "clblast.h" for status codes (0 -> success).
  printf("Completed in %.3lf ms with status %d\n", time_ms, status);
  return 0;
}

// =================================================================================================
<commit_msg>Added missing namespace to the SGEMM example<commit_after>
// =================================================================================================
// This file is part of the CLBlast project. The project is licensed under Apache Version 2.0. This
// project loosely follows the Google C++ styleguide and uses a tab-size of two spaces and a max-
// width of 100 characters per line.
//
// Author(s):
//   Cedric Nugteren <www.cedricnugteren.nl>
//
// This file demonstrates the use of the SGEMM routine. It is a stand-alone example, but it does
// require the Khronos C++ OpenCL API header file (downloaded by CMake). The example uses C++
// features, but CLBlast can also be used using the regular C-style OpenCL API.
//
// Note that this example is meant for illustration purposes only. CLBlast provides other programs
// for performance benchmarking ('client_xxxxx') and for correctness testing ('test_xxxxx').
//
// =================================================================================================

#include <cstdio>
#include <chrono>
#include <vector>

// Includes the C++ OpenCL API. If not yet available, it can be found here:
// https://www.khronos.org/registry/cl/api/1.1/cl.hpp
#include "cl.hpp"

// Includes the CLBlast library
#include <clblast.h>

// =================================================================================================

// Example use of the single-precision Xgemm routine SGEMM
int main() {

  // OpenCL platform/device settings
  const auto platform_id = 0;
  const auto device_id = 0;

  // Example SGEMM arguments
  const size_t m = 128;
  const size_t n = 64;
  const size_t k = 512;
  const float alpha = 0.7f;
  const float beta = 1.0f;
  const auto a_ld = k;
  const auto b_ld = n;
  const auto c_ld = n;

  // Initializes the OpenCL platform
  auto platforms = std::vector<cl::Platform>();
  cl::Platform::get(&platforms);
  if (platforms.size() == 0 || platform_id >= platforms.size()) { return 1; }
  auto platform = platforms[platform_id];

  // Initializes the OpenCL device (note: example for GPU devices only)
  auto devices = std::vector<cl::Device>();
  platform.getDevices(CL_DEVICE_TYPE_GPU, &devices);
  if (devices.size() == 0 || device_id >= devices.size()) { return 1; }
  auto device = devices[device_id];

  // Creates the OpenCL context, queue, and an event
  auto context = cl::Context({device});
  auto queue = cl::CommandQueue(context, device);
  auto event = cl_event{nullptr};

  // Populate host matrices with some example data
  auto host_a = std::vector<float>(m*k);
  auto host_b = std::vector<float>(n*k);
  auto host_c = std::vector<float>(m*n);
  for (auto &item: host_a) { item = 12.193f; }
  for (auto &item: host_b) { item = -8.199f; }
  for (auto &item: host_c) { item = 0.0f; }

  // Copy the matrices to the device
  auto device_a = cl::Buffer(context, CL_MEM_READ_WRITE, host_a.size()*sizeof(float));
  auto device_b = cl::Buffer(context, CL_MEM_READ_WRITE, host_b.size()*sizeof(float));
  auto device_c = cl::Buffer(context, CL_MEM_READ_WRITE, host_c.size()*sizeof(float));
  queue.enqueueWriteBuffer(device_a, CL_TRUE, 0, host_a.size()*sizeof(float), host_a.data());
  queue.enqueueWriteBuffer(device_b, CL_TRUE, 0, host_b.size()*sizeof(float), host_b.data());
  queue.enqueueWriteBuffer(device_c, CL_TRUE, 0, host_c.size()*sizeof(float), host_c.data());

  // Start the timer
  auto start_time = std::chrono::steady_clock::now();

  // Call the SGEMM routine. Note that the type of alpha and beta (float) determine the precision.
  auto queue_plain = queue();
  auto status = clblast::Gemm(clblast::Layout::kRowMajor,
                              clblast::Transpose::kNo, clblast::Transpose::kNo,
                              m, n, k,
                              alpha,
                              device_a(), 0, a_ld,
                              device_b(), 0, b_ld,
                              beta,
                              device_c(), 0, c_ld,
                              &queue_plain, &event);

  // Record the execution time
  clWaitForEvents(1, &event);
  auto elapsed_time = std::chrono::steady_clock::now() - start_time;
  auto time_ms = std::chrono::duration<double,std::milli>(elapsed_time).count();

  // Example completed. See "clblast.h" for status codes (0 -> success).
  printf("Completed in %.3lf ms with status %d\n", time_ms, status);
  return 0;
}

// =================================================================================================
<|endoftext|>