You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

276 lines
10 KiB

#ifndef MEDUSA_BITS_APPROXIMATIONS_MONOMIALS_HPP_
#define MEDUSA_BITS_APPROXIMATIONS_MONOMIALS_HPP_
/**
* @file
* Implementation of Monomial basis.
*/
#include "Monomials_fwd.hpp"
#include <medusa/bits/utils/assert.hpp>
#include <medusa/bits/utils/numutils.hpp>
#include <iostream>
#include "Operators_fwd.hpp"
namespace mm {
template <class vec_t>
Monomials<vec_t>::Monomials(int order) {
assert_msg(-1 <= order, "Requested monomials of negative order %d.", order);
setFromPowers(generatePowers(order, dim));
}
template <class vec_t>
std::vector<std::vector<int>> Monomials<vec_t>::generatePowers(int max_order, int dim) {
if (max_order < 0) return {};
if (dim == 0) return {{}};
std::vector<std::vector<int>> powers;
for (int i = 0; i <= max_order; ++i) {
auto other = generatePowers(max_order - i, dim-1);
for (const auto& p : other) {
powers.push_back({i});
for (int o : p) {
powers.back().push_back(o);
}
}
}
return powers;
}
template <class vec_t>
Monomials<vec_t> Monomials<vec_t>::tensorBasis(int order) {
assert_msg(-1 <= order, "Requested monomials of negative order %d.", order);
if (order == -1) return Monomials<vec_t>();
std::vector<std::vector<int>> powers;
Vec<int, dim> counter = 0;
Vec<int, dim> counts = order+1;
do {
powers.push_back(std::vector<int>(counter.begin(), counter.end()));
} while (incrementCounter(counter, counts));
return Monomials<vec_t>(powers);
}
template <class vec_t>
void Monomials<vec_t>::setFromPowers(const std::vector<std::vector<int>>& powers) {
powers_.resize(dim, powers.size());
int size = powers.size();
for (int i = 0; i < size; ++i) {
const std::vector<int>& p = powers[i];
assert_msg(p.size() == dim, "Monomial size %s does not match dimension %d", p.size(), dim);
for (int j = 0; j < dim; ++j) {
powers_(j, i) = p[j];
}
}
}
template <class vec_t>
typename vec_t::scalar_t Monomials<vec_t>::eval(
int index, const vec_t& point, const std::vector<vector_t>& /* support */) const {
assert_msg(0 <= index && index < size(), "Monomial at index %d does not exist. "
"Index must be in range [0, %d).", index, size());
scalar_t result(1.0);
for (int i = 0; i < dim; i++) {
result *= ipow(point[i], powers_(i, index));
}
return result;
}
template <class vec_t>
typename vec_t::scalar_t Monomials<vec_t>::evalOp(
int index, const vector_t& point, Lap<dim>, const std::vector<vector_t>&,
scalar_t scale) const {
scalar_t result(0.0);
for (int d = 0; d < dim; ++d) {
if (powers_(d, index) <= 1) continue;
scalar_t der2(1.0);
for (int i = 0; i < d; i++) {
der2 *= ipow(point[i], powers_(i, index));
}
der2 *= powers_(d, index) * (powers_(d, index) - 1) * ipow(point[d], powers_(d, index)-2);
for (int i = d+1; i < dim; i++) {
der2 *= ipow(point[i], powers_(i, index));
}
result += der2;
}
return result/scale/scale;
}
template <class vec_t>
typename vec_t::scalar_t Monomials<vec_t>::evalOp(
int index, const vector_t& point, Der1<dim> op, const std::vector<vector_t>&,
scalar_t scale) const {
if (powers_(op.var, index) == 0) return 0;
scalar_t result(1.0);
for (int i = 0; i < op.var; i++) {
result *= ipow(point[i], powers_(i, index));
}
result *= powers_(op.var, index)*ipow(point[op.var], powers_(op.var, index)-1);
for (int i = op.var+1; i < dim; i++) {
result *= ipow(point[i], powers_(i, index));
}
return result/scale;
}
template <class vec_t>
typename vec_t::scalar_t Monomials<vec_t>::evalOp(
int index, const vector_t& point, Der2<dim> op, const std::vector<vector_t>&,
scalar_t scale) const {
if (op.var1 == op.var2) {
if (powers_(op.var1, index) <= 1) return 0;
scalar_t result(1.0);
for (int i = 0; i < op.var1; i++) {
result *= ipow(point[i], powers_(i, index));
}
result *= powers_(op.var1, index) * (powers_(op.var1, index)-1) *
ipow(point[op.var1], powers_(op.var1, index)-2);
for (int i = op.var1+1; i < dim; i++) {
result *= ipow(point[i], powers_(i, index));
}
return result/scale/scale;
} else {
if (powers_(op.var1, index) == 0 || powers_(op.var2, index) == 0 ) return 0;
scalar_t result(1.0);
for (int i = 0; i < op.var1; i++) {
result *= ipow(point[i], powers_(i, index));
}
result *= powers_(op.var1, index)*ipow(point[op.var1], powers_(op.var1, index)-1);
for (int i = op.var1+1; i < op.var2; i++) {
result *= ipow(point[i], powers_(i, index));
}
result *= powers_(op.var2, index)*ipow(point[op.var2], powers_(op.var2, index)-1);
for (int i = op.var2+1; i < dim; i++) {
result *= ipow(point[i], powers_(i, index));
}
return result/scale/scale;
}
}
template <class vec_t>
typename vec_t::scalar_t Monomials<vec_t>::evalOp(int index, const vector_t& point,
Derivative<dim> d, const std::vector<vector_t>&, scalar_t scale) const {
assert_msg(0 <= index && index < size(), "Monomial at index %d does not exist. "
"Index must be in range [0, %d).", index, size());
int totaldeg = 0;
for (int x : d.orders) {
assert_msg(x >= 0, "Derivative of negative order %d requested.", x);
totaldeg += x;
}
scalar_t result(1.0);
for (int i = 0; i < dim; i++) {
if (d.orders[i] > powers_(i, index)) {
result = 0;
break;
}
result *= ipow(point[i], powers_(i, index) - d.orders[i]);
for (int j = powers_(i, index); j > powers_(i, index) - d.orders[i]; j--) {
result *= j;
}
}
return result / ipow(scale, totaldeg);
}
template <class vec_t>
typename vec_t::scalar_t Monomials<vec_t>::evalAt0(int index, const std::vector<vector_t>&) const {
assert_msg(0 <= index && index < size(), "Monomial at index %d does not exist. "
"Index must be in range [0, %d).", index, size());
return powers_.col(index).sum() == 0;
}
/// @cond
template <class vec_t>
template <typename operator_t>
typename vec_t::scalar_t Monomials<vec_t>::evalOp(int index, const vector_t& point, operator_t op,
const std::vector<vector_t>& support, scalar_t scale) const {
return op.apply(*this, index, point, support, scale);
}
/// @endcond
template <class vec_t>
typename vec_t::scalar_t Monomials<vec_t>::evalOpAt0(int index, const Lap<dim>&,
const std::vector<vector_t>&, scalar_t scale) const {
assert_msg(0 <= index && index < size(), "Monomial at index %d does not exist. "
"Index must be in range [0, %d).", index, size());
scalar_t result = 0;
for (int d = 0; d < vec_t::dim; ++d) {
if (powers()(d, index) != 2) continue;
scalar_t r = 2.0;
for (int i = 0; i < vec_t::dim; ++i) {
int p = powers()(i, index);
if (i != d && p != 0) { r = 0; break; }
}
result += r;
}
return result / (scale*scale);
}
template <class vec_t>
typename vec_t::scalar_t Monomials<vec_t>::evalOpAt0(int index, const Der1<dim>& der1,
const std::vector<vector_t>& , scalar_t scale) const {
assert_msg(der1.var >= 0, "Index of derived variable %d should be higher or equal to 0.",
der1.var);
assert_msg(der1.var < dim, "Index of derived variable %d should be lower"
" than the number of dimensions %d", der1.var, dim);
assert_msg(0 <= index && index < size(), "Monomial at index %d does not exist. "
"Index must be in range [0, %d).", index, size());
int d = der1.var;
scalar_t r = 0;
if (powers()(d, index) == 1) {
r = 1;
for (int i = 0; i < vec_t::dim; ++i) {
int p = powers()(i, index);
if (i != d && p != 0) r=0;
}
}
return r / scale;
}
template <class vec_t>
typename vec_t::scalar_t Monomials<vec_t>::evalOpAt0(int index, const Der2<dim>& der2,
const std::vector<vector_t>& , scalar_t scale) const {
assert_msg(der2.var1 >= 0 && der2.var2 >=0, "Index of derived variables %d and %d should"
" be both higher or equal to 0.",
der2.var1, der2.var2);
assert_msg(der2.var1 < dim && der2.var2 < dim , "Indexes of derived variables %d and %d should"
" both be lower than the number of dimensions %d", der2.var1, der2.var2, dim);
assert_msg(0 <= index && index < size(), "Monomial at index %d does not exist. "
"Index must be in range [0, %d).", index, size());
int d1 = der2.var1;
int d2 = der2.var2;
scalar_t r = 0;
if (d1 == d2) {
if (powers()(d1, index) == 2) {
r = 2;
for (int i = 0; i < vec_t::dim; ++i) {
int p = powers()(i, index);
if (i != d1 && p != 0) r = 0;
}
}
} else {
if (powers()(d1, index) == 1 && powers()(d2, index) == 1) {
r = 1;
for (int i = 0; i < vec_t::dim; ++i) {
int p = powers()(i, index);
if (i != d1 && i != d2 && p != 0) r = 0;
}
}
}
return r / (scale * scale);
}
template <class vec_t>
typename vec_t::scalar_t Monomials<vec_t>::evalOpAt0(int index, const Derivative<dim>& der,
const std::vector<vector_t>& support, scalar_t scale) const {
return evalOp(index, 0.0, der, support, scale);
}
/// Output basic info about given Monomial basis.
template <class V>
std::ostream& operator<<(std::ostream& os, const Monomials<V>& m) {
return os << "Monomials " << m.dim << "D: "
<< m.powers_.transpose() << ", number of functions = " << m.size();
}
} // namespace mm
#endif // MEDUSA_BITS_APPROXIMATIONS_MONOMIALS_HPP_