ldsCtrlEst_h/lds_uniform_mats.h #
List of uniformly sized matrices. More…
Namespaces #
Name |
---|
lds Linear Dynamical Systems (LDS) namespace. |
Classes #
Name | |
---|---|
class | lds::UniformMatrixList |
Detailed Description #
This file provides a container for uniformly sized matrices. Users may specify one dimension to be free to vary in the list.
Source code #
//===-- ldsCtrlEst_h/lds_uniform_mats.h - Uniform Matrices ------*- C++ -*-===//
//
// Copyright 2021 Michael Bolus
// Copyright 2021 Georgia Institute of Technology
//
// 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.
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
#ifndef LDSCTRLEST_LDS_UNIFORM_MATS_H
#define LDSCTRLEST_LDS_UNIFORM_MATS_H
#include <array> // std::array
#include <vector> // std::vector
#include "lds.h"
namespace lds {
template <MatrixListFreeDim D = kMatFreeDimNone>
class UniformMatrixList : public std::vector<Matrix> {
private:
// TODO(mfbolus): would rather *uncomment* the below for sake of conversion
// using std::vector<Matrix>::vector;
using std::vector<Matrix>::operator=;
using std::vector<Matrix>::operator[];
using std::vector<Matrix>::begin;
using std::vector<Matrix>::end;
using std::vector<Matrix>::size;
public:
using std::vector<Matrix>::at;
UniformMatrixList() = default;
explicit UniformMatrixList(const std::vector<Matrix>& mats,
std::array<size_t, 2> dim = {0, 0});
explicit UniformMatrixList(std::vector<Matrix>&& mats,
std::array<size_t, 2> dim = {0, 0});
UniformMatrixList(std::initializer_list<Matrix> mats,
std::array<size_t, 2> dim = {0, 0});
UniformMatrixList(const UniformMatrixList<D>& that);
UniformMatrixList(UniformMatrixList<D>&& that) noexcept;
~UniformMatrixList() = default;
const std::array<size_t, 2>& dim(size_t n = 0) const { return dim_.at(n); }
size_t size() { return std::vector<Matrix>::size(); };
const Matrix& at(size_t n) { return std::vector<Matrix>::at(n); };
void Swap(Matrix& that, size_t n);
UniformMatrixList<D>& operator=(const UniformMatrixList<D>& that);
UniformMatrixList<D>& operator=(UniformMatrixList<D>&& that) noexcept;
private:
void CheckDimensions(std::array<size_t, 2> dim);
std::vector<std::array<size_t, 2>> dim_;
};
template <MatrixListFreeDim D>
inline void UniformMatrixList<D>::Swap(Matrix& that, size_t n) {
// make sure request in range
if (n >= this->size()) {
std::cerr
<< "Requested UniformMatrixList element out of bounds. Skipping.\n";
return;
}
// check dim
bool does_match = true;
if (!(D == kMatFreeDim1)) {
does_match = does_match && (dim_[0][0] == that.n_rows);
}
if (!(D == kMatFreeDim2)) {
does_match = does_match && (dim_[0][1] == that.n_cols);
}
if (!does_match) {
std::cerr << "Cannot swap a UniformMatrixList element for an element of "
"different size. Skipping.\n";
return;
}
// if checks pass, perform swap
Matrix tmp = std::move((*this)[n]);
(*this)[n] = std::move(that);
that = std::move(tmp);
if (D == kMatFreeDim1) {
this->dim_[n][0] = (*this)[n].n_rows;
}
if (D == kMatFreeDim2) {
this->dim_[n][1] = (*this)[n].n_cols;
}
}
template <MatrixListFreeDim D>
inline UniformMatrixList<D>& UniformMatrixList<D>::operator=(
const UniformMatrixList<D>& that) {
// make sure dim_ vector is initialized
if (dim_.empty()) {
dim_ = std::vector<std::array<size_t, 2>>(that.size(), {0, 0});
}
// check dimensions
if (!this->empty()) {
if (this->size() != that.size()) {
std::ostringstream ss;
ss << "cannot reassign " << this->size() << " matrices with "
<< that.size() << " matrices";
throw std::runtime_error(ss.str());
}
// if dimensions a not zero and do not match, skip move with error message.
bool dims_nonzero = true;
for (auto d : dim_) {
if (!(D == kMatFreeDim1) && d[0] < 1) {
dims_nonzero = false;
break;
}
if (!(D == kMatFreeDim2) && d[1] < 1) {
dims_nonzero = false;
break;
}
}
if (dims_nonzero) {
bool does_match = true;
if (!(D == kMatFreeDim1)) {
does_match = does_match && (dim_[0][0] == that.at(0).n_rows);
}
if (!(D == kMatFreeDim2)) {
does_match = does_match && (dim_[0][1] == that.at(0).n_cols);
}
if (!does_match) {
std::ostringstream ss;
ss << "cannot reassign matrices of size " << dim_[0][0] << "x"
<< dim_[0][1] << " with matrices of size " << that.at(0).n_rows
<< "x" << that.at(0).n_cols;
throw std::runtime_error(ss.str());
}
}
}
for (size_t k = 0; k < this->size(); k++) {
(*this)[k] = that[k];
dim_[k] = that.dim(k);
}
return (*this);
}
template <MatrixListFreeDim D>
inline UniformMatrixList<D>& UniformMatrixList<D>::operator=(
UniformMatrixList<D>&& that) noexcept {
// // check dimensions
// // if empty, assume a default constructed object and safe to move
// if (!this->empty()) {
// if (this->size() != that.size()) {
// std::cerr << "Cannot reassign " << this->size() << " matrices with "
// << that.size() << " matrices. Skipping.\n";
// return (*this);
// }
//
// // if dimensions a not zero and do not match, skip move with error
// message. bool dims_nonzero = true; for (auto d : dim_) {
// if (!(D == kMatFreeDim1) && (d[0] < 1)) {
// dims_nonzero = false;
// break;
// }
// if (!(D == kMatFreeDim2) && (d[1] < 1)) {
// dims_nonzero = false;
// break;
// }
// }
//
// if (dims_nonzero) {
// bool does_match = true;
// if (!(D == kMatFreeDim1)) {
// does_match = does_match && (dim_[0][0] == that.at(0).n_rows);
// }
//
// if (!(D == kMatFreeDim2)) {
// does_match = does_match && (dim_[0][1] == that.at(0).n_cols);
// }
//
// if (!does_match) {
// this->at(0).print("this[0] = ");
// that.at(0).print("that[0] = ");
// std::cerr
// << "Cannot move a UniformMatrixList element of size (" <<
// that.at(0).n_rows << "," << that.at(0).n_cols << ") for an
// element of size (" << dim_[0][0] << "," << dim_[0][1] << ").
// Skipping.\n";
// return (*this);
// }
// }
// }
dim_ = that.dim_;
std::vector<Matrix>::operator=(std::move(that));
return (*this);
}
template <MatrixListFreeDim D>
UniformMatrixList<D>::UniformMatrixList(const std::vector<Matrix>& mats,
std::array<size_t, 2> dim)
: vector(mats) {
CheckDimensions(dim);
}
template <MatrixListFreeDim D>
UniformMatrixList<D>::UniformMatrixList(std::vector<Matrix>&& mats,
std::array<size_t, 2> dim)
: vector(std::move(mats)) {
CheckDimensions(dim);
};
template <MatrixListFreeDim D>
UniformMatrixList<D>::UniformMatrixList(std::initializer_list<Matrix> mats,
std::array<size_t, 2> dim)
: vector(mats) {
CheckDimensions(dim);
};
template <MatrixListFreeDim D>
UniformMatrixList<D>::UniformMatrixList(const UniformMatrixList<D>& that)
: vector(that) {
(*this) = that;
}
template <MatrixListFreeDim D>
UniformMatrixList<D>::UniformMatrixList(UniformMatrixList<D>&& that) noexcept
: vector(std::move(that)) {
for (size_t k = 0; k < this->size(); k++) {
std::array<size_t, 2> dim_k({this->at(k).n_rows, this->at(k).n_cols});
dim_.push_back(dim_k);
}
}
template <MatrixListFreeDim D>
void UniformMatrixList<D>::CheckDimensions(std::array<size_t, 2> dim) {
// change behavior based on free dim D
if ((dim[0] == 0) && !(D == kMatFreeDim1)) {
dim[0] = this->at(0).n_rows;
}
if ((dim[1] == 0) && !(D == kMatFreeDim2)) {
dim[1] = this->at(0).n_cols;
}
// make sure dimensiolaties are all uniform
bool does_match(true);
for (const Matrix& mat : *this) {
if (!(D == kMatFreeDim1)) {
does_match = does_match && (mat.n_rows == dim[0]);
}
if (!(D == kMatFreeDim2)) {
does_match = does_match && (mat.n_cols == dim[1]);
}
if (!does_match) {
throw std::runtime_error(
"Dimensionality of one or more input matrices are not uniform.");
}
}
dim_ = std::vector<std::array<size_t, 2>>(this->size(), dim);
for (size_t k = 0; k < this->size(); k++) {
dim_[k][0] = (*this)[k].n_rows;
dim_[k][1] = (*this)[k].n_cols;
}
}
} // namespace lds
#endif
Updated on 19 May 2022 at 17:16:05 Eastern Daylight Time