dynare/mex/sources/estimation/libmat/Vector.hh

329 lines
8.1 KiB
C++

/*
* Copyright (C) 2010-2017 Dynare Team
*
* This file is part of Dynare.
*
* Dynare is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Dynare 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Dynare. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _VECTOR_HH
#define _VECTOR_HH
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cassert>
#include <cmath>
/*
This header defines three vector classes, which implement a "vector concept"
(much like the concepts of the Standard Template Library or of Boost
Library). The first class is a vector owning the data space for its elements,
and the other two are vector "views" of something else (either a subvector of
another vector, or a row or column of a matrix). This design philosophy is
close to the design of the GNU Scientific Library, but here using the
syntactic power of C++ class and templates, while achieving very high
efficiency.
These classes can be used with various templated functions, including
wrappers around the BLAS primitives.
The expressions required to be valid for a class V implementing the "vector concept" are:
- V.getSize(): return number of elements
- V.getStride(): return the stride, i.e. the offset between two elements in the data space
- V.getData(): return the pointer to the data space
- V(i): get an element of the vector
The expressions required to be valid for a class V implementing the "mutable vector concept" are (in addition to those of "vector concept"):
- V = X: assignment operator
- V(i) = d: assign an element of the vector
- V.setAll(d): set all the elements of the vector
*/
//! A full vector, implements the "mutable vector concept"
/*! Owns the data space for the elements */
class Vector
{
private:
double *data;
const size_t size;
public:
Vector(size_t size_arg);
Vector(const Vector &arg);
virtual
~Vector();
inline size_t
getSize() const
{
return size;
}
inline size_t
getStride() const
{
return 1;
}
inline double *
getData()
{
return data;
}
inline const double *
getData() const
{
return data;
}
inline void
setAll(double val)
{
std::fill_n(data, size, val);
}
inline double &
operator()(size_t i)
{
return data[i];
}
inline const double &
operator()(size_t i) const
{
return data[i];
}
//! Assignment operator, only works for vectors of same size
template<class Vec>
Vector &
operator=(const Vec &arg)
{
assert(size == arg.getSize());
const double *p2 = arg.getData();
for (double *p1 = data; p1 < data + size; p1++)
{
*p1 = *p2;
p2 += arg.getStride();
}
return *this;
}
//! The copy assignment operator, which is not generated by the template assignment operator
/*! See C++ standard, §12.8.9, in the footnote */
Vector &operator=(const Vector &arg);
};
//! A vector view (i.e. a subvector of another vector, or a row or column of a matrix), implements the "mutable vector concept"
/*! Does not own the data space for the elements, so depends on another vector or matrix */
class VectorView
{
private:
double *const data;
const size_t size, stride;
public:
VectorView(double *data_arg, size_t size_arg, size_t stride_arg);
/* Can't use a template for the 2 constructors below: this would override the
constructor which uses a pointer, because the argument list is the same */
VectorView(Vector &arg, size_t offset, size_t size_arg);
VectorView(VectorView &arg, size_t offset, size_t size_arg);
virtual ~VectorView()
{
};
inline size_t
getSize() const
{
return size;
}
inline size_t
getStride() const
{
return stride;
}
inline double *
getData()
{
return data;
}
inline const double *
getData() const
{
return data;
}
inline void
setAll(double val)
{
for (double *p = data; p < data + size*stride; p += stride)
*p = val;
}
inline double &
operator()(size_t i)
{
return data[i*stride];
}
inline const double &
operator()(size_t i) const
{
return data[i*stride];
}
//! Assignment operator, only works for vectors of same size
template<class Vec>
VectorView &
operator=(const Vec &arg)
{
assert(size == arg.getSize());
double *p1;
const double *p2;
for (p1 = data, p2 = arg.getData(); p1 < data + size*stride; p1 += stride, p2 += arg.getStride())
*p1 = *p2;
return *this;
}
//! The copy assignment operator, which is not generated by the template assignment operator
/*! See C++ standard, §12.8.9, in the footnote */
VectorView &operator=(const VectorView &arg);
};
//! Like a VectorView, but the data cannot be modified (implements the "vector concept")
class VectorConstView
{
private:
const double *const data;
const size_t size, stride;
public:
VectorConstView(const double *data_arg, size_t size_arg, size_t stride_arg);
/* Can't use a template for the 3 constructors below: this would override the
constructor which uses a pointer, because the argument list is the same */
VectorConstView(const Vector &arg, size_t offset, size_t size_arg);
VectorConstView(const VectorView &arg, size_t offset, size_t size_arg);
VectorConstView(const VectorConstView &arg, size_t offset, size_t size_arg);
virtual ~VectorConstView()
{
};
inline size_t
getSize() const
{
return size;
}
inline size_t
getStride() const
{
return stride;
}
inline const double *
getData() const
{
return data;
}
inline const double &
operator()(size_t i) const
{
return data[i*stride];
}
};
std::ostream &operator<<(std::ostream &out, const Vector &V);
std::ostream &operator<<(std::ostream &out, const VectorView &V);
std::ostream &operator<<(std::ostream &out, const VectorConstView &V);
namespace vec
{
template<class Vec>
void
print(std::ostream &out, const Vec &V)
{
for (size_t i = 0; i < V.getSize(); i++)
out << V(i) << " ";
out << std::endl;
}
//! Computes v1 = v1 + v2
template<class Vec1, class Vec2>
void
add(Vec1 &v1, const Vec2 &v2)
{
assert(v1.getSize() == v2.getSize());
double *p1 = v1.getData();
const double *p2 = v2.getData();
while (p1 < v1.getData() + v1.getSize() * v1.getStride())
{
*p1 += *p2;
p1 += v1.getStride();
p2 += v2.getStride();
}
}
//! Computes v1 = v1 - v2
template<class Vec1, class Vec2>
void
sub(Vec1 &v1, const Vec2 &v2)
{
assert(v1.getSize() == v2.getSize());
double *p1 = v1.getData();
const double *p2 = v2.getData();
while (p1 < v1.getData() + v1.getSize() * v1.getStride())
{
*p1 -= *p2;
p1 += v1.getStride();
p2 += v2.getStride();
}
}
//! Does v = -v
template<class Vec>
void
negate(Vec &v)
{
double *p = v.getData();
while (p < v.getData() + v.getSize() * v.getStride())
{
*p = -*p;
p += v.getStride();
}
}
// Computes the infinite norm of a vector
template<class Vec>
double
nrminf(const Vec &v)
{
double nrm = 0;
const double *p = v.getData();
while (p < v.getData() + v.getSize() * v.getStride())
{
if (fabs(*p) > nrm)
nrm = fabs(*p);
p += v.getStride();
}
return nrm;
}
// Computes the sum, min and max of a vector
// and returns double mean=sum/size
template<class Vec>
double
meanSumMinMax(double &sum, double &min, double &max, const Vec &v)
{
sum = 0;
min = max = v(0);
const double *p = v.getData();
while (p < v.getData() + v.getSize() * v.getStride())
{
if ((*p) > max)
max = (*p);
if ((*p) < min)
min = (*p);
sum += *p;
p += v.getStride();
}
return sum/v.getSize();
}
} // End of namespace
#endif