/*! * * * \brief Model for scaling and translation of data vectors. * * * * \author T. Glasmachers * \date 2013 * * * \par Copyright 1995-2017 Shark Development Team * *

* This file is part of Shark. * * * Shark is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Shark is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Shark. If not, see . * */ #ifndef SHARK_MODELS_NORMALIZER_H #define SHARK_MODELS_NORMALIZER_H #include #include namespace shark { /// /// \brief "Diagonal" linear model for data normalization. /// /// \par /// The Normalizer is a restricted and often more efficient variant of /// the LinearModel class. It restricts the linear model in two respects: /// (1) input and output dimension must agree, /// (2) computations are independent for each component. /// This is useful mostly for data normalization (therefore the name). /// The model's operation is of the form \f$ x \mapsto A x + b \f$ where /// A is a diagonal matrix. This reduces memory requirements to linear, /// which is why there is no sparse version of this model (as opposed to /// the more general linear model). Also, the addition of b is optional. /// template class Normalizer : public AbstractModel { public: typedef AbstractModel base_type; typedef Normalizer self_type; typedef typename base_type::BatchInputType BatchInputType; typedef typename base_type::BatchOutputType BatchOutputType; /// \brief Construction from dimension Normalizer(std::size_t dimension = 0, bool hasOffset = false) { setStructure(dimension,hasOffset);} /// \brief Construction from matrix and and optional offset vector Normalizer(VectorType const& diagonal, VectorType const& offset = VectorType()) { setStructure(diagonal, offset);} /// \brief From INameable: return the class name. std::string name() const { return "Normalizer"; } /// \brief derivative storage object (empty for this model) boost::shared_ptr createState() const{ return boost::shared_ptr(new EmptyState()); } /// \brief check for the presence of an offset term bool hasOffset() const{ return !m_b.empty(); } /// \brief obtain the input dimension Shape inputShape() const{ return m_A.size(); } /// \brief obtain the output dimension Shape outputShape() const{ return m_A.size(); } /// \brief return the diagonal of the matrix VectorType const& diagonal() const{ return m_A; } /// \brief return the offset vector VectorType const& offset() const{ return m_b; } /// \brief obtain the parameter vector VectorType parameterVector() const{ return m_A | m_b; } /// \brief overwrite the parameter vector void setParameterVector(VectorType const& newParameters){ SIZE_CHECK(newParameters.size() == numberOfParameters()); std::size_t dim = m_A.size(); noalias(m_A) = subrange(newParameters,0,dim); noalias(m_b) = subrange(newParameters, dim, newParameters.size()); } /// \brief return the number of parameter std::size_t numberOfParameters() const{ return m_A.size() + m_b.size(); } /// \brief overwrite structure and parameters void setStructure(VectorType const& diagonal, VectorType const& offset = VectorType()){ m_A = diagonal; m_b = offset; } /// \brief overwrite structure and parameters void setStructure(std::size_t dimension, bool hasOffset = false){ m_A.resize(dimension); m_b.resize(hasOffset? dimension : 0); } using base_type::eval; /// \brief Evaluate the model: output = matrix * input + offset. void eval(BatchInputType const& input, BatchOutputType& output) const{ SIZE_CHECK(input.size2() == m_A.size()); output.resize(input.size1(), input.size2()); noalias(output) = input * repeat(m_A,input.size1()); if (hasOffset()){ noalias(output) += repeat(m_b,input.size1()); } } /// \brief Evaluate the model: output = matrix * input + offset. void eval(BatchInputType const& input, BatchOutputType& output, State& state) const{ eval(input, output); } /// from ISerializable void read(InArchive& archive){ archive & m_A; archive & m_b; } /// from ISerializable void write(OutArchive& archive) const{ archive & m_A; archive & m_b; } protected: VectorType m_A; ///< matrix A (see class documentation) VectorType m_b; ///< vector b (see class documentation) }; } #endif