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.
Conception/drake-master/common/polynomial.cc

879 lines
26 KiB

#include "drake/common/polynomial.h"
#include <algorithm>
#include <cstring>
#include <limits>
#include <numeric>
#include <set>
#include <stdexcept>
#include <utility>
#include "drake/common/drake_assert.h"
#include "drake/common/drake_throw.h"
using Eigen::Dynamic;
using Eigen::Matrix;
using std::accumulate;
using std::pair;
using std::runtime_error;
using std::string;
using std::vector;
namespace drake {
template <typename T>
bool Polynomial<T>::Monomial::HasSameExponents(
const Monomial& other) const {
if (terms.size() != other.terms.size()) return false;
for (typename vector<Term>::const_iterator iter = terms.begin();
iter != terms.end(); iter++) {
typename vector<Term>::const_iterator match =
find(other.terms.begin(), other.terms.end(), *iter);
if (match == other.terms.end()) return false;
}
return true;
}
template <typename T>
bool Polynomial<T>::Monomial::HasVariable(const VarType& var) const {
for (const auto& t : terms) {
if (t.var == var) {
return true;
}
}
return false;
}
template <typename T>
Polynomial<T>::Polynomial(const T& scalar) {
Monomial m;
m.coefficient = scalar;
monomials_.push_back(m);
is_univariate_ = true;
}
template <typename T>
Polynomial<T>::Polynomial(const T coefficient,
const vector<Term>& terms) {
Monomial m;
m.coefficient = coefficient;
m.terms = terms;
is_univariate_ = true;
for (int i = static_cast<int>(m.terms.size()) - 1; i >= 0; i--) {
if ((i > 0) && (m.terms[i].var != m.terms[0].var)) {
is_univariate_ = false;
}
for (int j = 0; j < (i - 1); j++) { // merge any duplicate vars
if (m.terms[i].var == m.terms[j].var) {
m.terms[j].power += m.terms[i].power;
m.terms.erase(m.terms.begin() + i);
break;
}
}
}
monomials_.push_back(m);
}
template <typename T>
Polynomial<T>::Polynomial(
typename vector<
typename Polynomial<T>::Monomial>::const_iterator start,
typename vector<typename Polynomial<T>::Monomial>::
const_iterator finish) {
is_univariate_ = true;
for (
typename vector<
typename Polynomial<T>::Monomial>::const_iterator iter =
start;
iter != finish; iter++)
monomials_.push_back(*iter);
MakeMonomialsUnique();
}
template <typename T>
Polynomial<T>::Polynomial(const string& varname, const unsigned int num) {
Monomial m;
m.coefficient = T{1};
Term t;
t.var = VariableNameToId(varname, num);
t.power = 1;
m.terms.push_back(t);
monomials_.push_back(m);
is_univariate_ = true;
}
template <typename T>
Polynomial<T>::Polynomial(const T& coeff,
const VarType& v) {
Monomial m;
m.coefficient = coeff;
Term t;
t.var = v;
t.power = 1;
m.terms.push_back(t);
monomials_.push_back(m);
is_univariate_ = true;
}
template <typename T>
Polynomial<T>::Polynomial(const WithCoefficients& coefficients) {
const Eigen::Ref<const VectorX<T>>& coeffs = coefficients.value;
const VarType v = VariableNameToId("t");
monomials_.reserve(coeffs.size());
for (int i = 0; i < coeffs.size(); ++i) {
Monomial m;
m.coefficient = coeffs(i);
if (i > 0) {
m.terms.reserve(1);
m.terms.push_back(Term{v, i});
}
monomials_.push_back(std::move(m));
}
is_univariate_ = true;
}
template <typename T>
int Polynomial<T>::GetNumberOfCoefficients() const {
return static_cast<int>(monomials_.size());
}
template <typename T>
int Polynomial<T>::Monomial::GetDegree() const {
if (terms.empty()) return 0;
int degree = terms[0].power;
for (size_t i = 1; i < terms.size(); i++) degree *= terms[i].power;
return degree;
}
template <typename T>
int Polynomial<T>::Monomial::GetDegreeOf(VarType v) const {
for (const Term& term : terms) {
if (term.var == v) {
return term.power;
}
}
return 0;
}
template <typename T>
typename Polynomial<T>::Monomial
Polynomial<T>::Monomial::Factor(const Monomial& divisor) const {
Monomial error, result;
error.coefficient = 0;
result.coefficient = coefficient / divisor.coefficient;
for (const Term& term : terms) {
const PowerType divisor_power = divisor.GetDegreeOf(term.var);
if (term.power < divisor_power) { return error; }
Term new_term;
new_term.var = term.var;
new_term.power = term.power - divisor_power;
if (new_term.power > 0) {
result.terms.push_back(new_term);
}
}
for (const Term& divisor_term : divisor.terms) {
if (!GetDegreeOf(divisor_term.var)) { return error; }
}
return result;
}
template <typename T>
int Polynomial<T>::GetDegree() const {
int max_degree = 0;
for (typename vector<Monomial>::const_iterator iter = monomials_.begin();
iter != monomials_.end(); iter++) {
int monomial_degree = iter->GetDegree();
if (monomial_degree > max_degree) max_degree = monomial_degree;
}
return max_degree;
}
template <typename T>
bool Polynomial<T>::IsAffine() const {
for (const auto& monomial : monomials_) {
if ((monomial.terms.size() > 1) || (monomial.GetDegree() > 1)) {
return false;
}
}
return true;
}
template <typename T>
typename Polynomial<T>::VarType
Polynomial<T>::GetSimpleVariable() const {
if (monomials_.size() != 1) return 0;
if (monomials_[0].terms.size() != 1) return 0;
if (monomials_[0].terms[0].power != 1) return 0;
return monomials_[0].terms[0].var;
}
template <typename T>
const std::vector<typename Polynomial<T>::Monomial>&
Polynomial<T>::GetMonomials() const {
return monomials_;
}
template <typename T>
VectorX<T> Polynomial<T>::GetCoefficients() const {
if (!is_univariate_) {
throw runtime_error(
"GetCoefficients is only defined for univariate polynomials");
}
VectorX<T> result = VectorX<T>::Zero(GetDegree() + 1);
for (const auto& monomial : monomials_) {
const int power = monomial.terms.empty() ? 0 : monomial.terms[0].power;
result[power] = monomial.coefficient;
}
return result;
}
template <typename T>
std::set<typename Polynomial<T>::VarType>
Polynomial<T>::GetVariables() const {
std::set<Polynomial<T>::VarType> vars;
for (const Monomial& monomial : monomials_) {
for (const Term& term : monomial.terms) {
vars.insert(term.var);
}
}
return vars;
}
template <typename T>
Polynomial<T> Polynomial<T>::EvaluatePartial(
const std::map<VarType, T>& var_values) const {
using std::pow;
std::vector<Monomial> new_monomials;
for (const Monomial& monomial : monomials_) {
T new_coefficient = monomial.coefficient;
std::vector<Term> new_terms;
for (const Term& term : monomial.terms) {
if (var_values.count(term.var)) {
new_coefficient *= pow(var_values.at(term.var), term.power);
} else {
new_terms.push_back(term);
}
}
Monomial new_monomial = {new_coefficient, new_terms};
new_monomials.push_back(new_monomial);
}
return Polynomial(new_monomials.begin(), new_monomials.end());
}
template <typename T>
void Polynomial<T>::Subs(const VarType& orig,
const VarType& replacement) {
for (typename vector<Monomial>::iterator iter = monomials_.begin();
iter != monomials_.end(); iter++) {
for (typename vector<Term>::iterator t = iter->terms.begin();
t != iter->terms.end(); t++) {
if (t->var == orig) t->var = replacement;
}
}
}
template <typename T>
Polynomial<T> Polynomial<T>::Substitute(
const VarType& orig, const Polynomial<T>& replacement) const {
// TODO(russt): Consider making this more efficient by updating coefficients
// in place instead of relying on the more general polynomial operators.
Polynomial<T> p;
for (const auto& source_monomial : monomials_) {
if (source_monomial.HasVariable(orig)) {
Polynomial<T> m = source_monomial.coefficient;
for (const Term& t : source_monomial.terms) {
if (t.var == orig) {
m *= pow(replacement, t.power);
} else {
m *= Polynomial(1.0, {t});
}
p += m;
}
} else {
// Then this monomial is not changed; add it in directly.
p += Polynomial(source_monomial.coefficient, source_monomial.terms);
}
}
return p;
} // namespace drake
template <typename T>
Polynomial<T> Polynomial<T>::Derivative(
int derivative_order) const {
DRAKE_DEMAND(derivative_order >= 0);
if (!is_univariate_)
throw runtime_error(
"Derivative is only defined for univariate polynomials");
if (derivative_order == 0) {
return *this;
}
Polynomial<T> ret;
for (typename vector<Monomial>::const_iterator iter = monomials_.begin();
iter != monomials_.end(); iter++) {
if (!iter->terms.empty() && (
iter->terms[0].power >= static_cast<PowerType>(derivative_order))) {
Monomial m = *iter;
for (int k = 0; k < derivative_order;
k++) { // take the remaining derivatives
m.coefficient = m.coefficient * m.terms[0].power;
m.terms[0].power -= 1;
}
if (m.terms[0].power < 1) m.terms.erase(m.terms.begin());
ret.monomials_.push_back(m);
}
}
ret.is_univariate_ = true;
return ret;
}
template <typename T>
Polynomial<T> Polynomial<T>::Integral(
const T& integration_constant) const {
if (!is_univariate_)
throw runtime_error(
"Integral is only defined for univariate polynomials");
Polynomial<T> ret = *this;
for (typename vector<Monomial>::iterator iter = ret.monomials_.begin();
iter != ret.monomials_.end(); iter++) {
if (iter->terms.empty()) {
Term t;
t.var = 0;
for (typename vector<Monomial>::iterator iterB = ret.monomials_.begin();
iterB != ret.monomials_.end(); iterB++) {
if (!iterB->terms.empty()) {
t.var = iterB->terms[0].var;
break;
}
}
if (t.var < 1) throw runtime_error("don't know the variable name");
t.power = 1;
iter->terms.push_back(t);
} else {
iter->coefficient /= static_cast<RealScalar>(iter->terms[0].power + 1);
iter->terms[0].power += PowerType{1};
}
}
Monomial m;
m.coefficient = integration_constant;
ret.is_univariate_ = true;
ret.monomials_.push_back(m);
return ret;
}
template <typename T>
bool Polynomial<T>::operator==(
const Polynomial<T>& other) const {
// Comparison of unsorted vectors is faster copying them into std::set
// btrees rather than using std::is_permutation().
// TODO(#2216) switch from multiset to set for further performance gains.
const std::multiset<Monomial> this_monomials(monomials_.begin(),
monomials_.end());
const std::multiset<Monomial> other_monomials(other.monomials_.begin(),
other.monomials_.end());
return this_monomials == other_monomials;
}
template <typename T>
Polynomial<T>& Polynomial<T>::operator+=(
const Polynomial<T>& other) {
for (const auto& iter : other.monomials_) {
monomials_.push_back(iter);
}
MakeMonomialsUnique(); // also sets is_univariate false if necessary
return *this;
}
template <typename T>
Polynomial<T>& Polynomial<T>::operator-=(
const Polynomial<T>& other) {
for (const auto& iter : other.monomials_) {
monomials_.push_back(iter);
monomials_.back().coefficient *= T{-1};
}
MakeMonomialsUnique(); // also sets is_univariate false if necessary
return *this;
}
template <typename T>
Polynomial<T>& Polynomial<T>::operator*=(
const Polynomial<T>& other) {
vector<Monomial> new_monomials;
for (const auto& iter : monomials_) {
for (const auto& other_iter : other.monomials_) {
Monomial m;
m.coefficient = iter.coefficient * other_iter.coefficient;
m.terms = iter.terms;
for (size_t i = 0; i < other_iter.terms.size(); i++) {
bool new_var = true;
for (size_t j = 0; j < m.terms.size(); j++) {
if (m.terms[j].var == other_iter.terms[i].var) {
m.terms[j].power += other_iter.terms[i].power;
new_var = false;
break;
}
}
if (new_var) {
m.terms.push_back(other_iter.terms[i]);
}
}
new_monomials.push_back(m);
}
}
monomials_ = new_monomials;
MakeMonomialsUnique(); // also sets is_univariate false if necessary
return *this;
}
template <typename T>
Polynomial<T>& Polynomial<T>::operator+=(
const T& scalar) {
// add to the constant monomial if I have one
for (typename vector<Monomial>::iterator iter = monomials_.begin();
iter != monomials_.end(); iter++) {
if (iter->terms.empty()) {
iter->coefficient += scalar;
return *this;
}
}
// otherwise create the constant monomial
Monomial m;
m.coefficient = scalar;
monomials_.push_back(m);
return *this;
}
template <typename T>
Polynomial<T>& Polynomial<T>::operator-=(
const T& scalar) {
// add to the constant monomial if I have one
for (typename vector<Monomial>::iterator iter = monomials_.begin();
iter != monomials_.end(); iter++) {
if (iter->terms.empty()) {
iter->coefficient -= scalar;
return *this;
}
}
// otherwise create the constant monomial
Monomial m;
m.coefficient = -scalar;
monomials_.push_back(m);
return *this;
}
template <typename T>
Polynomial<T>& Polynomial<T>::operator*=(
const T& scalar) {
for (typename vector<Monomial>::iterator iter = monomials_.begin();
iter != monomials_.end(); iter++) {
iter->coefficient *= scalar;
}
return *this;
}
template <typename T>
Polynomial<T>& Polynomial<T>::operator/=(
const T& scalar) {
for (typename vector<Monomial>::iterator iter = monomials_.begin();
iter != monomials_.end(); iter++) {
iter->coefficient /= scalar;
}
return *this;
}
template <typename T>
const Polynomial<T> Polynomial<T>::operator+(
const Polynomial& other) const {
Polynomial<T> ret = *this;
ret += other;
return ret;
}
template <typename T>
const Polynomial<T> Polynomial<T>::operator-(
const Polynomial& other) const {
Polynomial<T> ret = *this;
ret -= other;
return ret;
}
template <typename T>
const Polynomial<T> Polynomial<T>::operator-()
const {
Polynomial<T> ret = *this;
for (typename vector<Monomial>::iterator iter = ret.monomials_.begin();
iter != ret.monomials_.end(); iter++) {
iter->coefficient = -iter->coefficient;
}
return ret;
}
template <typename T>
const Polynomial<T> Polynomial<T>::operator*(
const Polynomial<T>& other) const {
Polynomial<T> ret = *this;
ret *= other;
return ret;
}
template <typename T>
const Polynomial<T> Polynomial<T>::operator/(
const T& scalar) const {
Polynomial<T> ret = *this;
ret /= scalar;
return ret;
}
template <typename T>
typename Polynomial<T>::RootsType Polynomial<T>::Roots() const {
if (!is_univariate_)
throw runtime_error("Roots is only defined for univariate polynomials");
// RootsType (std::complex<T>) does not currently work for AutoDiffXd nor for
// Expression, which leaves only double. We could, in principle, try to
// support more types here.
if constexpr (std::is_same_v<T, double>) {
auto coefficients = GetCoefficients();
// need to handle degree 0 and 1 explicitly because Eigen's polynomial
// solver doesn't work for these
int degree = static_cast<int>(coefficients.size()) - 1;
switch (degree) {
case 0:
return Polynomial<T>::RootsType(degree);
case 1: {
Polynomial<T>::RootsType ret(degree);
ret[0] = -coefficients[0] / coefficients[1];
return ret;
}
default: {
Eigen::PolynomialSolver<RealScalar, Eigen::Dynamic> solver;
solver.compute(coefficients);
return solver.roots();
}
}
} else {
throw std::runtime_error(
"Polynomial<T>::Roots() is only supports T=double.");
}
}
template <typename T>
boolean<T> Polynomial<T>::CoefficientsAlmostEqual(
const Polynomial<T>& other, const Polynomial<T>::RealScalar& tol,
const ToleranceType& tol_type) const {
using std::abs;
using std::min;
std::vector<bool> monomial_has_match(monomials_.size(), false);
boolean<T> comparison{true};
for (const auto& m : other.GetMonomials()) {
bool found_matching_term = false;
for (size_t i = 0; i < monomials_.size(); i++) {
if (monomial_has_match[i]) continue;
if (m.terms == monomials_[i].terms) {
found_matching_term = true;
if (tol_type == ToleranceType::kAbsolute) {
comparison = comparison &&
abs(m.coefficient - monomials_[i].coefficient) <= tol;
} else {
comparison =
comparison &&
abs(m.coefficient - monomials_[i].coefficient) <=
tol * min(abs(m.coefficient), abs(monomials_[i].coefficient));
}
monomial_has_match[i] = true;
break;
}
}
if (!found_matching_term) {
if (tol_type == ToleranceType::kAbsolute) {
// then I can still succeed, if my coefficient is close to zero.
comparison = comparison && abs(m.coefficient) <= tol;
} else {
return boolean<T>{false};
}
}
}
// Finally, check any monomials in this that did not have a match in other.
for (size_t i = 0; i < monomials_.size(); i++) {
if (monomial_has_match[i]) continue;
if (tol_type == ToleranceType::kAbsolute) {
comparison = comparison && abs(monomials_[i].coefficient) <= tol;
} else {
return boolean<T>{false};
}
}
return comparison;
}
constexpr char kNameChars[] = "@#_.abcdefghijklmnopqrstuvwxyz";
const unsigned int kNumNameChars = sizeof(kNameChars) - 1;
const unsigned int kNameLength = 4;
const unsigned int kMaxNamePart = 923521; // (kNumNameChars+1)^kNameLength;
template <typename T>
bool Polynomial<T>::IsValidVariableName(const string name) {
size_t len = name.length();
if (len < 1) return false;
for (size_t i = 0; i < len; i++)
if (!strchr(kNameChars, name[i])) return false;
return true;
}
template <typename T>
typename Polynomial<T>::VarType
Polynomial<T>::VariableNameToId(const string name,
const unsigned int m) {
DRAKE_THROW_UNLESS(IsValidVariableName(name));
unsigned int multiplier = 1;
VarType name_part = 0;
for (int i = static_cast<int>(name.size()) - 1; i >= 0; i--) {
const char* const character_match = strchr(kNameChars, name[i]);
DRAKE_ASSERT(character_match != nullptr);
VarType offset = static_cast<VarType>(character_match - kNameChars);
name_part += (offset + 1) * multiplier;
multiplier *= kNumNameChars + 1;
}
if (name_part > kMaxNamePart) {
throw runtime_error("name " + name +
" (" + std::to_string(name_part) +
") exceeds max allowed");
}
const VarType maxId = std::numeric_limits<VarType>::max() / 2 / kMaxNamePart;
if (m > maxId) throw runtime_error("name exceeds max ID");
if (m < 1) throw runtime_error("m must be >0");
return static_cast<VarType>(2) * (name_part + kMaxNamePart * (m - 1));
}
template <typename T>
string Polynomial<T>::IdToVariableName(const VarType id) {
VarType name_part = (id / 2) % kMaxNamePart; // id/2 to be compatible w/
// msspoly, even though I'm not
// doing the trig support here
unsigned int m = id / 2 / kMaxNamePart;
unsigned int multiplier = static_cast<unsigned int>(
std::pow(static_cast<double>(kNumNameChars + 1),
static_cast<int>(kNameLength) - 1));
char name[kNameLength + 1];
int j = 0;
for (int i = 0; i < static_cast<int>(kNameLength); i++) {
unsigned int name_ind = (name_part / multiplier) % (kNumNameChars + 1);
if (name_ind > 0) name[j++] = kNameChars[name_ind - 1];
multiplier /= kNumNameChars + 1;
}
if (j == 0) name[j++] = kNameChars[0];
name[j] = '\0';
return string(name) + std::to_string((m + 1));
}
template <typename T>
void Polynomial<T>::MakeMonomialsUnique(void) {
VarType unique_var = 0; // also update the univariate flag
for (int i = static_cast<int>(monomials_.size()) - 1; i >= 0; --i) {
if (monomials_[i].coefficient == 0) {
monomials_.erase(monomials_.begin() + i);
continue;
}
Monomial& mi = monomials_[i];
if (!mi.terms.empty()) {
if (mi.terms.size() > 1) is_univariate_ = false;
if (mi.terms[0].var != unique_var) {
if (unique_var > 0) {
is_univariate_ = false;
} else {
unique_var = mi.terms[0].var;
}
}
}
for (int j = 0; j <= (i - 1); j++) {
Monomial& mj = monomials_[j];
if (mi.HasSameExponents(mj)) {
// it's a match, so delete monomial i
monomials_[j].coefficient += monomials_[i].coefficient;
monomials_.erase(monomials_.begin() + i);
break;
}
}
}
}
namespace {
using symbolic::Expression;
// Visitor class to implement FromExpression.
template <typename T>
class FromExpressionVisitor {
public:
Polynomial<T> Visit(const Expression& e) {
return drake::symbolic::VisitExpression<Polynomial<T>>(this, e);
}
private:
static Polynomial<T> VisitAddition(const Expression& e) {
const auto constant = get_constant_in_addition(e);
const auto& expr_to_coeff_map = get_expr_to_coeff_map_in_addition(e);
return accumulate(
expr_to_coeff_map.begin(), expr_to_coeff_map.end(),
Polynomial<T>{constant},
[](const Polynomial<T>& polynomial,
const pair<const Expression, double>& p) {
return polynomial + Polynomial<T>::FromExpression(p.first) * p.second;
});
}
static Polynomial<T> VisitMultiplication(const Expression& e) {
const auto constant = drake::symbolic::get_constant_in_multiplication(e);
const auto& base_to_exponent_map =
drake::symbolic::get_base_to_exponent_map_in_multiplication(e);
return accumulate(
base_to_exponent_map.begin(), base_to_exponent_map.end(),
Polynomial<T>{constant},
[](const Polynomial<T>& polynomial,
const pair<const Expression, Expression>& p) {
const Expression& base{p.first};
const Expression& exponent{p.second};
DRAKE_ASSERT(base.is_polynomial());
DRAKE_ASSERT(is_constant(exponent));
return polynomial *
pow(Polynomial<T>::FromExpression(base),
static_cast<int>(get_constant_value(exponent)));
});
}
static Polynomial<T> VisitDivision(const Expression& e) {
DRAKE_ASSERT(e.is_polynomial());
const auto& first_arg{get_first_argument(e)};
const auto& second_arg{get_second_argument(e)};
DRAKE_ASSERT(is_constant(second_arg));
return Polynomial<T>::FromExpression(first_arg) /
get_constant_value(second_arg);
}
static Polynomial<T> VisitVariable(const Expression& e) {
return Polynomial<T>{1.0, static_cast<Polynomial<double>::VarType>(
get_variable(e).get_id())};
}
static Polynomial<T> VisitConstant(const Expression& e) {
return Polynomial<T>{get_constant_value(e)};
}
static Polynomial<T> VisitLog(const Expression&) {
throw runtime_error("Log expression is not polynomial-convertible.");
}
static Polynomial<T> VisitPow(const Expression& e) {
DRAKE_ASSERT(e.is_polynomial());
const int exponent{
static_cast<int>(get_constant_value(get_second_argument(e)))};
return pow(Polynomial<T>::FromExpression(get_first_argument(e)), exponent);
}
static Polynomial<T> VisitAbs(const Expression&) {
throw runtime_error("Abs expression is not polynomial-convertible.");
}
static Polynomial<T> VisitExp(const Expression&) {
throw runtime_error("Exp expression is not polynomial-convertible.");
}
static Polynomial<T> VisitSqrt(const Expression&) {
throw runtime_error("Sqrt expression is not polynomial-convertible.");
}
static Polynomial<T> VisitSin(const Expression&) {
throw runtime_error("Sin expression is not polynomial-convertible.");
}
static Polynomial<T> VisitCos(const Expression&) {
throw runtime_error("Cos expression is not polynomial-convertible.");
}
static Polynomial<T> VisitTan(const Expression&) {
throw runtime_error("Tan expression is not polynomial-convertible.");
}
static Polynomial<T> VisitAsin(const Expression&) {
throw runtime_error("Asin expression is not polynomial-convertible.");
}
static Polynomial<T> VisitAcos(const Expression&) {
throw runtime_error("Acos expression is not polynomial-convertible.");
}
static Polynomial<T> VisitAtan(const Expression&) {
throw runtime_error("Atan expression is not polynomial-convertible.");
}
static Polynomial<T> VisitAtan2(const Expression&) {
throw runtime_error("Atan2 expression is not polynomial-convertible.");
}
static Polynomial<T> VisitSinh(const Expression&) {
throw runtime_error("Sinh expression is not polynomial-convertible.");
}
static Polynomial<T> VisitCosh(const Expression&) {
throw runtime_error("Cosh expression is not polynomial-convertible.");
}
static Polynomial<T> VisitTanh(const Expression&) {
throw runtime_error("Tanh expression is not polynomial-convertible.");
}
static Polynomial<T> VisitMin(const Expression&) {
throw runtime_error("Min expression is not polynomial-convertible.");
}
static Polynomial<T> VisitMax(const Expression&) {
throw runtime_error("Max expression is not polynomial-convertible.");
}
static Polynomial<T> VisitCeil(const Expression&) {
throw runtime_error("Ceil expression is not polynomial-convertible.");
}
static Polynomial<T> VisitFloor(const Expression&) {
throw runtime_error("Floor expression is not polynomial-convertible.");
}
static Polynomial<T> VisitIfThenElse(const Expression&) {
throw runtime_error("IfThenElse expression is not polynomial-convertible.");
}
static Polynomial<T> VisitUninterpretedFunction(const Expression&) {
throw runtime_error(
"Uninterpreted-function expression is not polynomial-convertible.");
}
// Makes VisitExpression a friend of this class so that VisitExpression can
// use its private methods.
friend Polynomial<T> drake::symbolic::VisitExpression<Polynomial<T>>(
FromExpressionVisitor*, const Expression&);
};
} // namespace
template <typename T>
Polynomial<T> Polynomial<T>::FromExpression(const Expression& e) {
return FromExpressionVisitor<T>{}.Visit(e);
}
// template class Polynomial<std::complex<double>>;
// doesn't work yet because the roots solver can't handle it
} // namespace drake
DRAKE_DEFINE_CLASS_TEMPLATE_INSTANTIATIONS_ON_DEFAULT_SCALARS(
class drake::Polynomial)