diff --git a/drake/common/symbolic_expression.cc b/drake/common/symbolic_expression.cc index a157c545a3b2..4f1fab31bbb8 100644 --- a/drake/common/symbolic_expression.cc +++ b/drake/common/symbolic_expression.cc @@ -153,6 +153,18 @@ Polynomial Expression::ToPolynomial() const { return ptr_->ToPolynomial(); } +int Expression::Degree(const Variables& vars) const { + DRAKE_ASSERT(ptr_ != nullptr); + DRAKE_DEMAND(is_polynomial()); + return ptr_->Degree(vars); +} + +int Expression::Degree() const { + DRAKE_ASSERT(ptr_ != nullptr); + DRAKE_DEMAND(is_polynomial()); + return ptr_->Degree(GetVariables()); +} + double Expression::Evaluate(const Environment& env) const { DRAKE_ASSERT(ptr_ != nullptr); return ptr_->Evaluate(env); diff --git a/drake/common/symbolic_expression.h b/drake/common/symbolic_expression.h index bb5334e174f1..81707e4288c8 100644 --- a/drake/common/symbolic_expression.h +++ b/drake/common/symbolic_expression.h @@ -176,6 +176,28 @@ class Expression { */ Polynomial ToPolynomial() const; + /** + * Returns the total degrees of the polynomial w.r.t the variables in + * @p vars. For example, the total degree of + * e = x^2*y + 2 * x*y*z^3 + x * z^2 + * w.r.t (x, y) is 3 (from x^2 * y) + * w.r.t (x, z) is 4 (from x*y*z^3) + * w.r.t (z) is 3 (from x*y*z^3) + * Throws a runtime error if is_polynomial() is false. + * @param vars A set of variables. + * @return The total degree. + */ + int Degree(const Variables& vars) const; + + /** + * Returns the total degress of all the variables in the polynomial. + * For example, the total degree of + * x^2*y + 2*x*y*z^3 + x*z^2 + * is 5, from x*y*z^3 + * Throws a runtime error is is_polynomial() is false. + * @return The total degree. + */ + int Degree() const; /** Evaluates under a given environment (by default, an empty environment). * @throws std::runtime_error if NaN is detected during evaluation. */ diff --git a/drake/common/symbolic_expression_cell.cc b/drake/common/symbolic_expression_cell.cc index 6f35f0a0cf4e..ff473a7b222d 100644 --- a/drake/common/symbolic_expression_cell.cc +++ b/drake/common/symbolic_expression_cell.cc @@ -211,6 +211,10 @@ Polynomial ExpressionVar::ToPolynomial() const { return Polynomial(1.0, var_.get_id()); } +int ExpressionVar::Degree(const Variables &vars) const { + return vars.include(var_) ? 1 : 0; +} + double ExpressionVar::Evaluate(const Environment& env) const { Environment::const_iterator const it{env.find(var_)}; if (it != env.cend()) { @@ -260,6 +264,10 @@ Polynomial ExpressionConstant::ToPolynomial() const { return Polynomial(v_); } +int ExpressionConstant::Degree(const Variables& vars) const { + return 0; +} + double ExpressionConstant::Evaluate(const Environment& env) const { DRAKE_DEMAND(!std::isnan(v_)); return v_; @@ -301,6 +309,10 @@ Polynomial ExpressionNaN::ToPolynomial() const { throw runtime_error("NaN is detected while converting to Polynomial."); } +int ExpressionNaN::Degree(const Variables& vars) const { + throw runtime_error("NaN is detected while enquiring polynomial degree."); +} + double ExpressionNaN::Evaluate(const Environment& env) const { throw runtime_error("NaN is detected during Symbolic computation."); } @@ -387,6 +399,14 @@ Polynomial ExpressionAdd::ToPolynomial() const { }); } +int ExpressionAdd::Degree(const Variables& vars) const { + int degree = 0; + for (const auto& p : expr_to_coeff_map_) { + degree = std::max(degree, p.first.Degree(vars)); + } + return degree; +} + double ExpressionAdd::Evaluate(const Environment& env) const { return accumulate( expr_to_coeff_map_.begin(), expr_to_coeff_map_.end(), constant_, @@ -622,6 +642,18 @@ Polynomial ExpressionMul::ToPolynomial() const { }); } +int ExpressionMul::Degree(const Variables &vars) const { + // The precondition is is_polynomial() == True. + return accumulate( + base_to_exponent_map_.begin(), base_to_exponent_map_.end(), 0, + [vars](const int& degree, const pair& p) { + const Expression& base{p.first}; + const Expression& expnt{p.second}; + return degree + + base.Degree(vars) * static_cast(get_constant_value(expnt)); + }); +} + double ExpressionMul::Evaluate(const Environment& env) const { return accumulate( base_to_exponent_map_.begin(), base_to_exponent_map_.end(), constant_, @@ -780,6 +812,11 @@ Polynomial ExpressionDiv::ToPolynomial() const { get_constant_value(get_second_argument()); } +int ExpressionDiv::Degree(const Variables& vars) const { + // The precondition is is_polynomial() == True. + return get_first_argument().Degree(vars) - get_second_argument().Degree(vars); +} + Expression ExpressionDiv::Substitute(const Substitution& s) const { return get_first_argument().Substitute(s) / get_second_argument().Substitute(s); @@ -816,6 +853,10 @@ Polynomial ExpressionLog::ToPolynomial() const { throw runtime_error("Log expression is not polynomial-convertible."); } +int ExpressionLog::Degree(const Variables &vars) const { + throw runtime_error("Log expression does not have a polynomial degree."); +} + Expression ExpressionLog::Substitute(const Substitution& s) const { return log(get_argument().Substitute(s)); } @@ -836,6 +877,10 @@ Polynomial ExpressionAbs::ToPolynomial() const { throw runtime_error("Abs expression is not polynomial-convertible."); } +int ExpressionAbs::Degree(const Variables& vars) const { + throw runtime_error("Abs expression does not have a polynomial degree."); +} + Expression ExpressionAbs::Substitute(const Substitution& s) const { return abs(get_argument().Substitute(s)); } @@ -853,6 +898,10 @@ Polynomial ExpressionExp::ToPolynomial() const { throw runtime_error("Exp expression is not polynomial-convertible."); } +int ExpressionExp::Degree(const Variables &vars) const { + throw runtime_error("Exp expression does not have a polynomial degree."); +} + Expression ExpressionExp::Substitute(const Substitution& s) const { return exp(get_argument().Substitute(s)); } @@ -879,6 +928,10 @@ Polynomial ExpressionSqrt::ToPolynomial() const { throw runtime_error("Sqrt expression is not polynomial-convertible."); } +int ExpressionSqrt::Degree(const Variables& vars) const { + throw runtime_error("Sqrt expression does not have a polynomial degree."); +} + Expression ExpressionSqrt::Substitute(const Substitution& s) const { return sqrt(get_argument().Substitute(s)); } @@ -914,6 +967,13 @@ Polynomial ExpressionPow::ToPolynomial() const { return pow(get_first_argument().ToPolynomial(), exponent); } +int ExpressionPow::Degree(const Variables &vars) const { + // As a precondition, this expression `is_polynomial`, so the exponent is an + // integer and this cast does not change its value. + const int expnt{static_cast(get_constant_value(get_second_argument()))}; + return get_first_argument().Degree(vars) * expnt; +} + Expression ExpressionPow::Substitute(const Substitution& s) const { return pow(get_first_argument().Substitute(s), get_second_argument().Substitute(s)); @@ -936,6 +996,10 @@ Polynomial ExpressionSin::ToPolynomial() const { throw runtime_error("Sin expression is not polynomial-convertible."); } +int ExpressionSin::Degree(const Variables& vars) const { + throw runtime_error("Sin expression does not have a polynomial degree."); +} + Expression ExpressionSin::Substitute(const Substitution& s) const { return sin(get_argument().Substitute(s)); } @@ -953,6 +1017,10 @@ Polynomial ExpressionCos::ToPolynomial() const { throw runtime_error("Cos expression is not polynomial-convertible."); } +int ExpressionCos::Degree(const Variables &vars) const { + throw runtime_error("Cos expression does not have a polynomial degree."); +} + Expression ExpressionCos::Substitute(const Substitution& s) const { return cos(get_argument().Substitute(s)); } @@ -970,6 +1038,10 @@ Polynomial ExpressionTan::ToPolynomial() const { throw runtime_error("Tan expression is not polynomial-convertible."); } +int ExpressionTan::Degree(const Variables& vars) const { + throw runtime_error("Tan expression does not have a polynomial degree."); +} + Expression ExpressionTan::Substitute(const Substitution& s) const { return tan(get_argument().Substitute(s)); } @@ -996,6 +1068,10 @@ Polynomial ExpressionAsin::ToPolynomial() const { throw runtime_error("Asin expression is not polynomial-convertible."); } +int ExpressionAsin::Degree(const Variables &vars) const { + throw runtime_error("Asin expression does not have a polynomial degree."); +} + Expression ExpressionAsin::Substitute(const Substitution& s) const { return asin(get_argument().Substitute(s)); } @@ -1025,6 +1101,10 @@ Polynomial ExpressionAcos::ToPolynomial() const { throw runtime_error("Acos expression is not polynomial-convertible."); } +int ExpressionAcos::Degree(const Variables &vars) const { + throw runtime_error("Acos expression does not have a polynomial degree."); +} + Expression ExpressionAcos::Substitute(const Substitution& s) const { return acos(get_argument().Substitute(s)); } @@ -1045,6 +1125,10 @@ Polynomial ExpressionAtan::ToPolynomial() const { throw runtime_error("Atan expression is not polynomial-convertible."); } +int ExpressionAtan::Degree(const Variables &vars) const { + throw runtime_error("Atan expression does not have a polynomial degree."); +} + Expression ExpressionAtan::Substitute(const Substitution& s) const { return atan(get_argument().Substitute(s)); } @@ -1062,6 +1146,10 @@ Polynomial ExpressionAtan2::ToPolynomial() const { throw runtime_error("Atan2 expression is not polynomial-convertible."); } +int ExpressionAtan2::Degree(const Variables &vars) const { + throw runtime_error("Atan2 expression does not have a polynomial degree."); +} + Expression ExpressionAtan2::Substitute(const Substitution& s) const { return atan2(get_first_argument().Substitute(s), get_second_argument().Substitute(s)); @@ -1083,6 +1171,10 @@ Polynomial ExpressionSinh::ToPolynomial() const { throw runtime_error("Sinh expression is not polynomial-convertible."); } +int ExpressionSinh::Degree(const Variables &vars) const { + throw runtime_error("Sinh expression does not have a polynomial degree."); +} + Expression ExpressionSinh::Substitute(const Substitution& s) const { return sinh(get_argument().Substitute(s)); } @@ -1100,6 +1192,10 @@ Polynomial ExpressionCosh::ToPolynomial() const { throw runtime_error("Cosh expression is not polynomial-convertible."); } +int ExpressionCosh::Degree(const Variables &vars) const { + throw runtime_error("Cosh expression does not have a polynomial degree."); +} + Expression ExpressionCosh::Substitute(const Substitution& s) const { return cosh(get_argument().Substitute(s)); } @@ -1117,6 +1213,10 @@ Polynomial ExpressionTanh::ToPolynomial() const { throw runtime_error("Tanh expression is not polynomial-convertible."); } +int ExpressionTanh::Degree(const Variables& vars) const { + throw runtime_error("Tanh expression does not have a polynomial degree."); +} + Expression ExpressionTanh::Substitute(const Substitution& s) const { return tanh(get_argument().Substitute(s)); } @@ -1134,6 +1234,10 @@ Polynomial ExpressionMin::ToPolynomial() const { throw runtime_error("Min expression is not polynomial-convertible."); } +int ExpressionMin::Degree(const Variables &vars) const { + throw runtime_error("Min expression does not have a polynomial degree."); +} + Expression ExpressionMin::Substitute(const Substitution& s) const { return min(get_first_argument().Substitute(s), get_second_argument().Substitute(s)); @@ -1155,6 +1259,10 @@ Polynomial ExpressionMax::ToPolynomial() const { throw runtime_error("Max expression is not polynomial-convertible."); } +int ExpressionMax::Degree(const Variables &vars) const { + throw runtime_error("Max expression does not have a polynomial degree."); +} + Expression ExpressionMax::Substitute(const Substitution& s) const { return max(get_first_argument().Substitute(s), get_second_argument().Substitute(s)); @@ -1222,6 +1330,11 @@ Polynomial ExpressionIfThenElse::ToPolynomial() const { throw runtime_error("IfThenElse expression is not polynomial-convertible."); } +int ExpressionIfThenElse::Degree(const Variables &vars) const { + throw runtime_error( + "IfThenElse expression does not have a polynomial degree."); +} + double ExpressionIfThenElse::Evaluate(const Environment& env) const { if (f_cond_.Evaluate(env)) { return e_then_.Evaluate(env); diff --git a/drake/common/symbolic_expression_cell.h b/drake/common/symbolic_expression_cell.h index 54991f8da3bb..5a14a423c361 100644 --- a/drake/common/symbolic_expression_cell.h +++ b/drake/common/symbolic_expression_cell.h @@ -45,6 +45,13 @@ class ExpressionCell { * \pre{is_polynomial() is true.} */ virtual Polynomial ToPolynomial() const = 0; + + /** + * Returns the total degrees of the polynomial w.r.t the variables in + * @p vars. @see Expression::Degree(const Variables& vars) + */ + virtual int Degree(const Variables& vars) const = 0; + /** Evaluates under a given environment (by default, an empty environment). * @throws std::runtime_error if NaN is detected during evaluation. */ @@ -155,6 +162,7 @@ class ExpressionVar : public ExpressionCell { bool EqualTo(const ExpressionCell& e) const override; bool Less(const ExpressionCell& e) const override; Polynomial ToPolynomial() const override; + int Degree(const Variables& vars) const override; double Evaluate(const Environment& env) const override; Expression Substitute(const Substitution& s) const override; std::ostream& Display(std::ostream& os) const override; @@ -172,6 +180,7 @@ class ExpressionConstant : public ExpressionCell { bool EqualTo(const ExpressionCell& e) const override; bool Less(const ExpressionCell& e) const override; Polynomial ToPolynomial() const override; + int Degree(const Variables& vars) const override; double Evaluate(const Environment& env) const override; Expression Substitute(const Substitution& s) const override; std::ostream& Display(std::ostream& os) const override; @@ -188,6 +197,7 @@ class ExpressionNaN : public ExpressionCell { bool EqualTo(const ExpressionCell& e) const override; bool Less(const ExpressionCell& e) const override; Polynomial ToPolynomial() const override; + int Degree(const Variables& vars) const override; double Evaluate(const Environment& env) const override; Expression Substitute(const Substitution& s) const override; std::ostream& Display(std::ostream& os) const override; @@ -216,6 +226,7 @@ class ExpressionAdd : public ExpressionCell { bool EqualTo(const ExpressionCell& e) const override; bool Less(const ExpressionCell& e) const override; Polynomial ToPolynomial() const override; + int Degree(const Variables& vars) const override; double Evaluate(const Environment& env) const override; Expression Substitute(const Substitution& s) const override; std::ostream& Display(std::ostream& os) const override; @@ -314,6 +325,7 @@ class ExpressionMul : public ExpressionCell { bool EqualTo(const ExpressionCell& e) const override; bool Less(const ExpressionCell& e) const override; Polynomial ToPolynomial() const override; + int Degree(const Variables& vars) const override; double Evaluate(const Environment& env) const override; Expression Substitute(const Substitution& s) const override; std::ostream& Display(std::ostream& os) const override; @@ -395,6 +407,7 @@ class ExpressionDiv : public BinaryExpressionCell { public: ExpressionDiv(const Expression& e1, const Expression& e2); Polynomial ToPolynomial() const override; + int Degree(const Variables& vars) const override; Expression Substitute(const Substitution& s) const override; std::ostream& Display(std::ostream& os) const override; @@ -407,6 +420,7 @@ class ExpressionLog : public UnaryExpressionCell { public: explicit ExpressionLog(const Expression& e); Polynomial ToPolynomial() const override; + int Degree(const Variables& vars) const override; Expression Substitute(const Substitution& s) const override; std::ostream& Display(std::ostream& os) const override; @@ -423,6 +437,7 @@ class ExpressionAbs : public UnaryExpressionCell { public: explicit ExpressionAbs(const Expression& e); Polynomial ToPolynomial() const override; + int Degree(const Variables& vars) const override; Expression Substitute(const Substitution& s) const override; std::ostream& Display(std::ostream& os) const override; @@ -438,6 +453,7 @@ class ExpressionExp : public UnaryExpressionCell { public: explicit ExpressionExp(const Expression& e); Polynomial ToPolynomial() const override; + int Degree(const Variables& vars) const override; Expression Substitute(const Substitution& s) const override; std::ostream& Display(std::ostream& os) const override; @@ -450,6 +466,7 @@ class ExpressionSqrt : public UnaryExpressionCell { public: explicit ExpressionSqrt(const Expression& e); Polynomial ToPolynomial() const override; + int Degree(const Variables& vars) const override; Expression Substitute(const Substitution& s) const override; std::ostream& Display(std::ostream& os) const override; @@ -466,6 +483,7 @@ class ExpressionPow : public BinaryExpressionCell { public: ExpressionPow(const Expression& e1, const Expression& e2); Polynomial ToPolynomial() const override; + int Degree(const Variables& vars) const override; Expression Substitute(const Substitution& s) const override; std::ostream& Display(std::ostream& os) const override; @@ -483,6 +501,7 @@ class ExpressionSin : public UnaryExpressionCell { public: explicit ExpressionSin(const Expression& e); Polynomial ToPolynomial() const override; + int Degree(const Variables& vars) const override; Expression Substitute(const Substitution& s) const override; std::ostream& Display(std::ostream& os) const override; @@ -495,6 +514,7 @@ class ExpressionCos : public UnaryExpressionCell { public: explicit ExpressionCos(const Expression& e); Polynomial ToPolynomial() const override; + int Degree(const Variables& vars) const override; Expression Substitute(const Substitution& s) const override; std::ostream& Display(std::ostream& os) const override; @@ -507,6 +527,7 @@ class ExpressionTan : public UnaryExpressionCell { public: explicit ExpressionTan(const Expression& e); Polynomial ToPolynomial() const override; + int Degree(const Variables& vars) const override; Expression Substitute(const Substitution& s) const override; std::ostream& Display(std::ostream& os) const override; @@ -519,6 +540,7 @@ class ExpressionAsin : public UnaryExpressionCell { public: explicit ExpressionAsin(const Expression& e); Polynomial ToPolynomial() const override; + int Degree(const Variables& vars) const override; Expression Substitute(const Substitution& s) const override; std::ostream& Display(std::ostream& os) const override; @@ -535,6 +557,7 @@ class ExpressionAcos : public UnaryExpressionCell { public: explicit ExpressionAcos(const Expression& e); Polynomial ToPolynomial() const override; + int Degree(const Variables& vars) const override; Expression Substitute(const Substitution& s) const override; std::ostream& Display(std::ostream& os) const override; @@ -551,6 +574,7 @@ class ExpressionAtan : public UnaryExpressionCell { public: explicit ExpressionAtan(const Expression& e); Polynomial ToPolynomial() const override; + int Degree(const Variables& vars) const override; Expression Substitute(const Substitution& s) const override; std::ostream& Display(std::ostream& os) const override; @@ -564,6 +588,7 @@ class ExpressionAtan2 : public BinaryExpressionCell { public: ExpressionAtan2(const Expression& e1, const Expression& e2); Polynomial ToPolynomial() const override; + int Degree(const Variables& vars) const override; Expression Substitute(const Substitution& s) const override; std::ostream& Display(std::ostream& os) const override; @@ -576,6 +601,7 @@ class ExpressionSinh : public UnaryExpressionCell { public: explicit ExpressionSinh(const Expression& e); Polynomial ToPolynomial() const override; + int Degree(const Variables& vars) const override; Expression Substitute(const Substitution& s) const override; std::ostream& Display(std::ostream& os) const override; @@ -588,6 +614,7 @@ class ExpressionCosh : public UnaryExpressionCell { public: explicit ExpressionCosh(const Expression& e); Polynomial ToPolynomial() const override; + int Degree(const Variables& vars) const override; Expression Substitute(const Substitution& s) const override; std::ostream& Display(std::ostream& os) const override; @@ -600,6 +627,7 @@ class ExpressionTanh : public UnaryExpressionCell { public: explicit ExpressionTanh(const Expression& e); Polynomial ToPolynomial() const override; + int Degree(const Variables& vars) const override; Expression Substitute(const Substitution& s) const override; std::ostream& Display(std::ostream& os) const override; @@ -612,6 +640,7 @@ class ExpressionMin : public BinaryExpressionCell { public: ExpressionMin(const Expression& e1, const Expression& e2); Polynomial ToPolynomial() const override; + int Degree(const Variables& vars) const override; Expression Substitute(const Substitution& s) const override; std::ostream& Display(std::ostream& os) const override; @@ -624,6 +653,7 @@ class ExpressionMax : public BinaryExpressionCell { public: ExpressionMax(const Expression& e1, const Expression& e2); Polynomial ToPolynomial() const override; + int Degree(const Variables& vars) const override; Expression Substitute(const Substitution& s) const override; std::ostream& Display(std::ostream& os) const override; @@ -642,6 +672,7 @@ class ExpressionIfThenElse : public ExpressionCell { bool EqualTo(const ExpressionCell& e) const override; bool Less(const ExpressionCell& e) const override; Polynomial ToPolynomial() const override; + int Degree(const Variables& vars) const override; double Evaluate(const Environment& env) const override; Expression Substitute(const Substitution& s) const override; std::ostream& Display(std::ostream& os) const override; diff --git a/drake/common/test/symbolic_expression_test.cc b/drake/common/test/symbolic_expression_test.cc index 5ac7ed12b320..11c4bee57ef8 100644 --- a/drake/common/test/symbolic_expression_test.cc +++ b/drake/common/test/symbolic_expression_test.cc @@ -515,7 +515,7 @@ TEST_F(SymbolicExpressionTest, ToPolynomial1) { const Expression e5{pow(x_ + y_ + z_, 3)}; const Expression e6{pow(x_ + y_ + z_, 3) / 10}; const Expression e7{-pow(y_, 3)}; - const Expression e8{pow(pow(x_, 3), 1 / 3)}; + const Expression e8{pow(pow(x_, 3), 1.0 / 3)}; EXPECT_NEAR(e0.Evaluate(env), e0.ToPolynomial().EvaluateMultivariate(eval_point), 1e-8); @@ -548,6 +548,105 @@ TEST_F(SymbolicExpressionTest, ToPolynomial2) { } } +TEST_F(SymbolicExpressionTest, Degree) { + const Expression e0{42.0}; + EXPECT_EQ(e0.Degree({var_x_, var_y_}), 0); + EXPECT_EQ(e0.Degree(), 0); + + const Expression e1{pow(x_, 2)}; + EXPECT_EQ(e1.Degree({var_x_}), 2); + EXPECT_EQ(e1.Degree({var_y_}), 0); + EXPECT_EQ(e1.Degree({var_x_, var_y_}), 2); + EXPECT_EQ(e1.Degree(), 2); + + const Expression e2{pow(x_, 2) * pow(y_, 3)}; + EXPECT_EQ(e2.Degree({var_x_}), 2); + EXPECT_EQ(e2.Degree({var_y_}), 3); + EXPECT_EQ(e2.Degree({var_z_}), 0); + EXPECT_EQ(e2.Degree({var_x_, var_y_}), 5); + EXPECT_EQ(e2.Degree({var_x_, var_z_}), 2); + EXPECT_EQ(e2.Degree({var_y_, var_z_}), 3); + EXPECT_EQ(e2.Degree({var_x_, var_y_, var_z_}), 5); + EXPECT_EQ(e2.Degree(), 5); + + const Expression e3{3 + x_ + y_ + z_}; + EXPECT_EQ(e3.Degree({var_x_}), 1); + EXPECT_EQ(e3.Degree({var_y_}), 1); + EXPECT_EQ(e3.Degree({var_z_}), 1); + EXPECT_EQ(e3.Degree({var_x_, var_y_}), 1); + EXPECT_EQ(e3.Degree({var_x_, var_y_, var_z_}), 1); + EXPECT_EQ(e3.Degree(), 1); + + const Expression e4{1 + pow(x_, 2) + pow(y_, 3)}; + EXPECT_EQ(e4.Degree({var_x_}), 2); + EXPECT_EQ(e4.Degree({var_y_}), 3); + EXPECT_EQ(e4.Degree({var_x_, var_y_}), 3); + EXPECT_EQ(e4.Degree({var_x_, var_z_}), 2); + EXPECT_EQ(e4.Degree({var_x_, var_y_, var_z_}), 3); + EXPECT_EQ(e4.Degree(), 3); + + const Expression e5{1 + pow(x_, 2) * y_ + x_ * y_ * y_ * z_}; + EXPECT_EQ(e5.Degree({var_x_}), 2); + EXPECT_EQ(e5.Degree({var_y_}), 2); + EXPECT_EQ(e5.Degree({var_z_}), 1); + EXPECT_EQ(e5.Degree({var_x_, var_y_}), 3); + EXPECT_EQ(e5.Degree({var_x_, var_z_}), 2); + EXPECT_EQ(e5.Degree({var_y_, var_z_}), 3); + EXPECT_EQ(e5.Degree({var_x_, var_y_, var_z_}), 4); + EXPECT_EQ(e5.Degree(), 4); + + const Expression e6{pow(x_ + y_ + z_, 3)}; + EXPECT_EQ(e6.Degree({var_x_}), 3); + EXPECT_EQ(e6.Degree({var_y_}), 3); + EXPECT_EQ(e6.Degree({var_z_}), 3); + EXPECT_EQ(e6.Degree({var_x_, var_y_}), 3); + EXPECT_EQ(e6.Degree({var_x_, var_z_}), 3); + EXPECT_EQ(e6.Degree({var_y_, var_z_}), 3); + EXPECT_EQ(e6.Degree({var_x_, var_y_, var_z_}), 3); + EXPECT_EQ(e6.Degree(), 3); + + const Expression e7{pow(x_ + x_ * y_ * y_, 2) * y_ + + pow(x_ + pow(y_ + x_ * z_, 2), 3)}; + EXPECT_EQ(e7.Degree({var_x_}), 6); + EXPECT_EQ(e7.Degree({var_y_}), 6); + EXPECT_EQ(e7.Degree({var_z_}), 6); + EXPECT_EQ(e7.Degree({var_x_, var_y_}), 7); + EXPECT_EQ(e7.Degree({var_x_, var_z_}), 12); + EXPECT_EQ(e7.Degree({var_y_, var_z_}), 6); + EXPECT_EQ(e7.Degree({var_x_, var_y_, var_z_}), 12); + EXPECT_EQ(e7.Degree(), 12); + + const Expression e8{pow(x_ + y_ + z_, 3) / 10}; + EXPECT_EQ(e8.Degree({var_x_}), 3); + EXPECT_EQ(e8.Degree({var_y_}), 3); + EXPECT_EQ(e8.Degree({var_z_}), 3); + EXPECT_EQ(e8.Degree({var_x_, var_y_}), 3); + EXPECT_EQ(e8.Degree({var_x_, var_z_}), 3); + EXPECT_EQ(e8.Degree({var_y_, var_z_}), 3); + EXPECT_EQ(e8.Degree({var_x_, var_y_, var_z_}), 3); + EXPECT_EQ(e8.Degree(), 3); + + const Expression e9{-pow(y_, 3)}; + EXPECT_EQ(e9.Degree({var_x_}), 0); + EXPECT_EQ(e9.Degree({var_y_}), 3); + EXPECT_EQ(e9.Degree({var_z_}), 0); + EXPECT_EQ(e9.Degree({var_x_, var_y_}), 3); + EXPECT_EQ(e9.Degree({var_x_, var_z_}), 0); + EXPECT_EQ(e9.Degree({var_y_, var_z_}), 3); + EXPECT_EQ(e9.Degree({var_x_, var_y_, var_z_}), 3); + EXPECT_EQ(e9.Degree(), 3); + + const Expression e10{pow(pow(x_, 3), 1.0 / 3)}; + EXPECT_EQ(e10.Degree({var_x_}), 1); + EXPECT_EQ(e10.Degree({var_y_}), 0); + EXPECT_EQ(e10.Degree({var_z_}), 0); + EXPECT_EQ(e10.Degree({var_x_, var_y_}), 1); + EXPECT_EQ(e10.Degree({var_x_, var_z_}), 1); + EXPECT_EQ(e10.Degree({var_y_, var_z_}), 0); + EXPECT_EQ(e10.Degree({var_x_, var_y_, var_z_}), 1); + EXPECT_EQ(e10.Degree(), 1); +} + TEST_F(SymbolicExpressionTest, LessKind) { CheckOrdering({e_constant_, e_var_, e_add_, e_neg_, e_mul_, e_div_, e_log_, e_abs_, e_exp_, e_sqrt_,