Program Listing for File system_state.h

Return to documentation for file (src/rlenvs/dynamics/system_state.h)

#ifndef SYSTEM_STATE_H
#define SYSTEM_STATE_H

#include "rlenvs/rlenvs_types_v2.h"

#include <string>
#include <array>
#include <utility>
#include <algorithm>
#include <vector>
#include <ostream>
#include <stdexcept>
#include <iomanip> // std::setprecision

namespace rlenvscpp{
namespace dynamics{

template<int dim>
class SysState
{

public:

    static const int dimension = dim;

    typedef std::array<std::pair<std::string, real_t>, dim> value_type;

    template<int dim1, int dim2>
    static void extract(const SysState<dim1>& state, SysState<dim2>& other);

    SysState();

    SysState(std::array<std::pair<std::string, real_t>, dim>&& values);

    SysState(std::array<std::string, dim>&& names, real_t val);

    SysState(const SysState<dim>& other);

    template<int other_dim>
    SysState(const SysState<other_dim>& other);

    SysState& operator=(const SysState<dim>& other);

    SysState(SysState&& other);

    SysState& operator=(SysState&& other);

    SysState& operator+=(const DynVec<real_t>& vec);

    SysState& operator-=(const DynVec<real_t>& vec);

    SysState& operator*=(real_t val);

    real_t get(const std::string& name)const;

    DynVec<real_t> as_vector()const;

    void set(const std::string& name, real_t val);

    void set(uint_t i, const std::pair<std::string, real_t>& value);

    void add(const DynVec<real_t>& container);

    void add(const std::vector<real_t>& container);

    uint_t size()const{return dim;}

    const std::array<real_t, dim> get_values()const;

    const std::vector<std::string_view> get_names()const;

    real_t& operator[](uint_t);

    const real_t& operator[](uint_t)const;

    real_t& operator[](const std::string& name){return this->operator()(name);}

    const real_t& operator[](const std::string& name)const{return this->operator()(name);}

    real_t& operator()(const std::string& name);

    const real_t& operator()(const std::string& name)const;

    real_t& operator()(const std::string_view name){return (*this)(std::string(name));}

    const real_t& operator()(const std::string_view name)const{return (*this)(std::string(name));}

    void clear();

    std::ostream& print(std::ostream& out)const;

    const std::string as_string()const;

    void scale(real_t val);

    template<typename Container>
    void set(const Container& container);

    //template<typename Container>
    //Container get_values_view(uint_t start, uint_t end)const;

private:

    std::array<std::pair<std::string, real_t>, dim> values_;

};

template<int dim>
template<int dim1, int dim2>
void
SysState<dim>::extract(const SysState<dim1>& state, SysState<dim2>& other){

    static_assert (dim2 <= dim1, "Invalid dimension dim2 > dim1");

    for(auto& name:other.get_names()){

        auto value = state(name);
        other.set(std::string(name), value);
    }
}

template<int dim>
SysState<dim>::SysState()
    :
   values_()
{
    std::for_each(values_.begin(), values_.end(),
                  [](std::pair<std::string, real_t>& item){

        item.first= "NO NAME";
        item.second = 0.0;
    });
}

template<int dim>
SysState<dim>::SysState(std::array<std::pair<std::string, real_t>, dim>&& values)
    :
    values_(values)
{}

template<int dim>
SysState<dim>::SysState(std::array<std::string, dim>&& names, real_t val)
    :
   values_()
{
    for(uint_t i=0; i<dim; ++i){
        values_[i] = std::pair(names[i], val);
    }
}

template<int dim>
SysState<dim>::SysState(const SysState<dim>& other)
    :
      values_(other.values_)
{}

template<int dim>
template<int other_dim>
SysState<dim>::SysState(const SysState<other_dim>& other)
    :
      values_()
{
    static_assert (dim <= other_dim, "Invalid dimension: dim < other_dim" );

    auto names = other.get_names();
    auto values = other.get_values();

    for(uint_t i=0; i<dim; ++i){
        values_[i] = std::make_pair(names[i], values[i]);
    }
}

template<int dim>
SysState<dim>&
SysState<dim>::operator=(const SysState<dim>& other){

    if(this == &other){
        return *this;
    }

    this->values_ = other.values_;
    return *this;
}

template<int dim>
SysState<dim>::SysState(SysState&& other)
    :
      values_(other.values_)
{
    other.clear();
}

template<int dim>
SysState<dim>&
SysState<dim>::operator=(SysState&& other){

    if(this == &other){
        return *this;
    }

    this->values_ = other.values_;
    other.clear();
    return *this;
}

template<int dim>
SysState<dim>&
SysState<dim>::operator+=(const DynVec<real_t>& vec){
    add(vec);
    return *this;
}

template<int dim>
SysState<dim>&
SysState<dim>::operator-=(const DynVec<real_t>& vec){
    add(-1.0*vec);
    return *this;
}

template<int dim>
SysState<dim>&
SysState<dim>::operator*=(real_t val){
    scale(val);
    return *this;
}

template<int dim>
void
SysState<dim>::scale(real_t val){
    std::for_each(values_.begin(),
                  values_.end(),
                  [=](auto& item){
        item.second *= val;
    });
}

template<int dim>
real_t
SysState<dim>::get(const std::string& name)const{


    auto itr = std::find_if(values_.begin(), values_.end(),
                         [&](const std::pair<std::string, real_t>& item){
        return item.first == name;
    });

    if(itr == values_.end()){
        auto error_msg("Invalid variable name. Name ");
        auto names = get_names();
        std::string name_strs("[");
        for(auto& name:names){

            name_strs += std::string(name);
            name_strs += std::string(",");
        }

        name_strs += std::string("]");
        throw std::invalid_argument(error_msg +
                                    name+
                                    std::string(" not in: ")+ name_strs);
    }

    return itr->second;
}

template<int dim>
DynVec<real_t>
SysState<dim>::as_vector()const{

    DynVec<real_t> vec(dim, 0.0);

    for(uint_t v=0; v<values_.size(); ++v){
        vec[v] = values_[v].second;
    }

    return vec;
}

template<int dim>
void
SysState<dim>::set(const std::string& name, real_t val){

    auto itr = std::find_if(values_.begin(), values_.end(),
                         [&](const std::pair<std::string, real_t>& item){
        return item.first == name;
    });

    if(itr == values_.end()){
        auto error_msg("Invalid variable name. Name ");
        auto names = get_names();
        std::string name_strs("[");
        for(auto& name:names){

            name_strs += std::string(name);
            name_strs += std::string(",");
        }

        name_strs += std::string("]");
        throw std::invalid_argument(error_msg +
                                    name+
                                    std::string(" not in: ")+ name_strs);
    }

    itr->second = val;
}

template<int dim>
template<typename Container>
void
SysState<dim>::set(const Container& container){

    if(container.size() != dim){
        throw std::invalid_argument("Container has incorrect size: "+
                                    std::to_string(container.size()) +
                                    " not equal to "+
                                    std::to_string(dim));
    }

    uint counter = 0;
    std::for_each(values_.begin(),
                  values_.end(),
                  [&](auto& arg){arg.second = container[counter++];});
}

template<int dim>
void
SysState<dim>::set(uint_t i, const std::pair<std::string, real_t>& value){
    values_[i] = value;
}

template<int dim>
real_t&
SysState<dim>::operator[](uint_t i){
    return values_[i].second;
}

template<int dim>
const real_t&
SysState<dim>::operator[](uint_t i)const{
    return values_[i].second;
}

template<int dim>
real_t&
SysState<dim>::operator()(const std::string& name){

    auto itr = std::find_if(values_.begin(), values_.end(),
                         [&](const std::pair<std::string, real_t>& item){
        return item.first == name;
    });

    if(itr == values_.end()){
        auto error_msg("Invalid variable name. Name ");
        auto names = get_names();
        std::string name_strs("[");
        for(auto& name:names){

            name_strs += std::string(name);
            name_strs += std::string(",");
        }

        name_strs += std::string("]");
        throw std::invalid_argument(error_msg +
                                    name+
                                    std::string(" not in: ")+ name_strs);
    }

    return itr->second;
}

template<int dim>
const real_t&
SysState<dim>::operator()(const std::string& name)const{

    auto itr = std::find_if(values_.begin(), values_.end(),
                         [&](const std::pair<std::string, real_t>& item){
        return item.first == name;
    });

   if(itr == values_.end()){
        auto error_msg("Invalid variable name. Name ");
        auto names = get_names();
        std::string name_strs("[");
        for(auto& name:names){

            name_strs += std::string(name);
            name_strs += std::string(",");
        }

        name_strs += std::string("]");
        throw std::invalid_argument(error_msg +
                                    name+
                                    std::string(" not in: ")+ name_strs);
    }

    return itr->second;
}

template<int dim>
void
SysState<dim>::clear(){

    std::for_each(values_.begin(), values_.end(),
                  [](std::pair<std::string, real_t>& item){
        item.second = 0.0;
    });
}

template<int dim>
const std::array<real_t, dim>
SysState<dim>::get_values()const{

    std::array<real_t, dim> copy;

    for(uint_t i=0; i<dim; ++i){
        copy[i] = values_[i].second;
    }

    return copy;
}

template<int dim>
const std::vector<std::string_view>
SysState<dim>::get_names()const{

    std::vector<std::string_view> copy(dim);

    for(uint_t i=0; i<dim; ++i){
        copy[i] = values_[i].first;
    }

    return copy;

}

template<int dim>
std::ostream&
SysState<dim>::print(std::ostream& out)const{

    out<<std::fixed << std::setprecision(4);

    std::for_each(values_.begin(), values_.end(),
              [&](const std::pair<std::string, real_t>& vals){
       out<<vals.first<<":"<<vals.second<<std::endl;
    });

    return out;
}

template<int dim>
const std::string
SysState<dim>::as_string()const{

    std::string result;

    std::for_each(values_.begin(), values_.end(),
              [&](const std::pair<std::string, real_t>& vals){
       result += vals.first;
       result += ":";
       result += std::to_string(vals.second);
       result += ",";
    });

    return result;

}

template<int dim>
void
SysState<dim>::add(const DynVec<real_t>& container){
    if(container.size() != dim){
        throw std::logic_error("Invalid container size for update. "+
                               std::to_string(container.size())+
                               " should be"+
                               std::to_string(dim));
    }

    for(uint_t i=0; i<dim; ++i){
        values_[i].second += container[i];
    }
}

template<int dim>
void
SysState<dim>::add(const std::vector<real_t>& container){
    if(container.size() != dim){
        throw std::logic_error("Invalid container size for update. "+
                               std::to_string(container.size())+
                               " should be"+
                               std::to_string(dim));
    }

    for(uint_t i=0; i<dim; ++i){
        values_[i].second += container[i];
    }
}

template<int dim>
inline
std::ostream& operator<<(std::ostream& out, const SysState<dim>& state){
    return state.print(out);
}

}

}

#endif // SYSTEM_STATE_H