<commit_before>#ifndef DESOLIN_TG_OBJECTS_HPP
#define DESOLIN_TG_OBJECTS_HPP

#include <boost/functional/hash.hpp>
#include <typeinfo>
#include <cassert>
#include <string>
#include <map>
#include <boost/format.hpp>
#include <TaskGraph>
#include <desolin/tg/Desolin_tg_fwd.hpp>

namespace desolin_internal
{

template<typename T_elementType>
class TGScalar
{
public:
  virtual const TGScalarExpr<T_elementType> getExpression() const = 0;
  virtual void setExpression(const TGScalarExpr<T_elementType>& e) = 0;
  virtual void addExpression(const TGScalarExpr<T_elementType>& e) = 0;
  virtual ~TGScalar() {}
  virtual InternalScalar<T_elementType>* createInternalRep() const = 0;
  virtual bool isParameter() const = 0;
  virtual void addParameterMappings(InternalScalar<T_elementType>& internal, ParameterHolder& params) const = 0;
  virtual std::size_t hashValue() const = 0;
};

template<typename T_elementType>
class TGVector
{
public:
  virtual const TGScalarExpr<T_elementType> getExpression(const tg::TaskExpression& row) const = 0;
  virtual void setExpression(const tg::TaskExpression& row, const TGScalarExpr<T_elementType>& e) = 0;
  virtual void addExpression(const tg::TaskExpression& row, const TGScalarExpr<T_elementType>& e) = 0;
  virtual int getRows() const = 0;
  virtual ~TGVector() {}
  virtual InternalVector<T_elementType>* createInternalRep() const = 0;
  virtual bool isParameter() const = 0;
  virtual void addParameterMappings(InternalVector<T_elementType>& internal, ParameterHolder& params) const = 0;
  virtual std::size_t hashValue() const = 0;
};

template<typename T_elementType>
class TGMatrix
{
public:
  virtual const TGScalarExpr<T_elementType> getExpression(const tg::TaskExpression& row, const tg::TaskExpression& col) const = 0;
  virtual void setExpression(const tg::TaskExpression& row, const tg::TaskExpression& col, const TGScalarExpr<T_elementType>& e) = 0;
  virtual void addExpression(const tg::TaskExpression& row, const tg::TaskExpression& col, const TGScalarExpr<T_elementType>& e) = 0;
  virtual int getRows() const = 0;
  virtual int getCols() const = 0;
  virtual ~TGMatrix() {}
  virtual InternalMatrix<T_elementType>* createInternalRep() const = 0;
  virtual bool isParameter() const = 0;
  virtual void addParameterMappings(InternalMatrix<T_elementType>& internal, ParameterHolder& params) const = 0;
  virtual std::size_t hashValue() const = 0;
};

template<typename T_elementType>
class TGScalarExpr
{
  const tg::TaskExpression expr;

public:
  TGScalarExpr() : expr(0)
  {
  }

  TGScalarExpr(const tg::TaskExpression& e) : expr(e)
  {
  }

  inline const tg::TaskExpression getExpression() const
  {
    return expr;
  }

  inline const TGScalarExpr mul(const TGScalarExpr& right) const
  {
    return TGScalarExpr(expr*right.expr);
  }

  inline const TGScalarExpr div(const TGScalarExpr& right) const
  {
    return TGScalarExpr(expr/right.expr);
  }

  inline const TGScalarExpr add(const TGScalarExpr& right) const
  {
    return TGScalarExpr(expr+right.expr);
  }

  inline const TGScalarExpr sub(const TGScalarExpr& right) const
  {
    return TGScalarExpr(expr-right.expr);
  }

  inline const TGScalarExpr sqrt() const
  {
    return TGScalarExpr(tSqrt(expr));
  }

  inline const TGScalarExpr abs() const
  {
    return TGScalarExpr(tAbs(expr));
  }

  inline const TGScalarExpr negate() const
  {
    return TGScalarExpr(-expr);
  }
};

template<typename T_elementType>
class TGConventionalScalar : public TGScalar<T_elementType>
{
  friend class Mapper;

private:
  const bool parameter;
  const std::string name;
  tg::TaskScalarVariable value;

  static tg::TaskScalarVariable createValue(bool param, const std::string& name)
  {
    if (param)
    {
      tParameter(tVarNamedTemplateType(T_elementType, val, name.c_str()));
      return val;
    }
    else
    {
      tVarNamedTemplateType(T_elementType, val, name.c_str());
      return val;
    }
  }

  static inline const std::string getPrefix()
  {
    return std::string("convScalar");
  }

public:
  TGConventionalScalar(NameGenerator& generator, const ConventionalScalar<T_elementType>& internal) : parameter(true), name(generator.getName(getPrefix())), value(createValue(true, name))
  {
  }

  TGConventionalScalar(bool param, NameGenerator& generator, const ExprNode<scalar, T_elementType>& s) : parameter(param), name(generator.getName(getPrefix())), value(createValue(param, name))
  {
  }

  const TGScalarExpr<T_elementType> getExpression() const
  {
    return TGScalarExpr<T_elementType>(value);
  }

  void setExpression(const TGScalarExpr<T_elementType>& e)
  {
    value = e.getExpression();
  }

  void addExpression(const TGScalarExpr<T_elementType>& e)
  {
    value += e.getExpression();
  }

  virtual InternalScalar<T_elementType>* createInternalRep() const
  {
    assert(parameter);
    return new ConventionalScalar<T_elementType>();
  }

  virtual bool isParameter() const
  {
    return parameter;
  }

  virtual std::size_t hashValue() const
  {
    std::size_t seed = boost::hash<std::string>()(typeid(*this).name());
    boost::hash_combine(seed, parameter);
    return seed;
  }

  virtual void addParameterMappings(InternalScalar<T_elementType>& internal, ParameterHolder& params) const
  {
    assert(parameter);
    Mapper mapper(*this, params);
    internal.accept(mapper);
  }

  class Mapper : public InternalScalarVisitor<T_elementType>
  {
  private:
    const TGConventionalScalar<T_elementType>& internal;
    ParameterHolder& parameterHolder;

  public:
    Mapper(const TGConventionalScalar<T_elementType>& i, ParameterHolder& p) : internal(i), parameterHolder(p)
    {
    }

    virtual void visit(ConventionalScalar<T_elementType>& s)
    {
      assert(s.isAllocated());
      parameterHolder.addParameter(internal.name, s.getValue());
    }
  };
};

template<typename T_elementType>
class TGConventionalVector : public TGVector<T_elementType>
{
private:
  const bool parameter;
  const std::string name;
  const int rows;
  tg::TaskArray<1> value;

  static tg::TaskArray<1> createValue(bool param, const std::string& name, int rows)
  {
    unsigned dims[1] = {rows};
    if (param)
    {
      tParameter(tArrayFromListNamed(T_elementType, val, 1, dims, name.c_str()));
      return val;
    }
    else
    {
      tArrayFromListNamed(T_elementType, val, 1, dims, name.c_str());
      return val;
    }
  }

  static inline const std::string getPrefix()
  {
    return std::string("convVector");
  }

public:
  TGConventionalVector(NameGenerator& generator, const ConventionalVector<T_elementType>& internal) :  parameter(true), name(generator.getName(getPrefix())), rows(internal.getRowCount()), value(createValue(true, name, rows))
  {
  }

  TGConventionalVector(bool param, NameGenerator& generator, const ExprNode<vector, T_elementType>& v) :  parameter(param), name(generator.getName(getPrefix())), rows(v.getRowCount()), value(createValue(param, name, rows))
  {
  }

  const TGScalarExpr<T_elementType> getExpression(const tg::TaskExpression& row) const
  {
    return TGScalarExpr<T_elementType>(value[row]);
  }

  void setExpression(const tg::TaskExpression& row, const TGScalarExpr<T_elementType>& e)
  {
    value[row] = e.getExpression();
  }

  void addExpression(const tg::TaskExpression& row, const TGScalarExpr<T_elementType>& e)
  {
    value[row] += e.getExpression();
  }

  virtual int getRows() const
  {
    return rows;
  }

  virtual InternalVector<T_elementType>* createInternalRep() const
  {
    assert(parameter);
    return new ConventionalVector<T_elementType>(rows);
  }

  virtual bool isParameter() const
  {
    return parameter;
  }

  virtual void addParameterMappings(InternalVector<T_elementType>& internal, ParameterHolder& params) const
  {
    assert(parameter);
    Mapper mapper(*this, params);
    internal.accept(mapper);
  }

  virtual std::size_t hashValue() const
  {
    std::size_t seed = boost::hash<std::string>()(typeid(*this).name());
    boost::hash_combine(seed, parameter);
    boost::hash_combine(seed, rows);
    return seed;
  }

  class Mapper : public InternalVectorVisitor<T_elementType>
  {
  private:
    const TGConventionalVector<T_elementType>& internal;
    ParameterHolder& parameterHolder;

  public:
    Mapper(const TGConventionalVector<T_elementType>& i, ParameterHolder& p) : internal(i), parameterHolder(p)
    {
    }

    virtual void visit(ConventionalVector<T_elementType>& v)
    {
      assert(v.isAllocated());
      parameterHolder.addParameter(internal.name, v.getValue());
    }
  };

};

template<typename T_elementType>
class TGConventionalMatrix : public TGMatrix<T_elementType>
{
private:
  const bool parameter;
  const std::string name;
  const int rows;
  const int cols;
  tg::TaskArray<2>  value;

  static tg::TaskArray<2> createValue(bool param, const std::string& name, int rows, int cols)
  {
    unsigned dims[2] = {rows, cols};
    if (param)
    {
      tParameter(tArrayFromListNamed(T_elementType, val, 2, dims, name.c_str()));
      return val;
    }
    else
    {
      tArrayFromListNamed(T_elementType, val, 2, dims, name.c_str());
      return val;
    }
  }

  static inline const std::string getPrefix()
  {
    return std::string("convMatrix");
  }

public:
  TGConventionalMatrix(NameGenerator& generator, ConventionalMatrix<T_elementType>& internal) : parameter(true), name(generator.getName(getPrefix())),  rows(internal.getRowCount()), cols(internal.getColCount()), value(createValue(true, name, rows, cols))
  {
  }

  TGConventionalMatrix(bool param, NameGenerator& generator, const ExprNode<matrix, T_elementType>& m) :  parameter(param), name(generator.getName(getPrefix())), rows(m.getRowCount()), cols(m.getColCount()), value(createValue(param, name, rows, cols))
  {
  }

  const TGScalarExpr<T_elementType> getExpression(const tg::TaskExpression& row, const tg::TaskExpression& col) const
  {
    return TGScalarExpr<T_elementType>(value[row][col]);
  }

  void setExpression(const tg::TaskExpression& row, const tg::TaskExpression& col, const TGScalarExpr<T_elementType>& e)
  {
    value[row][col] = e.getExpression();
  }

  void addExpression(const tg::TaskExpression& row, const tg::TaskExpression& col, const TGScalarExpr<T_elementType>& e)
  {
    value[row][col] += e.getExpression();
  }

  virtual int getRows() const
  {
    return rows;
  }

  virtual int getCols() const
  {
    return cols;
  }

  virtual InternalMatrix<T_elementType>* createInternalRep() const
  {
    assert(parameter);
    return new ConventionalMatrix<T_elementType>(rows, cols);
  }

  virtual bool isParameter() const
  {
    return parameter;
  }

  virtual void addParameterMappings(InternalMatrix<T_elementType>& internal, ParameterHolder& params) const
  {
    assert(parameter);
    Mapper mapper(*this, params);
    internal.accept(mapper);
  }

  virtual std::size_t hashValue() const
  {
    std::size_t seed = boost::hash<std::string>()(typeid(*this).name());
    boost::hash_combine(seed, parameter);
    boost::hash_combine(seed, rows);
    boost::hash_combine(seed, cols);
    return seed;
  }

  class Mapper : public InternalMatrixVisitor<T_elementType>
  {
  private:
    const TGConventionalMatrix<T_elementType>& internal;
    ParameterHolder& parameterHolder;

  public:
    Mapper(const TGConventionalMatrix<T_elementType>& i, ParameterHolder& p) : internal(i), parameterHolder(p)
    {
    }

    virtual void visit(ConventionalMatrix<T_elementType>& m)
    {
      assert(m.isAllocated());
      parameterHolder.addParameter(internal.name, m.getValue());
    }
  };
};

template<typename T_elementType>
class TGMatrixGen : public InternalMatrixVisitor<T_elementType>
{
  NameGenerator& generator;
  TGMatrix<T_elementType>* result;
public:
  TGMatrixGen(NameGenerator& g) : generator(g)
  {
  }

  void visit(ConventionalMatrix<T_elementType>& m)
  {
    result = new TGConventionalMatrix<T_elementType>(generator, m);
  }

  TGMatrix<T_elementType>* getResult() const
  {
    assert(result != NULL);
    return result;
  }
};

template<typename T_elementType>
class TGVectorGen : public InternalVectorVisitor<T_elementType>
{
  NameGenerator& generator;
  TGVector<T_elementType>* result;
public:
  TGVectorGen(NameGenerator& g) : generator(g)
  {
  }

  void visit(ConventionalVector<T_elementType>& m)
  {
    result = new TGConventionalVector<T_elementType>(generator, m);
  }

  TGVector<T_elementType>* getResult() const
  {
    assert(result != NULL);
    return result;
  }
};

template<typename T_elementType>
class TGScalarGen : public InternalScalarVisitor<T_elementType>
{
  NameGenerator& generator;
  TGScalar<T_elementType>* result;
public:
  TGScalarGen(NameGenerator& g) : generator(g)
  {
  }

  void visit(ConventionalScalar<T_elementType>& m)
  {
    result = new TGConventionalScalar<T_elementType>(generator, m);
  }

  TGScalar<T_elementType>* getResult() const
  {
    assert(result != NULL);
    return result;
  }
};

}
#endif
<commit_msg>Added name hashing to TaskGraph internal reprentation hashes.<commit_after>#ifndef DESOLIN_TG_OBJECTS_HPP
#define DESOLIN_TG_OBJECTS_HPP

#include <boost/functional/hash.hpp>
#include <typeinfo>
#include <cassert>
#include <string>
#include <map>
#include <boost/format.hpp>
#include <TaskGraph>
#include <desolin/tg/Desolin_tg_fwd.hpp>

namespace desolin_internal
{

template<typename T_elementType>
class TGScalar
{
public:
  virtual const TGScalarExpr<T_elementType> getExpression() const = 0;
  virtual void setExpression(const TGScalarExpr<T_elementType>& e) = 0;
  virtual void addExpression(const TGScalarExpr<T_elementType>& e) = 0;
  virtual ~TGScalar() {}
  virtual InternalScalar<T_elementType>* createInternalRep() const = 0;
  virtual bool isParameter() const = 0;
  virtual void addParameterMappings(InternalScalar<T_elementType>& internal, ParameterHolder& params) const = 0;
  virtual std::size_t hashValue() const = 0;
};

template<typename T_elementType>
class TGVector
{
public:
  virtual const TGScalarExpr<T_elementType> getExpression(const tg::TaskExpression& row) const = 0;
  virtual void setExpression(const tg::TaskExpression& row, const TGScalarExpr<T_elementType>& e) = 0;
  virtual void addExpression(const tg::TaskExpression& row, const TGScalarExpr<T_elementType>& e) = 0;
  virtual int getRows() const = 0;
  virtual ~TGVector() {}
  virtual InternalVector<T_elementType>* createInternalRep() const = 0;
  virtual bool isParameter() const = 0;
  virtual void addParameterMappings(InternalVector<T_elementType>& internal, ParameterHolder& params) const = 0;
  virtual std::size_t hashValue() const = 0;
};

template<typename T_elementType>
class TGMatrix
{
public:
  virtual const TGScalarExpr<T_elementType> getExpression(const tg::TaskExpression& row, const tg::TaskExpression& col) const = 0;
  virtual void setExpression(const tg::TaskExpression& row, const tg::TaskExpression& col, const TGScalarExpr<T_elementType>& e) = 0;
  virtual void addExpression(const tg::TaskExpression& row, const tg::TaskExpression& col, const TGScalarExpr<T_elementType>& e) = 0;
  virtual int getRows() const = 0;
  virtual int getCols() const = 0;
  virtual ~TGMatrix() {}
  virtual InternalMatrix<T_elementType>* createInternalRep() const = 0;
  virtual bool isParameter() const = 0;
  virtual void addParameterMappings(InternalMatrix<T_elementType>& internal, ParameterHolder& params) const = 0;
  virtual std::size_t hashValue() const = 0;
};

template<typename T_elementType>
class TGScalarExpr
{
  const tg::TaskExpression expr;

public:
  TGScalarExpr() : expr(0)
  {
  }

  TGScalarExpr(const tg::TaskExpression& e) : expr(e)
  {
  }

  inline const tg::TaskExpression getExpression() const
  {
    return expr;
  }

  inline const TGScalarExpr mul(const TGScalarExpr& right) const
  {
    return TGScalarExpr(expr*right.expr);
  }

  inline const TGScalarExpr div(const TGScalarExpr& right) const
  {
    return TGScalarExpr(expr/right.expr);
  }

  inline const TGScalarExpr add(const TGScalarExpr& right) const
  {
    return TGScalarExpr(expr+right.expr);
  }

  inline const TGScalarExpr sub(const TGScalarExpr& right) const
  {
    return TGScalarExpr(expr-right.expr);
  }

  inline const TGScalarExpr sqrt() const
  {
    return TGScalarExpr(tSqrt(expr));
  }

  inline const TGScalarExpr abs() const
  {
    return TGScalarExpr(tAbs(expr));
  }

  inline const TGScalarExpr negate() const
  {
    return TGScalarExpr(-expr);
  }
};

template<typename T_elementType>
class TGConventionalScalar : public TGScalar<T_elementType>
{
  friend class Mapper;

private:
  const bool parameter;
  const std::string name;
  tg::TaskScalarVariable value;

  static tg::TaskScalarVariable createValue(bool param, const std::string& name)
  {
    if (param)
    {
      tParameter(tVarNamedTemplateType(T_elementType, val, name.c_str()));
      return val;
    }
    else
    {
      tVarNamedTemplateType(T_elementType, val, name.c_str());
      return val;
    }
  }

  static inline const std::string getPrefix()
  {
    return std::string("convScalar");
  }

public:
  TGConventionalScalar(NameGenerator& generator, const ConventionalScalar<T_elementType>& internal) : parameter(true), name(generator.getName(getPrefix())), value(createValue(true, name))
  {
  }

  TGConventionalScalar(bool param, NameGenerator& generator, const ExprNode<scalar, T_elementType>& s) : parameter(param), name(generator.getName(getPrefix())), value(createValue(param, name))
  {
  }

  const TGScalarExpr<T_elementType> getExpression() const
  {
    return TGScalarExpr<T_elementType>(value);
  }

  void setExpression(const TGScalarExpr<T_elementType>& e)
  {
    value = e.getExpression();
  }

  void addExpression(const TGScalarExpr<T_elementType>& e)
  {
    value += e.getExpression();
  }

  virtual InternalScalar<T_elementType>* createInternalRep() const
  {
    assert(parameter);
    return new ConventionalScalar<T_elementType>();
  }

  virtual bool isParameter() const
  {
    return parameter;
  }

  virtual std::size_t hashValue() const
  {
    std::size_t seed = boost::hash<std::string>()(typeid(*this).name());
    boost::hash_combine(seed, parameter);
    boost::hash_combine(seed, name);
    return seed;
  }

  virtual void addParameterMappings(InternalScalar<T_elementType>& internal, ParameterHolder& params) const
  {
    assert(parameter);
    Mapper mapper(*this, params);
    internal.accept(mapper);
  }

  class Mapper : public InternalScalarVisitor<T_elementType>
  {
  private:
    const TGConventionalScalar<T_elementType>& internal;
    ParameterHolder& parameterHolder;

  public:
    Mapper(const TGConventionalScalar<T_elementType>& i, ParameterHolder& p) : internal(i), parameterHolder(p)
    {
    }

    virtual void visit(ConventionalScalar<T_elementType>& s)
    {
      assert(s.isAllocated());
      parameterHolder.addParameter(internal.name, s.getValue());
    }
  };
};

template<typename T_elementType>
class TGConventionalVector : public TGVector<T_elementType>
{
private:
  const bool parameter;
  const std::string name;
  const int rows;
  tg::TaskArray<1> value;

  static tg::TaskArray<1> createValue(bool param, const std::string& name, int rows)
  {
    unsigned dims[1] = {rows};
    if (param)
    {
      tParameter(tArrayFromListNamed(T_elementType, val, 1, dims, name.c_str()));
      return val;
    }
    else
    {
      tArrayFromListNamed(T_elementType, val, 1, dims, name.c_str());
      return val;
    }
  }

  static inline const std::string getPrefix()
  {
    return std::string("convVector");
  }

public:
  TGConventionalVector(NameGenerator& generator, const ConventionalVector<T_elementType>& internal) :  parameter(true), name(generator.getName(getPrefix())), rows(internal.getRowCount()), value(createValue(true, name, rows))
  {
  }

  TGConventionalVector(bool param, NameGenerator& generator, const ExprNode<vector, T_elementType>& v) :  parameter(param), name(generator.getName(getPrefix())), rows(v.getRowCount()), value(createValue(param, name, rows))
  {
  }

  const TGScalarExpr<T_elementType> getExpression(const tg::TaskExpression& row) const
  {
    return TGScalarExpr<T_elementType>(value[row]);
  }

  void setExpression(const tg::TaskExpression& row, const TGScalarExpr<T_elementType>& e)
  {
    value[row] = e.getExpression();
  }

  void addExpression(const tg::TaskExpression& row, const TGScalarExpr<T_elementType>& e)
  {
    value[row] += e.getExpression();
  }

  virtual int getRows() const
  {
    return rows;
  }

  virtual InternalVector<T_elementType>* createInternalRep() const
  {
    assert(parameter);
    return new ConventionalVector<T_elementType>(rows);
  }

  virtual bool isParameter() const
  {
    return parameter;
  }

  virtual void addParameterMappings(InternalVector<T_elementType>& internal, ParameterHolder& params) const
  {
    assert(parameter);
    Mapper mapper(*this, params);
    internal.accept(mapper);
  }

  virtual std::size_t hashValue() const
  {
    std::size_t seed = boost::hash<std::string>()(typeid(*this).name());
    boost::hash_combine(seed, parameter);
    boost::hash_combine(seed, rows);
    boost::hash_combine(seed, name);
    return seed;
  }

  class Mapper : public InternalVectorVisitor<T_elementType>
  {
  private:
    const TGConventionalVector<T_elementType>& internal;
    ParameterHolder& parameterHolder;

  public:
    Mapper(const TGConventionalVector<T_elementType>& i, ParameterHolder& p) : internal(i), parameterHolder(p)
    {
    }

    virtual void visit(ConventionalVector<T_elementType>& v)
    {
      assert(v.isAllocated());
      parameterHolder.addParameter(internal.name, v.getValue());
    }
  };

};

template<typename T_elementType>
class TGConventionalMatrix : public TGMatrix<T_elementType>
{
private:
  const bool parameter;
  const std::string name;
  const int rows;
  const int cols;
  tg::TaskArray<2>  value;

  static tg::TaskArray<2> createValue(bool param, const std::string& name, int rows, int cols)
  {
    unsigned dims[2] = {rows, cols};
    if (param)
    {
      tParameter(tArrayFromListNamed(T_elementType, val, 2, dims, name.c_str()));
      return val;
    }
    else
    {
      tArrayFromListNamed(T_elementType, val, 2, dims, name.c_str());
      return val;
    }
  }

  static inline const std::string getPrefix()
  {
    return std::string("convMatrix");
  }

public:
  TGConventionalMatrix(NameGenerator& generator, ConventionalMatrix<T_elementType>& internal) : parameter(true), name(generator.getName(getPrefix())),  rows(internal.getRowCount()), cols(internal.getColCount()), value(createValue(true, name, rows, cols))
  {
  }

  TGConventionalMatrix(bool param, NameGenerator& generator, const ExprNode<matrix, T_elementType>& m) :  parameter(param), name(generator.getName(getPrefix())), rows(m.getRowCount()), cols(m.getColCount()), value(createValue(param, name, rows, cols))
  {
  }

  const TGScalarExpr<T_elementType> getExpression(const tg::TaskExpression& row, const tg::TaskExpression& col) const
  {
    return TGScalarExpr<T_elementType>(value[row][col]);
  }

  void setExpression(const tg::TaskExpression& row, const tg::TaskExpression& col, const TGScalarExpr<T_elementType>& e)
  {
    value[row][col] = e.getExpression();
  }

  void addExpression(const tg::TaskExpression& row, const tg::TaskExpression& col, const TGScalarExpr<T_elementType>& e)
  {
    value[row][col] += e.getExpression();
  }

  virtual int getRows() const
  {
    return rows;
  }

  virtual int getCols() const
  {
    return cols;
  }

  virtual InternalMatrix<T_elementType>* createInternalRep() const
  {
    assert(parameter);
    return new ConventionalMatrix<T_elementType>(rows, cols);
  }

  virtual bool isParameter() const
  {
    return parameter;
  }

  virtual void addParameterMappings(InternalMatrix<T_elementType>& internal, ParameterHolder& params) const
  {
    assert(parameter);
    Mapper mapper(*this, params);
    internal.accept(mapper);
  }

  virtual std::size_t hashValue() const
  {
    std::size_t seed = boost::hash<std::string>()(typeid(*this).name());
    boost::hash_combine(seed, parameter);
    boost::hash_combine(seed, rows);
    boost::hash_combine(seed, cols);
    boost::hash_combine(sees, name);
    return seed;
  }

  class Mapper : public InternalMatrixVisitor<T_elementType>
  {
  private:
    const TGConventionalMatrix<T_elementType>& internal;
    ParameterHolder& parameterHolder;

  public:
    Mapper(const TGConventionalMatrix<T_elementType>& i, ParameterHolder& p) : internal(i), parameterHolder(p)
    {
    }

    virtual void visit(ConventionalMatrix<T_elementType>& m)
    {
      assert(m.isAllocated());
      parameterHolder.addParameter(internal.name, m.getValue());
    }
  };
};

template<typename T_elementType>
class TGMatrixGen : public InternalMatrixVisitor<T_elementType>
{
  NameGenerator& generator;
  TGMatrix<T_elementType>* result;
public:
  TGMatrixGen(NameGenerator& g) : generator(g)
  {
  }

  void visit(ConventionalMatrix<T_elementType>& m)
  {
    result = new TGConventionalMatrix<T_elementType>(generator, m);
  }

  TGMatrix<T_elementType>* getResult() const
  {
    assert(result != NULL);
    return result;
  }
};

template<typename T_elementType>
class TGVectorGen : public InternalVectorVisitor<T_elementType>
{
  NameGenerator& generator;
  TGVector<T_elementType>* result;
public:
  TGVectorGen(NameGenerator& g) : generator(g)
  {
  }

  void visit(ConventionalVector<T_elementType>& m)
  {
    result = new TGConventionalVector<T_elementType>(generator, m);
  }

  TGVector<T_elementType>* getResult() const
  {
    assert(result != NULL);
    return result;
  }
};

template<typename T_elementType>
class TGScalarGen : public InternalScalarVisitor<T_elementType>
{
  NameGenerator& generator;
  TGScalar<T_elementType>* result;
public:
  TGScalarGen(NameGenerator& g) : generator(g)
  {
  }

  void visit(ConventionalScalar<T_elementType>& m)
  {
    result = new TGConventionalScalar<T_elementType>(generator, m);
  }

  TGScalar<T_elementType>* getResult() const
  {
    assert(result != NULL);
    return result;
  }
};

}
#endif
<|endoftext|>


<commit_before>/**
 * These codes are licensed under the Unlicense.
 * http://unlicense.org
 */

#ifndef COMMATA_GUARD_F6071085_9476_4724_95ED_E1DA376E837C
#define COMMATA_GUARD_F6071085_9476_4724_95ED_E1DA376E837C

#include <memory>
#include <type_traits>
#include <utility>

#include "member_like_base.hpp"

namespace commata {
namespace detail {

template <class A, class = void>
struct reference_forwarded
{
    using type = typename A::value_type&;
};

template <class A>
struct reference_forwarded<A, typename A::reference>
{
    using type = typename A::reference;
};

template <class A, class = void>
struct const_reference_forwarded
{
    using type = const typename A::value_type&;
};

template <class A>
struct const_reference_forwarded<A, typename A::const_reference>
{
    using type = typename A::const_reference;
};

template <class Allocator>
class allocation_only_allocator :
    member_like_base<Allocator>
{
    using base_traits = typename std::allocator_traits<Allocator>;

    // To rebind
    template <class Allocator2>
    friend class allocation_only_allocator;

public:
    using pointer = typename base_traits::pointer;
    using const_pointer = typename base_traits::const_pointer;
    using void_pointer = typename base_traits::void_pointer;
    using const_void_pointer = typename base_traits::const_void_pointer;
    using value_type = typename base_traits::value_type;
    using size_type = typename base_traits::size_type;
    using difference_type = typename base_traits::difference_type;

    // These types are not required by the C++14 standard, but
    // std::basic_string which comes with gcc 7.3.1 seems to do
    using reference = typename reference_forwarded<Allocator>::type;
    using const_reference =
        typename const_reference_forwarded<Allocator>::type;

    template <class U>
    struct rebind
    {
        using other = allocation_only_allocator<
            typename base_traits::template rebind_alloc<U>>;
    };

    // Default-constructibility of an allocator is not mandated by the C++14
    // standard, but std::basic_string which comes with gcc 7.3.1 requires it
    allocation_only_allocator() noexcept
    {}

    // To make wrappers
    explicit allocation_only_allocator(const Allocator& other) noexcept :
        member_like_base<Allocator>(other)
    {}

    // ditto
    explicit allocation_only_allocator(Allocator&& other) noexcept :
        member_like_base<Allocator>(std::move(other))
    {}

    // To make rebound copies
    template <class Allocator2>
    explicit allocation_only_allocator(
        const allocation_only_allocator<Allocator2>& other) noexcept :
        member_like_base<Allocator>(Allocator(other.get()))
    {}

    // C++14 standard does not require this
    template <class OtherAllocator>
    allocation_only_allocator& operator=(
        const allocation_only_allocator<OtherAllocator>& other)
        noexcept(std::is_nothrow_assignable<
            Allocator&, const OtherAllocator&>::value)
    {
        static_cast<Allocator&>(*this) = other;
        return *this;
    }

    // ditto
    template <class OtherAllocator>
    allocation_only_allocator& operator=(
        allocation_only_allocator<OtherAllocator>&& other)
        noexcept(std::is_nothrow_assignable<
            Allocator&, OtherAllocator>::value)
    {
        static_cast<Allocator&>(*this) = std::move(other);
        return *this;
    }

    template <class... Args>
    auto allocate(size_type n, Args&&... args)
    {
        return base_traits::allocate(base(),
            n, std::forward<Args>(args)...);
    }

    auto deallocate(pointer p, size_type n) noexcept
    {
        return base_traits::deallocate(base(), p, n);
    }

    auto max_size() noexcept
    {
        return base_traits::max_size(base());
    }

    template <class T, class... Args>
    void construct(T* p, Args&&... args)
    {
        ::new(p) T(std::forward<Args>(args)...);
    }

    template <class T>
    void destroy(T* p)
    {
        destroy(p, std::is_trivially_destructible<T>());
    }

    auto select_on_container_copy_construction() noexcept
    {
        return base_traits::select_on_container_copy_construction(base());
    }

    using propagate_on_container_copy_assignment =
        typename base_traits::propagate_on_container_copy_assignment;
    using propagate_on_container_move_assignment =
        typename base_traits::propagate_on_container_move_assignment;
    using propagate_on_container_swap =
        typename base_traits::propagate_on_container_swap;

    decltype(auto) base() noexcept
    {
        return this->get();
    }

    decltype(auto) base() const noexcept
    {
        return this->get();
    }

private:
    template <class T>
    void destroy(T*, std::true_type)
    {}

    template <class T>
    void destroy(T* p, std::false_type)
    {
        p->~T();
    }
};

template <class Allocator1, class Allocator2>
inline bool operator==(
    const allocation_only_allocator<Allocator1>& left,
    const allocation_only_allocator<Allocator2>& right) noexcept
{
    return left.base() == right.base();
}

template <class Allocator1, class Allocator2>
inline bool operator!=(
    const allocation_only_allocator<Allocator1>& left,
    const allocation_only_allocator<Allocator2>& right) noexcept
{
    return !(left == right);
}

}}

#endif
<commit_msg>Potential bug fix: add generous ctors to allocation_only_allocator<commit_after>/**
 * These codes are licensed under the Unlicense.
 * http://unlicense.org
 */

#ifndef COMMATA_GUARD_F6071085_9476_4724_95ED_E1DA376E837C
#define COMMATA_GUARD_F6071085_9476_4724_95ED_E1DA376E837C

#include <memory>
#include <type_traits>
#include <utility>

#include "member_like_base.hpp"

namespace commata {
namespace detail {

template <class A, class = void>
struct reference_forwarded
{
    using type = typename A::value_type&;
};

template <class A>
struct reference_forwarded<A, typename A::reference>
{
    using type = typename A::reference;
};

template <class A, class = void>
struct const_reference_forwarded
{
    using type = const typename A::value_type&;
};

template <class A>
struct const_reference_forwarded<A, typename A::const_reference>
{
    using type = typename A::const_reference;
};

template <class Allocator>
class allocation_only_allocator;

template <class T>
class is_allocation_only_allocator : std::false_type
{};

template <class Allocator>
class is_allocation_only_allocator<allocation_only_allocator<Allocator>> :
    std::true_type
{};

template <class Allocator>
class allocation_only_allocator :
    member_like_base<Allocator>
{
    using base_traits = typename std::allocator_traits<Allocator>;

    // To rebind
    template <class Allocator2>
    friend class allocation_only_allocator;

public:
    using pointer = typename base_traits::pointer;
    using const_pointer = typename base_traits::const_pointer;
    using void_pointer = typename base_traits::void_pointer;
    using const_void_pointer = typename base_traits::const_void_pointer;
    using value_type = typename base_traits::value_type;
    using size_type = typename base_traits::size_type;
    using difference_type = typename base_traits::difference_type;

    // These types are not required by the C++14 standard, but
    // std::basic_string which comes with gcc 7.3.1 seems to do
    using reference = typename reference_forwarded<Allocator>::type;
    using const_reference =
        typename const_reference_forwarded<Allocator>::type;

    template <class U>
    struct rebind
    {
        using other = allocation_only_allocator<
            typename base_traits::template rebind_alloc<U>>;
    };

    // Default-constructibility of an allocator is not mandated by the C++14
    // standard, but std::basic_string which comes with gcc 7.3.1 requires it
    allocation_only_allocator() noexcept
    {}

    // To make wrappers
    explicit allocation_only_allocator(const Allocator& other) noexcept :
        member_like_base<Allocator>(other)
    {}

    // ditto
    explicit allocation_only_allocator(Allocator&& other) noexcept :
        member_like_base<Allocator>(std::move(other))
    {}

    // To make rebound copies
    template <class Allocator2>
    explicit allocation_only_allocator(
        const allocation_only_allocator<Allocator2>& other) noexcept :
        member_like_base<Allocator>(Allocator(other.get()))
    {}

    // ditto
    template <class Allocator2,
        std::enable_if_t<
            !is_allocation_only_allocator<Allocator2>::value_type>>
    explicit allocation_only_allocator(const Allocator2& other) noexcept :
        member_like_base<Allocator>(
            typename std::allocator_traits<Allocator2>::template
                rebind_alloc<value_type>(other))
    {}

    // ditto
    template <class Allocator2,
        std::enable_if_t<
            !is_allocation_only_allocator<Allocator2>::value_type>>
    explicit allocation_only_allocator(Allocator2&& other) noexcept :
        member_like_base<Allocator>(
            typename std::allocator_traits<Allocator2>::template
                rebind_alloc<value_type>(std::move(other)))
    {}

    // C++14 standard does not require this
    template <class OtherAllocator>
    allocation_only_allocator& operator=(
        const allocation_only_allocator<OtherAllocator>& other)
        noexcept(std::is_nothrow_assignable<
            Allocator&, const OtherAllocator&>::value)
    {
        static_cast<Allocator&>(*this) = other;
        return *this;
    }

    // ditto
    template <class OtherAllocator>
    allocation_only_allocator& operator=(
        allocation_only_allocator<OtherAllocator>&& other)
        noexcept(std::is_nothrow_assignable<
            Allocator&, OtherAllocator>::value)
    {
        static_cast<Allocator&>(*this) = std::move(other);
        return *this;
    }

    template <class... Args>
    auto allocate(size_type n, Args&&... args)
    {
        return base_traits::allocate(base(),
            n, std::forward<Args>(args)...);
    }

    auto deallocate(pointer p, size_type n) noexcept
    {
        return base_traits::deallocate(base(), p, n);
    }

    auto max_size() noexcept
    {
        return base_traits::max_size(base());
    }

    template <class T, class... Args>
    void construct(T* p, Args&&... args)
    {
        ::new(p) T(std::forward<Args>(args)...);
    }

    template <class T>
    void destroy(T* p)
    {
        destroy(p, std::is_trivially_destructible<T>());
    }

    auto select_on_container_copy_construction() noexcept
    {
        return base_traits::select_on_container_copy_construction(base());
    }

    using propagate_on_container_copy_assignment =
        typename base_traits::propagate_on_container_copy_assignment;
    using propagate_on_container_move_assignment =
        typename base_traits::propagate_on_container_move_assignment;
    using propagate_on_container_swap =
        typename base_traits::propagate_on_container_swap;

    decltype(auto) base() noexcept
    {
        return this->get();
    }

    decltype(auto) base() const noexcept
    {
        return this->get();
    }

private:
    template <class T>
    void destroy(T*, std::true_type)
    {}

    template <class T>
    void destroy(T* p, std::false_type)
    {
        p->~T();
    }
};

template <class Allocator1, class Allocator2>
inline bool operator==(
    const allocation_only_allocator<Allocator1>& left,
    const allocation_only_allocator<Allocator2>& right) noexcept
{
    return left.base() == right.base();
}

template <class Allocator1, class Allocator2>
inline bool operator!=(
    const allocation_only_allocator<Allocator1>& left,
    const allocation_only_allocator<Allocator2>& right) noexcept
{
    return !(left == right);
}

}}

#endif
<|endoftext|>


<commit_before>
/**
 Sketch of the L1 ring buffer desired API -- what the RPC server would
 look like.

 */

/*
 For RPC write_chunks: we need to keep the assembled_chunks alive via
 a shared_ptr.  This can be achieved by the RPC server pulling
 requests off the client-facing socket in one thread, retrieving
 shared_ptrs to the assembled_chunks, and putting them in a
 (thread-safe) queue which will keep the shared_ptrs alive.  After
 enqueuing a chunk + args, it should send a request to a back-end
 worker to pull some work from the queue.  The worker can dequeue the
 assembled_chunk, msgpack it or otherwise write it to disk, and then
 drop the shared_ptr.

 ZMQ_DONTWAIT -- blocks on zmq_send when high-water-mark is reached (DEALER)
 //#include <zmq.hpp>
 */

/*
 For the telescoping time-sampling, we want to keep ~4 ring buffers.
 The property they have is that as the oldest data are dropped off the
 end of the ring buffer, we want to take two chunks and compile them
 into one chunk.  While this is happening, we still want to be able to
 access them. (ie, the RPC callbacks should still know about them).

 Each of these ~4 ring buffers should use a fixed amount of space; we
 may want to re-use the assembled_chunk memory.
 */

/*
 One idea: rather than explicitly "pinning" assembled_chunks, we could
 use shared_ptr.unique() -- if only the ring buffer has a copy of the
 shared_ptr, then that assembled_chunk can be dropped.
 */

/*
 Another idea is to use the assembled_chunk (or a wrapper of it)'s
 destructor to notify the ring buffer (or an allocator) that it is
 being deleted.
 */

/*
For the telescoping chain, we want the ring buffer to tell us when an
assembled_chunk is being dropped.
 */

/*
 assembled_chunk::make() is a factory for assembled_chunks.

 assembled_chunk_ringbuf::_make_assembled_chunk() wraps that or calls directly

 assembled_chunk_ringbuf holds active_chunk0 and active_chunk1
 *outside* the ringbuf.

 _put_assembled_chunk is where assembled_chunks get added to the ring buffer.

 */

/*
 assembled_chunk_ringbuf: needs to allocate a new chunk when it
 receives a packet with ichunk >= active_ichunk + 2.

 Could do:
 - try to allocate a new assembled_chunk.  If that fails:
 - if assembled_ringbuf_size == assembled_ringbuf_capacity,
   then the buffer is full of chunks waiting for the consumer thread.
   -> drop data?  This means we keep the oldest data; alternative
      would be to drop the oldest frame and keep the newest data
      instead.

 - iteratively: go to the next ringbuf position and drop that chunk
   off the back -- call callback, then reset the shared_ptr.  Then try
   to allocate a new assembled_chunk.  If resetting the shared_ptr
   drop the last reference to an assembled_chunk, then that chunk will
   become available.  If not (eg, if RPC thread has a copy of the
   shared_ptr), continue on to the next position.  This process will
   stop once we drop (assembled_ringbuf_capacity -
   assembled_ringbuf_size) chunks -- ie, all the chunks left in the
   buffer are the ones waiting to be consumed.

 - there will be a callback for when a chunk is being dropped.  This
   is where we handle the telescoping: we'll hold zero or one older
   chunks, and when a chunk is about to be dropped, if we had an older
   one, then we can downsample the two and then enqueue the resulting
   new chunk.  This enqueue call could (typically will, in
   steady-state) cause a cascade of dropping the oldest frame from the
   next ring buffer.

 - the longer-duration ring buffers do not have 'downstream'
   consumers.

- Huh, what if the queue of assembled chunks waiting for the
  downstream consumer and the ring buffer per se are two separate data
  structures that each hold shared_ptrs?

 - ring buffer could allocate an assembled_chunk *subclass* that tells
   the ring buffer when it is deleted.

 */

/*
 Single ringbuffer public API.

 ringbuf<T>(int size)

 // called when an item is about to be dropped off the end.
 virtual void drop(T);

 // try to enqueue an element; returns false if the ring buffer is full.
 bool enqueue(const T&)
 bool enqueue(T*)?
 shared_ptr<T> enqueue(T*)?

 //
 vector<T> snapshot(bool test(T*)) ?

 where T : shared_ptr<assembled_chunk> and we will subclass it to
 override drop() to do the telescoping.

 */

#include <iostream>
#include <queue>
#include <deque>

using namespace std;
using namespace std::placeholders;

#include "ch_frb_io.hpp"
using namespace ch_frb_io;

std::ostream& operator<<(std::ostream& s, const assembled_chunk& ch) {
    s << "assembled_chunk(beam " << ch.beam_id << ", ichunk " << ch.ichunk << ")";
    return s;
}

// forward decl
template<class T>
class RingbufDeleter;

template<class T>
class Ringbuf {
    friend class RingbufDeleter<T>;

public:
    /*
     Creates a new Ringbuf with the given maximum quota size.
     */
    Ringbuf(int maxsize) :
        _deleter(this),
        _q(maxsize),
        _live(0),
        _maxsize(maxsize)
    {}

    virtual ~Ringbuf() {}

    /*
     Tries to push a new frame onto the ring buffer.  If the quota of
     frames has been reached, frames will be popped off the front
     until the buffer is empty.  If space is still not available, will
     return an empty shared_ptr.

     Returns the enqueued shared_ptr if successful.
     */
    shared_ptr<T> push(T* t) {
        while (_live >= _maxsize) {
            cout << "Push: _live >= _maxsize." << " (" << _live << " >= " << _maxsize << ")" << endl;
            if (_q.empty()) {
                cout << "Ring buffer empty but still too many live elements -- push fails" << endl;
                return shared_ptr<T>();
            }
            cout << "Dropping an element..." << endl;
            shared_ptr<T> p = _q.front();
            _q.pop_front();
            dropping(p);
            p.reset();
            cout << "Now " << _live << " live" << endl;
        }
        cout << "Creating shared_ptr..." << endl;
        shared_ptr<T> p(t, _deleter);
        _live++;
        _q.push_back(p);
        cout << "Now " << _live << " objects are live" << endl;
        return p;
    }

    /*
     Pops the oldest frame from this buffer.
     */
    shared_ptr<T> pop() {
        cout << "Popping..." << endl;
        shared_ptr<T> p = _q.pop_front();
        cout << "Pop: returning " << *p << endl;
        return p;
    }

    vector<shared_ptr<T> > snapshot(bool (*testFunc)(const shared_ptr<T>)) {
        vector<shared_ptr<T> > vec;
        for (auto it = _q.begin(); it != _q.end(); it++) {
            if (!testFunc || testFunc(*it))
                vec.push_back(*it);
        }
        return vec;
    }

protected:
    // Small helper class that calls deleted() when one of our frames
    // is deleted.
    RingbufDeleter<T> _deleter;

    // The actual queue of frames.
    deque<shared_ptr<T> > _q;

    // Number of live frames.
    size_t _live;
    // Maximum allowable number of live frames.
    size_t _maxsize;

    // We're about to drop this frame.
    virtual void dropping(shared_ptr<T> t) {}

    // Called by the RingbufDeleter when a shared_ptr is deleted
    void deleted(T* t) {
        cout << "Deleting object: " << *t << endl;
        _live--;
        cout << "Now " << _live << " objects are live" << endl;
        // FIXME --?
        delete t;
    }

};

template<class T>
class RingbufDeleter {
public:
    RingbufDeleter(Ringbuf<T>* rb) : _ringbuf(rb) {}

    void operator()(T* t) {
        cout << "RingbufDelete::operator() called." << endl;
        _ringbuf->deleted(t);
    }

protected:
    Ringbuf<T>* _ringbuf;
};

class L1Ringbuf;

class AssembledChunkRingbuf : public Ringbuf<assembled_chunk> {

public:
    AssembledChunkRingbuf(int binlevel, L1Ringbuf* parent, int maxsize) :
        Ringbuf<assembled_chunk>(maxsize),
        _binlevel(binlevel),
        _parent(parent)
    {}

    virtual ~AssembledChunkRingbuf() {}

protected:
    // my time-binning. level: 0 = original intensity stream; 1 =
    // binned x 2, 2 = binned x 4.
    int _binlevel;
    L1Ringbuf* _parent;

    // Called when the given frame *t* is being dropped off the buffer
    // to free up some space for a new frame.
    virtual void dropping(shared_ptr<assembled_chunk> t);

};

class L1Ringbuf {
    friend class AssembledChunkRingbuf;

    static const size_t Nbins = 4;

public:
    L1Ringbuf() :
        _q(),
        _rb(),
        _dropped()
    {
        for (int i=0; i<Nbins; i++)
            _rb.push_back(new AssembledChunkRingbuf(i, this, 4));
            //_rb[i] = new AssembledChunkRingbuf(i, this, 4);
        for (int i=0; i<Nbins-1; i++)
            _dropped.push_back(shared_ptr<assembled_chunk>());
    }

    ~L1Ringbuf() {
        for (int i=0; i<Nbins; i++)
            delete _rb[i];
    }

    bool push(assembled_chunk* ch) {
        shared_ptr<assembled_chunk> p = _rb[0]->push(ch);
        if (!p)
            return false;
        _q.push(p);
        return true;
    }

    shared_ptr<assembled_chunk> pop() {
        shared_ptr<assembled_chunk> p = _q.front();
        _q.pop();
        return p;
    }

    void print() {
        cout << "L1 ringbuf:" << endl;

        for (int i=0; i<Nbins; i++) {
            vector<shared_ptr<assembled_chunk> > v = _rb[i]->snapshot(NULL);
            cout << "  binning " << i << ": [ ";
            for (auto it = v.begin(); it != v.end(); it++) {
                cout << (*it)->ichunk << " ";
            }
            cout << "]" << endl;
            if (i < Nbins-1) {
                cout << "  dropped " << i << ": ";
                if (_dropped[i])
                    cout << _dropped[i]->ichunk << endl;
                else
                    cout << "none" << endl;
            }
        }
    }

protected:
    // The queue for downstream
    queue<shared_ptr<assembled_chunk> > _q;

    vector<AssembledChunkRingbuf*> _rb;
    //array<AssembledChunkRingbuf*, Nbins> _rb;
    vector<shared_ptr<assembled_chunk> > _dropped;
    //array<shared_ptr<assembled_chunk>, Nbins> _dropped;

    void dropping(int binlevel, shared_ptr<assembled_chunk> ch) {
        cout << "Bin level " << binlevel << " dropping a chunk" << endl;
        if (binlevel >= Nbins-1)
            return;

        if (_dropped[binlevel]) {
            cout << "Now have 2 dropped chunks from bin level " << binlevel << endl;
            // FIXME -- bin down
            assembled_chunk* binned = new assembled_chunk(ch->beam_id, ch->nupfreq, ch->nt_per_packet, ch->fpga_counts_per_sample, _dropped[binlevel]->ichunk);
            // push onto _rb[level+1]
            _rb[binlevel+1]->push(binned);
            _dropped[binlevel].reset();
        } else {
            // Keep this one until its partner arrives!
            cout << "Saving as _dropped" << binlevel << endl;
            _dropped[binlevel] = ch;
        }
    }

};

// after L1Ringbuf has been declared...
void AssembledChunkRingbuf::dropping(shared_ptr<assembled_chunk> t) {
    _parent->dropping(_binlevel, t);
}

int main() {

    L1Ringbuf rb;

    int beam = 77;
    int nupfreq = 4;
    int nt_per = 16;
    int fpga_per = 400;

    assembled_chunk* ch;
    //ch = assembled_chunk::make(4, nupfreq, nt_per, fpga_per, 42);

    for (int i=0; i<32; i++) {
        ch = new assembled_chunk(beam, nupfreq, nt_per, fpga_per, i);
        rb.push(ch);

        cout << "Pushed " << i << endl;
        rb.print();
        cout << endl;

        // downstream thread consumes with a lag of 2...
        if (i >= 2) {
            rb.pop();
        }
    }

}

/*
int main() {
    cout << "Creating ringbuf..." << endl;
    Ringbuf<int> rb(4);

    int a = 42;
    int b = 43;
    int c = 44;

    cout << "Pushing" << endl;
    rb.push(&a);
    cout << "Pushing" << endl;
    rb.push(&b);
    cout << "Pushing" << endl;
    rb.push(&c);

    cout << "Popping" << endl;
    shared_ptr<int> p1 = rb.pop();
    cout << "Popping" << endl;
    shared_ptr<int> p2 = rb.pop();
    cout << "Dropping" << endl;
    p1.reset();
    cout << endl;

    int d = 45;
    int e = 46;
    int f = 47;
    int g = 48;

    cout << "Pushing d..." << endl;
    shared_ptr<int> pd = rb.push(&d);

    cout << endl;
    cout << "Pushing e..." << endl;
    shared_ptr<int> pe = rb.push(&e);

    cout << endl;
    cout << "Pushing f..." << endl;
    shared_ptr<int> pf = rb.push(&f);

    cout << endl;
    cout << "Pushing g..." << endl;
    rb.push(&g);

    cout << "Done" << endl;

}
 */

<commit_msg>oops, dequeue(int) constructor adds default-constructed elements<commit_after>
/**
 Sketch of the L1 ring buffer desired API -- what the RPC server would
 look like.

 */

/*
 For RPC write_chunks: we need to keep the assembled_chunks alive via
 a shared_ptr.  This can be achieved by the RPC server pulling
 requests off the client-facing socket in one thread, retrieving
 shared_ptrs to the assembled_chunks, and putting them in a
 (thread-safe) queue which will keep the shared_ptrs alive.  After
 enqueuing a chunk + args, it should send a request to a back-end
 worker to pull some work from the queue.  The worker can dequeue the
 assembled_chunk, msgpack it or otherwise write it to disk, and then
 drop the shared_ptr.

 ZMQ_DONTWAIT -- blocks on zmq_send when high-water-mark is reached (DEALER)
 //#include <zmq.hpp>
 */

/*
 For the telescoping time-sampling, we want to keep ~4 ring buffers.
 The property they have is that as the oldest data are dropped off the
 end of the ring buffer, we want to take two chunks and compile them
 into one chunk.  While this is happening, we still want to be able to
 access them. (ie, the RPC callbacks should still know about them).

 Each of these ~4 ring buffers should use a fixed amount of space; we
 may want to re-use the assembled_chunk memory.
 */

/*
 One idea: rather than explicitly "pinning" assembled_chunks, we could
 use shared_ptr.unique() -- if only the ring buffer has a copy of the
 shared_ptr, then that assembled_chunk can be dropped.
 */

/*
 Another idea is to use the assembled_chunk (or a wrapper of it)'s
 destructor to notify the ring buffer (or an allocator) that it is
 being deleted.
 */

/*
For the telescoping chain, we want the ring buffer to tell us when an
assembled_chunk is being dropped.
 */

/*
 assembled_chunk::make() is a factory for assembled_chunks.

 assembled_chunk_ringbuf::_make_assembled_chunk() wraps that or calls directly

 assembled_chunk_ringbuf holds active_chunk0 and active_chunk1
 *outside* the ringbuf.

 _put_assembled_chunk is where assembled_chunks get added to the ring buffer.

 */

/*
 assembled_chunk_ringbuf: needs to allocate a new chunk when it
 receives a packet with ichunk >= active_ichunk + 2.

 Could do:
 - try to allocate a new assembled_chunk.  If that fails:
 - if assembled_ringbuf_size == assembled_ringbuf_capacity,
   then the buffer is full of chunks waiting for the consumer thread.
   -> drop data?  This means we keep the oldest data; alternative
      would be to drop the oldest frame and keep the newest data
      instead.

 - iteratively: go to the next ringbuf position and drop that chunk
   off the back -- call callback, then reset the shared_ptr.  Then try
   to allocate a new assembled_chunk.  If resetting the shared_ptr
   drop the last reference to an assembled_chunk, then that chunk will
   become available.  If not (eg, if RPC thread has a copy of the
   shared_ptr), continue on to the next position.  This process will
   stop once we drop (assembled_ringbuf_capacity -
   assembled_ringbuf_size) chunks -- ie, all the chunks left in the
   buffer are the ones waiting to be consumed.

 - there will be a callback for when a chunk is being dropped.  This
   is where we handle the telescoping: we'll hold zero or one older
   chunks, and when a chunk is about to be dropped, if we had an older
   one, then we can downsample the two and then enqueue the resulting
   new chunk.  This enqueue call could (typically will, in
   steady-state) cause a cascade of dropping the oldest frame from the
   next ring buffer.

 - the longer-duration ring buffers do not have 'downstream'
   consumers.

- Huh, what if the queue of assembled chunks waiting for the
  downstream consumer and the ring buffer per se are two separate data
  structures that each hold shared_ptrs?

 - ring buffer could allocate an assembled_chunk *subclass* that tells
   the ring buffer when it is deleted.

 */

/*
 Single ringbuffer public API.

 ringbuf<T>(int size)

 // called when an item is about to be dropped off the end.
 virtual void drop(T);

 // try to enqueue an element; returns false if the ring buffer is full.
 bool enqueue(const T&)
 bool enqueue(T*)?
 shared_ptr<T> enqueue(T*)?

 //
 vector<T> snapshot(bool test(T*)) ?

 where T : shared_ptr<assembled_chunk> and we will subclass it to
 override drop() to do the telescoping.

 */

#include <iostream>
#include <queue>
#include <deque>
#include <functional>

using namespace std;
using namespace std::placeholders;

#include "ch_frb_io.hpp"
using namespace ch_frb_io;

std::ostream& operator<<(std::ostream& s, const assembled_chunk& ch) {
    s << "assembled_chunk(beam " << ch.beam_id << ", ichunk " << ch.ichunk << ")";
    return s;
}

// forward decl
template<class T>
class RingbufDeleter;

template<class T>
class Ringbuf {
    friend class RingbufDeleter<T>;

public:
    /*
     Creates a new Ringbuf with the given maximum quota size.
     */
    Ringbuf(int maxsize) :
        _deleter(this),
        _q(),
        _live(0),
        _maxsize(maxsize)
    {}

    virtual ~Ringbuf() {}

    /*
     Tries to push a new frame onto the ring buffer.  If the quota of
     frames has been reached, frames will be popped off the front
     until the buffer is empty.  If space is still not available, will
     return an empty shared_ptr.

     Returns the enqueued shared_ptr if successful.
     */
    shared_ptr<T> push(T* t) {
        while (_live >= _maxsize) {
            cout << "Push: _live >= _maxsize." << " (" << _live << " >= " << _maxsize << ")" << endl;
            if (_q.empty()) {
                cout << "Ring buffer empty but still too many live elements -- push fails" << endl;
                return shared_ptr<T>();
            }
            cout << "Dropping an element..." << endl;
            shared_ptr<T> p = _q.front();
            _q.pop_front();
            dropping(p);
            p.reset();
            cout << "Now " << _live << " live" << endl;
        }
        cout << "Creating shared_ptr..." << endl;
        shared_ptr<T> p(t, _deleter);
        _live++;
        _q.push_back(p);
        cout << "Now " << _live << " objects are live" << endl;
        return p;
    }

    /*
     Pops the oldest frame from this buffer.
     */
    shared_ptr<T> pop() {
        cout << "Popping..." << endl;
        shared_ptr<T> p = _q.pop_front();
        cout << "Pop: returning " << *p << endl;
        return p;
    }

    vector<shared_ptr<T> > snapshot(bool (*testFunc)(const shared_ptr<T>)) {
        vector<shared_ptr<T> > vec;
        for (auto it = _q.begin(); it != _q.end(); it++) {
	  if (!testFunc || testFunc(*it)) {
	    cout << "snapshot: " << (*it) << endl;
	    vec.push_back(*it);
	  }
        }
        return vec;
    }

protected:
    // Small helper class that calls deleted() when one of our frames
    // is deleted.
    RingbufDeleter<T> _deleter;

    // The actual queue of frames.
    deque<shared_ptr<T> > _q;

    // Number of live frames.
    size_t _live;
    // Maximum allowable number of live frames.
    size_t _maxsize;

    // We're about to drop this frame.
    virtual void dropping(shared_ptr<T> t) {}

    // Called by the RingbufDeleter when a shared_ptr is deleted
    void deleted(T* t) {
        cout << "Deleting object: " << *t << endl;
        _live--;
        cout << "Now " << _live << " objects are live" << endl;
        // FIXME --?
        delete t;
    }

};

template<class T>
class RingbufDeleter {
public:
    RingbufDeleter(Ringbuf<T>* rb) : _ringbuf(rb) {}

    void operator()(T* t) {
        cout << "RingbufDelete::operator() called." << endl;
        _ringbuf->deleted(t);
    }

protected:
    Ringbuf<T>* _ringbuf;
};

class L1Ringbuf;

class AssembledChunkRingbuf : public Ringbuf<assembled_chunk> {

public:
    AssembledChunkRingbuf(int binlevel, L1Ringbuf* parent, int maxsize) :
        Ringbuf<assembled_chunk>(maxsize),
        _binlevel(binlevel),
        _parent(parent)
    {}

    virtual ~AssembledChunkRingbuf() {}

protected:
    // my time-binning. level: 0 = original intensity stream; 1 =
    // binned x 2, 2 = binned x 4.
    int _binlevel;
    L1Ringbuf* _parent;

    // Called when the given frame *t* is being dropped off the buffer
    // to free up some space for a new frame.
    virtual void dropping(shared_ptr<assembled_chunk> t);

};

class L1Ringbuf {
    friend class AssembledChunkRingbuf;

    static const size_t Nbins = 4;

public:
    L1Ringbuf() :
        _q(),
        _rb(),
        _dropped()
    {
        for (size_t i=0; i<Nbins; i++)
            _rb.push_back(new AssembledChunkRingbuf(i, this, 4));
            //_rb[i] = new AssembledChunkRingbuf(i, this, 4);
        for (size_t i=0; i<Nbins-1; i++)
            _dropped.push_back(shared_ptr<assembled_chunk>());
    }

    ~L1Ringbuf() {
        for (size_t i=0; i<Nbins; i++)
            delete _rb[i];
    }

    bool push(assembled_chunk* ch) {
        shared_ptr<assembled_chunk> p = _rb[0]->push(ch);
        if (!p)
            return false;
        _q.push(p);
        return true;
    }

    shared_ptr<assembled_chunk> pop() {
        shared_ptr<assembled_chunk> p = _q.front();
        _q.pop();
        return p;
    }

    void print() {
        cout << "L1 ringbuf:" << endl;

        for (size_t i=0; i<Nbins; i++) {
            vector<shared_ptr<assembled_chunk> > v = _rb[i]->snapshot(NULL);
            cout << "  binning " << i << ": [ ";
            for (auto it = v.begin(); it != v.end(); it++) {
                cout << (*it)->ichunk << " ";
            }
            cout << "]" << endl;
            if (i < Nbins-1) {
                cout << "  dropped " << i << ": ";
                if (_dropped[i])
                    cout << _dropped[i]->ichunk << endl;
                else
                    cout << "none" << endl;
            }
        }
    }

protected:
    // The queue for downstream
    queue<shared_ptr<assembled_chunk> > _q;

    vector<AssembledChunkRingbuf*> _rb;
    //array<AssembledChunkRingbuf*, Nbins> _rb;
    vector<shared_ptr<assembled_chunk> > _dropped;
    //array<shared_ptr<assembled_chunk>, Nbins> _dropped;

    void dropping(int binlevel, shared_ptr<assembled_chunk> ch) {
        cout << "Bin level " << binlevel << " dropping a chunk" << endl;
        if (binlevel >= (int)(Nbins-1))
            return;

        if (_dropped[binlevel]) {
            cout << "Now have 2 dropped chunks from bin level " << binlevel << endl;
            // FIXME -- bin down
            assembled_chunk* binned = new assembled_chunk(ch->beam_id, ch->nupfreq, ch->nt_per_packet, ch->fpga_counts_per_sample, _dropped[binlevel]->ichunk);
            // push onto _rb[level+1]
            _rb[binlevel+1]->push(binned);
            _dropped[binlevel].reset();
        } else {
            // Keep this one until its partner arrives!
            cout << "Saving as _dropped" << binlevel << endl;
            _dropped[binlevel] = ch;
        }
    }

};

// after L1Ringbuf has been declared...
void AssembledChunkRingbuf::dropping(shared_ptr<assembled_chunk> t) {
    _parent->dropping(_binlevel, t);
}

int main() {

    L1Ringbuf rb;

    int beam = 77;
    int nupfreq = 4;
    int nt_per = 16;
    int fpga_per = 400;

    assembled_chunk* ch;
    //ch = assembled_chunk::make(4, nupfreq, nt_per, fpga_per, 42);

    for (int i=0; i<32; i++) {
        ch = new assembled_chunk(beam, nupfreq, nt_per, fpga_per, i);
        rb.push(ch);

        cout << "Pushed " << i << endl;
        rb.print();
        cout << endl;

        // downstream thread consumes with a lag of 2...
        if (i >= 2) {
            rb.pop();
        }
    }

}

/*
int main() {
    cout << "Creating ringbuf..." << endl;
    Ringbuf<int> rb(4);

    int a = 42;
    int b = 43;
    int c = 44;

    cout << "Pushing" << endl;
    rb.push(&a);
    cout << "Pushing" << endl;
    rb.push(&b);
    cout << "Pushing" << endl;
    rb.push(&c);

    cout << "Popping" << endl;
    shared_ptr<int> p1 = rb.pop();
    cout << "Popping" << endl;
    shared_ptr<int> p2 = rb.pop();
    cout << "Dropping" << endl;
    p1.reset();
    cout << endl;

    int d = 45;
    int e = 46;
    int f = 47;
    int g = 48;

    cout << "Pushing d..." << endl;
    shared_ptr<int> pd = rb.push(&d);

    cout << endl;
    cout << "Pushing e..." << endl;
    shared_ptr<int> pe = rb.push(&e);

    cout << endl;
    cout << "Pushing f..." << endl;
    shared_ptr<int> pf = rb.push(&f);

    cout << endl;
    cout << "Pushing g..." << endl;
    rb.push(&g);

    cout << "Done" << endl;

}
 */

<|endoftext|>


<commit_before>#include <QtNetwork>

#include "api-request.h"
#include "api-client.h"

SeafileApiRequest::SeafileApiRequest(const QUrl& url, Method method, const QString& token)
    : url_(url),
      method_(method),
      token_(token)
{
    api_client_ = new SeafileApiClient;
}

SeafileApiRequest::~SeafileApiRequest()
{
    delete api_client_;
}

void SeafileApiRequest::setParam(const QString& name, const QString& value)
{
    params_.addQueryItem(name, value);
}

void SeafileApiRequest::send()
{
    if (token_.size() > 0) {
        api_client_->setToken(token_);
    }

    switch (method_) {
    case METHOD_GET:
        api_client_->get(url_);
        break;
    case METHOD_POST:
        api_client_->post(url_, params_.encodedQuery());
        break;
    }

    connect(api_client_, SIGNAL(requestSuccess(QNetworkReply&)),
            this, SLOT(requestSuccess(QNetworkReply&)));

    connect(api_client_, SIGNAL(requestFailed(int)),
            this, SIGNAL(failed(int)));
}

json_t* SeafileApiRequest::parseJSON(QNetworkReply &reply, json_error_t *error)
{
    QByteArray raw = reply.readAll();
    //qDebug("\n%s\n", raw.data());
    json_t *root = json_loads(raw.data(), 0, error);
    return root;
}
<commit_msg>fixed api request post param escaping<commit_after>#include <QtNetwork>

#include "api-request.h"
#include "api-client.h"

SeafileApiRequest::SeafileApiRequest(const QUrl& url, Method method, const QString& token)
    : url_(url),
      method_(method),
      token_(token)
{
    api_client_ = new SeafileApiClient;
}

SeafileApiRequest::~SeafileApiRequest()
{
    delete api_client_;
}

void SeafileApiRequest::setParam(const QString& name, const QString& value)
{
    params_.addEncodedQueryItem(QUrl::toPercentEncoding(name),
                                QUrl::toPercentEncoding(value));
}

void SeafileApiRequest::send()
{
    if (token_.size() > 0) {
        api_client_->setToken(token_);
    }

    switch (method_) {
    case METHOD_GET:
        api_client_->get(url_);
        break;
    case METHOD_POST:
        api_client_->post(url_, params_.encodedQuery());
        break;
    }

    connect(api_client_, SIGNAL(requestSuccess(QNetworkReply&)),
            this, SLOT(requestSuccess(QNetworkReply&)));

    connect(api_client_, SIGNAL(requestFailed(int)),
            this, SIGNAL(failed(int)));
}

json_t* SeafileApiRequest::parseJSON(QNetworkReply &reply, json_error_t *error)
{
    QByteArray raw = reply.readAll();
    //qDebug("\n%s\n", raw.data());
    json_t *root = json_loads(raw.data(), 0, error);
    return root;
}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2014 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#ifndef DLL_OPENCV_RBM_VISUALIZER_HPP
#define DLL_OPENCV_RBM_VISUALIZER_HPP

#include "dll/stop_watch.hpp"
#include "dll/rbm_traits.hpp"
#include "dll/dbn_traits.hpp"

#include <opencv2/opencv.hpp>

namespace dll {

template<typename RBM>
struct opencv_rbm_visualizer {
    stop_watch<std::chrono::seconds> watch;

    const std::size_t shape = 28;
    const std::size_t num_hidden = 10;

    const bool scale = true;
    const std::size_t padding = 20;

    const std::size_t width;
    const std::size_t height;

    cv::Mat buffer_image;

    opencv_rbm_visualizer(std::size_t shape = 28, std::size_t num_hidden = 10, bool scale = true, std::size_t padding = 10) :
        shape(shape),
        num_hidden(num_hidden),
        scale(scale),
        padding(padding),
        width(shape * num_hidden + (num_hidden + 1) * 1 + 2 * padding),
        height(shape * num_hidden + (num_hidden + 1) * 1 + 2 * padding),
        buffer_image(cv::Size(width, height), CV_8UC1) {}

    void training_begin(const RBM& rbm){
        std::cout << "Train RBM with \"" << RBM::desc::template trainer_t<RBM>::name() << "\"" << std::endl;
        std::cout << "With parameters:" << std::endl;
        std::cout << "   learning_rate=" << rbm.learning_rate << std::endl;

        if(rbm_traits<RBM>::has_momentum()){
            std::cout << "   momentum=" << rbm.momentum << std::endl;
        }

        if(rbm_traits<RBM>::decay() == decay_type::L1 || rbm_traits<RBM>::decay() == decay_type::L1_FULL){
            std::cout << "   weight_cost(L1)=" << rbm.weight_cost << std::endl;
        }

        if(rbm_traits<RBM>::decay() == decay_type::L2 || rbm_traits<RBM>::decay() == decay_type::L2_FULL){
            std::cout << "   weight_cost(L2)=" << rbm.weight_cost << std::endl;
        }

        if(rbm_traits<RBM>::has_sparsity()){
            std::cout << "   sparsity_target=" << rbm.sparsity_target << std::endl;
        }

        cv::namedWindow("RBM Training", cv::WINDOW_NORMAL);

        refresh();
    }

    void epoch_end(std::size_t epoch, double error, double free_energy, const RBM& rbm){
        printf("epoch %ld - Reconstruction error average: %.5f - Free energy average: %.3f\n", epoch, error, free_energy);

        buffer_image = cv::Scalar(255);

        cv::putText(buffer_image, "epoch " + std::to_string(epoch), cv::Point(10,12), CV_FONT_NORMAL, 0.3, cv::Scalar(0), 1, 2);

        for(std::size_t hi = 0; hi < num_hidden; ++hi){
            for(std::size_t hj = 0; hj < num_hidden; ++hj){
                auto real_h = hi * num_hidden + hj;

                typename RBM::weight min = 100.0;
                typename RBM::weight max = 0.0;

                if(scale){
                    for(std::size_t real_v = 0; real_v < shape * shape; ++real_v){
                        min = std::min(rbm.w(real_v, real_h), min);
                        max = std::max(rbm.w(real_v, real_h), max);
                    }
                }

                for(std::size_t i = 0; i < shape; ++i){
                    for(std::size_t j = 0; j < shape; ++j){
                        auto real_v = i * shape + j;

                        auto value = rbm.w(real_v, real_h);

                        if(scale){
                            value -= min;
                            value *= 1.0 / (max + 1e-8);
                        }

                        buffer_image.at<uint8_t>(padding+1+hi*(shape+1)+i, padding+1+hj*(shape+1)+j) = value * 255;
                    }
                }
            }
        }

        refresh();
    }

    void training_end(const RBM&){
        std::cout << "Training took " << watch.elapsed() << "s" << std::endl;

        cv::waitKey(0);
    }

    void refresh(){
        cv::imshow("RBM Training", buffer_image);
        cv::waitKey(30);
    }
};

} //end of dll namespace

#endif<commit_msg>Fix default values<commit_after>//=======================================================================
// Copyright (c) 2014 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#ifndef DLL_OPENCV_RBM_VISUALIZER_HPP
#define DLL_OPENCV_RBM_VISUALIZER_HPP

#include "dll/stop_watch.hpp"
#include "dll/rbm_traits.hpp"
#include "dll/dbn_traits.hpp"

#include <opencv2/opencv.hpp>

namespace dll {

template<typename RBM>
struct opencv_rbm_visualizer {
    stop_watch<std::chrono::seconds> watch;

    const std::size_t shape = 28;
    const std::size_t num_hidden = 10;

    const bool scale = true;
    const std::size_t padding = 20;

    const std::size_t width;
    const std::size_t height;

    cv::Mat buffer_image;

    opencv_rbm_visualizer(std::size_t shape = 28, std::size_t num_hidden = 10, bool scale = true, std::size_t padding = 20) :
        shape(shape),
        num_hidden(num_hidden),
        scale(scale),
        padding(padding),
        width(shape * num_hidden + (num_hidden + 1) * 1 + 2 * padding),
        height(shape * num_hidden + (num_hidden + 1) * 1 + 2 * padding),
        buffer_image(cv::Size(width, height), CV_8UC1) {}

    void training_begin(const RBM& rbm){
        std::cout << "Train RBM with \"" << RBM::desc::template trainer_t<RBM>::name() << "\"" << std::endl;
        std::cout << "With parameters:" << std::endl;
        std::cout << "   learning_rate=" << rbm.learning_rate << std::endl;

        if(rbm_traits<RBM>::has_momentum()){
            std::cout << "   momentum=" << rbm.momentum << std::endl;
        }

        if(rbm_traits<RBM>::decay() == decay_type::L1 || rbm_traits<RBM>::decay() == decay_type::L1_FULL){
            std::cout << "   weight_cost(L1)=" << rbm.weight_cost << std::endl;
        }

        if(rbm_traits<RBM>::decay() == decay_type::L2 || rbm_traits<RBM>::decay() == decay_type::L2_FULL){
            std::cout << "   weight_cost(L2)=" << rbm.weight_cost << std::endl;
        }

        if(rbm_traits<RBM>::has_sparsity()){
            std::cout << "   sparsity_target=" << rbm.sparsity_target << std::endl;
        }

        cv::namedWindow("RBM Training", cv::WINDOW_NORMAL);

        refresh();
    }

    void epoch_end(std::size_t epoch, double error, double free_energy, const RBM& rbm){
        printf("epoch %ld - Reconstruction error average: %.5f - Free energy average: %.3f\n", epoch, error, free_energy);

        buffer_image = cv::Scalar(255);

        cv::putText(buffer_image, "epoch " + std::to_string(epoch), cv::Point(10,12), CV_FONT_NORMAL, 0.3, cv::Scalar(0), 1, 2);

        for(std::size_t hi = 0; hi < num_hidden; ++hi){
            for(std::size_t hj = 0; hj < num_hidden; ++hj){
                auto real_h = hi * num_hidden + hj;

                typename RBM::weight min = 100.0;
                typename RBM::weight max = 0.0;

                if(scale){
                    for(std::size_t real_v = 0; real_v < shape * shape; ++real_v){
                        min = std::min(rbm.w(real_v, real_h), min);
                        max = std::max(rbm.w(real_v, real_h), max);
                    }
                }

                for(std::size_t i = 0; i < shape; ++i){
                    for(std::size_t j = 0; j < shape; ++j){
                        auto real_v = i * shape + j;

                        auto value = rbm.w(real_v, real_h);

                        if(scale){
                            value -= min;
                            value *= 1.0 / (max + 1e-8);
                        }

                        buffer_image.at<uint8_t>(padding+1+hi*(shape+1)+i, padding+1+hj*(shape+1)+j) = value * 255;
                    }
                }
            }
        }

        refresh();
    }

    void training_end(const RBM&){
        std::cout << "Training took " << watch.elapsed() << "s" << std::endl;

        cv::waitKey(0);
    }

    void refresh(){
        cv::imshow("RBM Training", buffer_image);
        cv::waitKey(30);
    }
};

} //end of dll namespace

#endif<|endoftext|>


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

#include <set>
#include <sstream>

#include "ngraph/op/batch_norm.hpp"
#include "ngraph/op/constant.hpp"
#include "ngraph/op/get_output_element.hpp"
#include "ngraph/validation_util.hpp"

ngraph::op::BatchNormInference::BatchNormInference(double eps,
                                                   std::shared_ptr<ngraph::Node> gamma,
                                                   std::shared_ptr<ngraph::Node> beta,
                                                   std::shared_ptr<ngraph::Node> input,
                                                   std::shared_ptr<ngraph::Node> mean,
                                                   std::shared_ptr<ngraph::Node> variance)
    : Op("BatchNormInference", check_single_output_args({gamma, beta, input, mean, variance}))
    , m_epsilon(eps)
{
    constructor_validate_and_infer_types();
}

ngraph::op::BatchNormTraining::BatchNormTraining(double eps,
                                                 std::shared_ptr<ngraph::Node> gamma,
                                                 std::shared_ptr<ngraph::Node> beta,
                                                 std::shared_ptr<ngraph::Node> input)
    : Op("BatchNormTraining", check_single_output_args({gamma, beta, input}))
    , m_epsilon(eps)
{
    constructor_validate_and_infer_types();
}

void ngraph::op::BatchNormInference::validate_and_infer_types()
{
    element::Type result_et;
    PartialShape result_batch_shape;
    PartialShape result_channel_shape; // unused here

    std::tie(result_et, result_batch_shape, result_channel_shape) =
        infer_batch_norm_forward(this,
                                 get_input_element_type(INPUT_DATA),
                                 get_input_element_type(INPUT_GAMMA),
                                 get_input_element_type(INPUT_BETA),
                                 get_input_element_type(INPUT_MEAN),
                                 get_input_element_type(INPUT_VARIANCE),
                                 get_input_partial_shape(INPUT_DATA),
                                 get_input_partial_shape(INPUT_GAMMA),
                                 get_input_partial_shape(INPUT_BETA),
                                 get_input_partial_shape(INPUT_MEAN),
                                 get_input_partial_shape(INPUT_VARIANCE));

    set_output_size(1);
    set_output_type(0, result_et, result_batch_shape);
}

void ngraph::op::BatchNormTraining::validate_and_infer_types()
{
    element::Type result_et;
    PartialShape result_batch_shape;
    PartialShape result_channel_shape;

    std::tie(result_et, result_batch_shape, result_channel_shape) =
        infer_batch_norm_forward(this,
                                 get_input_element_type(INPUT_DATA),
                                 get_input_element_type(INPUT_GAMMA),
                                 get_input_element_type(INPUT_BETA),
                                 get_input_partial_shape(INPUT_DATA),
                                 get_input_partial_shape(INPUT_GAMMA),
                                 get_input_partial_shape(INPUT_BETA));

    set_output_size(3);
    set_output_type(0, result_et, result_batch_shape);
    set_output_type(1, result_et, result_channel_shape);
    set_output_type(2, result_et, result_channel_shape);
}

std::shared_ptr<ngraph::Node>
    ngraph::op::BatchNormInference::copy_with_new_args(const NodeVector& new_args) const
{
    check_new_args_count(this, new_args);
    return std::make_shared<BatchNormInference>(
        m_epsilon, new_args.at(0), new_args.at(1), new_args.at(2), new_args.at(3), new_args.at(4));
}

std::shared_ptr<ngraph::Node>
    ngraph::op::BatchNormTraining::copy_with_new_args(const NodeVector& new_args) const
{
    check_new_args_count(this, new_args);
    return std::make_shared<BatchNormTraining>(
        m_epsilon, new_args.at(0), new_args.at(1), new_args.at(2));
}

ngraph::op::BatchNormTrainingBackprop::BatchNormTrainingBackprop(
    double eps,
    std::shared_ptr<ngraph::Node> gamma,
    std::shared_ptr<ngraph::Node> beta,
    std::shared_ptr<ngraph::Node> input,
    std::shared_ptr<ngraph::Node> mean,
    std::shared_ptr<ngraph::Node> variance,
    std::shared_ptr<ngraph::Node> delta)
    : Op("BatchNormTrainingBackprop",
         check_single_output_args({gamma, beta, input, mean, variance, delta}))
    , m_epsilon(eps)

{
    constructor_validate_and_infer_types();
}

void ngraph::op::BatchNormTrainingBackprop::validate_and_infer_types()
{
    PartialShape input_and_delta_shape{get_input_partial_shape(INPUT_DATA)};

    NODE_VALIDATION_ASSERT(
        this, PartialShape::merge_into(input_and_delta_shape, get_input_partial_shape(INPUT_DELTA)))
        << "Shape of delta does not match the shape of the input data (input data shape: "
        << get_input_partial_shape(INPUT_DATA)
        << ", delta shape: " << get_input_partial_shape(INPUT_DELTA) << ").";

    element::Type input_and_delta_et;

    NODE_VALIDATION_ASSERT(this,
                           element::Type::merge(input_and_delta_et,
                                                get_input_element_type(INPUT_DATA),
                                                get_input_element_type(INPUT_DELTA)))
        << "Element type for input (" << get_input_element_type(INPUT_DATA)
        << ") does not match element type for delta (" << get_input_element_type(INPUT_DATA)
        << ").";

    element::Type result_et;
    PartialShape result_batch_shape;
    PartialShape result_channel_shape;

    std::tie(result_et, result_batch_shape, result_channel_shape) =
        infer_batch_norm_forward(this,
                                 input_and_delta_et,
                                 get_input_element_type(INPUT_GAMMA),
                                 get_input_element_type(INPUT_BETA),
                                 get_input_element_type(INPUT_MEAN),
                                 get_input_element_type(INPUT_VARIANCE),
                                 input_and_delta_shape,
                                 get_input_partial_shape(INPUT_GAMMA),
                                 get_input_partial_shape(INPUT_BETA),
                                 get_input_partial_shape(INPUT_MEAN),
                                 get_input_partial_shape(INPUT_VARIANCE));

    set_output_size(3);
    set_output_type(0, result_et, result_batch_shape);
    set_output_type(1, result_et, result_channel_shape);
    set_output_type(2, result_et, result_channel_shape);
}

std::shared_ptr<ngraph::Node>
    ngraph::op::BatchNormTrainingBackprop::copy_with_new_args(const NodeVector& new_args) const
{
    check_new_args_count(this, new_args);
    return std::make_shared<op::BatchNormTrainingBackprop>(m_epsilon,
                                                           new_args.at(0),
                                                           new_args.at(1),
                                                           new_args.at(2),
                                                           new_args.at(3),
                                                           new_args.at(4),
                                                           new_args.at(5));
}

void ngraph::op::BatchNormTraining::generate_adjoints(autodiff::Adjoints& adjoints,
                                                      const NodeVector& deltas)
{
    auto gamma = get_argument(0);
    auto beta = get_argument(1);
    auto input = get_argument(2);
    std::shared_ptr<Node> mean = nullptr;
    std::shared_ptr<Node> var = nullptr;

    // Extract mean and variance outputs from BatchNormBase
    // as these are used by BatchNormTrainingBackprop.
    // The users of the outputs (GetOutputElements' Inputs) aren't sorted
    // and get_n() is used to sort the inputs in the same order as Batchnorm's outputs
    // Next, Mean and Variance (`at(1)` and `at(2)`) are extracted
    // Please see `add_output` in `BatchNormBase::BatchNormBase` for more details

    auto goes = op::get_output_elements(shared_from_this());
    mean = goes.at(1);
    var = goes.at(2);
    if (!mean)
    {
        throw ngraph_error("GetOutputElement for mean is missing");
    }

    if (!var)
    {
        throw ngraph_error("GetOutputElement for variance is missing");
    }

    auto bbn = std::make_shared<op::BatchNormTrainingBackprop>(
        get_eps_value(), gamma, beta, input, mean, var, deltas.at(0));
    auto dinput = std::make_shared<op::GetOutputElement>(bbn, 0);
    auto dgamma = std::make_shared<op::GetOutputElement>(bbn, 1);
    auto dbeta = std::make_shared<op::GetOutputElement>(bbn, 2);

    adjoints.add_delta(input, dinput);
    adjoints.add_delta(gamma, dgamma);
    adjoints.add_delta(beta, dbeta);
}
<commit_msg>Update BatchNorm to set_output_size at construction time (#1963)<commit_after>//*****************************************************************************
// Copyright 2017-2018 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//*****************************************************************************

#include <set>
#include <sstream>

#include "ngraph/op/batch_norm.hpp"
#include "ngraph/op/constant.hpp"
#include "ngraph/op/get_output_element.hpp"
#include "ngraph/validation_util.hpp"

ngraph::op::BatchNormInference::BatchNormInference(double eps,
                                                   std::shared_ptr<ngraph::Node> gamma,
                                                   std::shared_ptr<ngraph::Node> beta,
                                                   std::shared_ptr<ngraph::Node> input,
                                                   std::shared_ptr<ngraph::Node> mean,
                                                   std::shared_ptr<ngraph::Node> variance)
    : Op("BatchNormInference", check_single_output_args({gamma, beta, input, mean, variance}))
    , m_epsilon(eps)
{
    set_output_size(1);
    constructor_validate_and_infer_types();
}

ngraph::op::BatchNormTraining::BatchNormTraining(double eps,
                                                 std::shared_ptr<ngraph::Node> gamma,
                                                 std::shared_ptr<ngraph::Node> beta,
                                                 std::shared_ptr<ngraph::Node> input)
    : Op("BatchNormTraining", check_single_output_args({gamma, beta, input}))
    , m_epsilon(eps)
{
    set_output_size(3);
    constructor_validate_and_infer_types();
}

void ngraph::op::BatchNormInference::validate_and_infer_types()
{
    element::Type result_et;
    PartialShape result_batch_shape;
    PartialShape result_channel_shape; // unused here

    std::tie(result_et, result_batch_shape, result_channel_shape) =
        infer_batch_norm_forward(this,
                                 get_input_element_type(INPUT_DATA),
                                 get_input_element_type(INPUT_GAMMA),
                                 get_input_element_type(INPUT_BETA),
                                 get_input_element_type(INPUT_MEAN),
                                 get_input_element_type(INPUT_VARIANCE),
                                 get_input_partial_shape(INPUT_DATA),
                                 get_input_partial_shape(INPUT_GAMMA),
                                 get_input_partial_shape(INPUT_BETA),
                                 get_input_partial_shape(INPUT_MEAN),
                                 get_input_partial_shape(INPUT_VARIANCE));

    set_output_type(0, result_et, result_batch_shape);
}

void ngraph::op::BatchNormTraining::validate_and_infer_types()
{
    element::Type result_et;
    PartialShape result_batch_shape;
    PartialShape result_channel_shape;

    std::tie(result_et, result_batch_shape, result_channel_shape) =
        infer_batch_norm_forward(this,
                                 get_input_element_type(INPUT_DATA),
                                 get_input_element_type(INPUT_GAMMA),
                                 get_input_element_type(INPUT_BETA),
                                 get_input_partial_shape(INPUT_DATA),
                                 get_input_partial_shape(INPUT_GAMMA),
                                 get_input_partial_shape(INPUT_BETA));

    set_output_type(0, result_et, result_batch_shape);
    set_output_type(1, result_et, result_channel_shape);
    set_output_type(2, result_et, result_channel_shape);
}

std::shared_ptr<ngraph::Node>
    ngraph::op::BatchNormInference::copy_with_new_args(const NodeVector& new_args) const
{
    check_new_args_count(this, new_args);
    return std::make_shared<BatchNormInference>(
        m_epsilon, new_args.at(0), new_args.at(1), new_args.at(2), new_args.at(3), new_args.at(4));
}

std::shared_ptr<ngraph::Node>
    ngraph::op::BatchNormTraining::copy_with_new_args(const NodeVector& new_args) const
{
    check_new_args_count(this, new_args);
    return std::make_shared<BatchNormTraining>(
        m_epsilon, new_args.at(0), new_args.at(1), new_args.at(2));
}

ngraph::op::BatchNormTrainingBackprop::BatchNormTrainingBackprop(
    double eps,
    std::shared_ptr<ngraph::Node> gamma,
    std::shared_ptr<ngraph::Node> beta,
    std::shared_ptr<ngraph::Node> input,
    std::shared_ptr<ngraph::Node> mean,
    std::shared_ptr<ngraph::Node> variance,
    std::shared_ptr<ngraph::Node> delta)
    : Op("BatchNormTrainingBackprop",
         check_single_output_args({gamma, beta, input, mean, variance, delta}))
    , m_epsilon(eps)

{
    set_output_size(3);
    constructor_validate_and_infer_types();
}

void ngraph::op::BatchNormTrainingBackprop::validate_and_infer_types()
{
    PartialShape input_and_delta_shape{get_input_partial_shape(INPUT_DATA)};

    NODE_VALIDATION_ASSERT(
        this, PartialShape::merge_into(input_and_delta_shape, get_input_partial_shape(INPUT_DELTA)))
        << "Shape of delta does not match the shape of the input data (input data shape: "
        << get_input_partial_shape(INPUT_DATA)
        << ", delta shape: " << get_input_partial_shape(INPUT_DELTA) << ").";

    element::Type input_and_delta_et;

    NODE_VALIDATION_ASSERT(this,
                           element::Type::merge(input_and_delta_et,
                                                get_input_element_type(INPUT_DATA),
                                                get_input_element_type(INPUT_DELTA)))
        << "Element type for input (" << get_input_element_type(INPUT_DATA)
        << ") does not match element type for delta (" << get_input_element_type(INPUT_DATA)
        << ").";

    element::Type result_et;
    PartialShape result_batch_shape;
    PartialShape result_channel_shape;

    std::tie(result_et, result_batch_shape, result_channel_shape) =
        infer_batch_norm_forward(this,
                                 input_and_delta_et,
                                 get_input_element_type(INPUT_GAMMA),
                                 get_input_element_type(INPUT_BETA),
                                 get_input_element_type(INPUT_MEAN),
                                 get_input_element_type(INPUT_VARIANCE),
                                 input_and_delta_shape,
                                 get_input_partial_shape(INPUT_GAMMA),
                                 get_input_partial_shape(INPUT_BETA),
                                 get_input_partial_shape(INPUT_MEAN),
                                 get_input_partial_shape(INPUT_VARIANCE));

    set_output_type(0, result_et, result_batch_shape);
    set_output_type(1, result_et, result_channel_shape);
    set_output_type(2, result_et, result_channel_shape);
}

std::shared_ptr<ngraph::Node>
    ngraph::op::BatchNormTrainingBackprop::copy_with_new_args(const NodeVector& new_args) const
{
    check_new_args_count(this, new_args);
    return std::make_shared<op::BatchNormTrainingBackprop>(m_epsilon,
                                                           new_args.at(0),
                                                           new_args.at(1),
                                                           new_args.at(2),
                                                           new_args.at(3),
                                                           new_args.at(4),
                                                           new_args.at(5));
}

void ngraph::op::BatchNormTraining::generate_adjoints(autodiff::Adjoints& adjoints,
                                                      const NodeVector& deltas)
{
    auto gamma = get_argument(0);
    auto beta = get_argument(1);
    auto input = get_argument(2);
    std::shared_ptr<Node> mean = nullptr;
    std::shared_ptr<Node> var = nullptr;

    // Extract mean and variance outputs from BatchNormBase
    // as these are used by BatchNormTrainingBackprop.
    // The users of the outputs (GetOutputElements' Inputs) aren't sorted
    // and get_n() is used to sort the inputs in the same order as Batchnorm's outputs
    // Next, Mean and Variance (`at(1)` and `at(2)`) are extracted
    // Please see `add_output` in `BatchNormBase::BatchNormBase` for more details

    auto goes = op::get_output_elements(shared_from_this());
    mean = goes.at(1);
    var = goes.at(2);
    if (!mean)
    {
        throw ngraph_error("GetOutputElement for mean is missing");
    }

    if (!var)
    {
        throw ngraph_error("GetOutputElement for variance is missing");
    }

    auto bbn = std::make_shared<op::BatchNormTrainingBackprop>(
        get_eps_value(), gamma, beta, input, mean, var, deltas.at(0));
    auto dinput = std::make_shared<op::GetOutputElement>(bbn, 0);
    auto dgamma = std::make_shared<op::GetOutputElement>(bbn, 1);
    auto dbeta = std::make_shared<op::GetOutputElement>(bbn, 2);

    adjoints.add_delta(input, dinput);
    adjoints.add_delta(gamma, dgamma);
    adjoints.add_delta(beta, dbeta);
}
<|endoftext|>