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/solvers/benchmarking/benchmark_mathematical_prog...

122 lines
5.2 KiB

#include "drake/common/symbolic/monomial_util.h"
#include "drake/solvers/mathematical_program.h"
#include "drake/tools/performance/fixture_common.h"
namespace drake {
namespace solvers {
namespace {
static void BenchmarkSosProgram1(benchmark::State& state) { // NOLINT
// Formulate a mathematical program with sum-of-squares constraints. This
// will involve a lot of computation on symbolic::Polynomial and imposing
// linear constraints.
// We construct symbolic::Polynomial directly from a Monomial map instead of
// parsing a symbolic::Expression.
for (auto _ : state) {
MathematicalProgram prog;
// Impose a constraint p_i(x).dot(q_i(x)) is sos, where both p_i(x) and
// q_i(x) are vectors of polynomials.
const auto x = prog.NewIndeterminates<7>();
const symbolic::Variables x_vars(x);
const auto monomial_basis = symbolic::MonomialBasis(x_vars, 3);
for (int i = 0; i < 10; ++i) {
VectorX<symbolic::Polynomial> p_i(15);
VectorX<symbolic::Polynomial> q_i(p_i.rows());
for (int j = 0; j < p_i.rows(); ++j) {
symbolic::Polynomial::MapType p_map;
for (int k = 0; k < monomial_basis.rows(); ++k) {
p_map.emplace(monomial_basis(k),
static_cast<double>(i * j) / 100.0 + k / 10.0 + 1);
}
p_i(j) = symbolic::Polynomial(std::move(p_map));
q_i(j) = prog.NewFreePolynomial(x_vars, 2);
}
prog.AddSosConstraint(p_i.dot(q_i));
}
}
}
static void BenchmarkSosProgram2(benchmark::State& state) { // NOLINT
// Formulate a mathematical program with sum-of-squares constraints. This
// will involve a lot of computation on symbolic::Polynomial and imposing
// linear constraints. Specifically it would involve the multiplication
// between two polynomials, one of the polynomial has all the coefficients as
// double constants, and the other polynomial coefficients are linear
// expressions, constructed using symbolic polynomial operations. This is
// different from BenchmarkSosProgram1 where the second polynomial
// coefficients are symbolic variables. We construct symbolic::Polynomial
// directly from a Monomial map instead of parsing a symbolic::Expression.
for (auto _ : state) {
MathematicalProgram prog;
// Impose a constraint p(x).dot(q(x)) is sos, where both p(x) and
// q(x) are both polynomials.
// where q(x) = ∂V/∂x * f(x)
// This ∂V/∂x * f(x) is often found in Lyapunov stability analysis.
const auto x = prog.NewIndeterminates<5>();
const symbolic::Variables x_vars(x);
const VectorX<symbolic::Monomial> monomial_basis =
symbolic::MonomialBasis(x_vars, 3);
const symbolic::Polynomial V = prog.NewFreePolynomial(x_vars, 4);
const Eigen::Matrix<symbolic::Polynomial, 1, 5> dVdx = V.Jacobian(x);
symbolic::Polynomial::MapType p_map;
for (int k = 0; k < monomial_basis.rows(); ++k) {
p_map.emplace(monomial_basis(k), static_cast<double>(k) / 10.0 + 1);
}
const symbolic::Polynomial p = symbolic::Polynomial(std::move(p_map));
// Construct f(x) ∈ ℝⁿ[x] where n = x.rows()
VectorX<symbolic::Polynomial> f(x.rows());
for (int i = 0; i < x.rows(); ++i) {
symbolic::Polynomial::MapType f_map;
for (int k = 0; k < monomial_basis.rows(); ++k) {
f_map.emplace(monomial_basis(k), static_cast<double>(k) * 2.0 + 1);
}
f(i) = symbolic::Polynomial(std::move(f_map));
}
const symbolic::Polynomial q = dVdx.dot(f);
prog.AddSosConstraint(p * q);
}
}
/**
* This program is reported in github issue
* https://github.com/RobotLocomotion/drake/issues/17160
* This program tries to find a lower bound for the cost-to-go that satisfies
* HJB inequality. Note that we create the right-hand side polynomial of the HJB
* inequality but don't impose any non-negative constraint on this polynomial.
* The reason is that this polynomial's coefficient isn't a linear expression of
* our decision variables. This benchmark program tests parsing a symbolic
* expression to a polynomial, but not imposing constraint on the polynomial.
*/
static void BenchmarkSosProgram3(benchmark::State& state) { // NOLINT
for (auto _ : state) {
MathematicalProgram prog;
const int nz = 3;
const int degree = 8;
const auto z = prog.NewIndeterminates(nz, "z");
const symbolic::Polynomial J =
prog.NewFreePolynomial(symbolic::Variables(z), degree);
const symbolic::Expression J_expr = J.ToExpression();
const RowVectorX<symbolic::Expression> dJdz = J_expr.Jacobian(z);
const Eigen::Vector3d f2(0, 0, 1);
const symbolic::Expression u_opt = -0.5 * dJdz.dot(f2);
const Eigen::Vector3d z0(0, 1, 0);
using std::pow;
const symbolic::Expression one_step_cost =
(z - z0).dot(z - z0) + pow(u_opt, 2);
const Vector3<symbolic::Expression> f(z(1) + z(2), -z(0) + z(2),
(z(0) + u_opt - z(2)));
const symbolic::Expression rhs = one_step_cost + dJdz.dot(f);
const symbolic::Polynomial rhs_poly(rhs, symbolic::Variables(z));
}
}
BENCHMARK(BenchmarkSosProgram1);
BENCHMARK(BenchmarkSosProgram2);
BENCHMARK(BenchmarkSosProgram3);
} // namespace
} // namespace solvers
} // namespace drake