Crocoddyl
quadratic-barrier.hpp
1 // BSD 3-Clause License
3 //
4 // Copyright (C) 2019-2021, LAAS-CNRS, University of Edinburgh, University of
5 // Oxford Copyright note valid unless otherwise stated in individual files. All
6 // rights reserved.
8 
9 #ifndef CROCODDYL_CORE_ACTIVATIONS_QUADRATIC_BARRIER_HPP_
10 #define CROCODDYL_CORE_ACTIVATIONS_QUADRATIC_BARRIER_HPP_
11 
12 #include <math.h>
13 
14 #include <pinocchio/utils/static-if.hpp>
15 #include <stdexcept>
16 
17 #include "crocoddyl/core/activation-base.hpp"
18 #include "crocoddyl/core/fwd.hpp"
19 #include "crocoddyl/core/utils/exception.hpp"
20 
21 namespace crocoddyl {
22 
23 template <typename _Scalar>
25  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
26 
27  typedef _Scalar Scalar;
29  typedef typename MathBase::VectorXs VectorXs;
30  typedef typename MathBase::MatrixXs MatrixXs;
31 
32  ActivationBoundsTpl(const VectorXs& lower, const VectorXs& upper,
33  const Scalar b = (Scalar)1.)
34  : lb(lower), ub(upper), beta(b) {
35  if (lb.size() != ub.size()) {
36  throw_pretty("Invalid argument: "
37  << "The lower and upper bounds don't have the same "
38  "dimension (lb,ub dimensions equal to " +
39  std::to_string(lb.size()) + "," +
40  std::to_string(ub.size()) + ", respectively)");
41  }
42  if (beta < Scalar(0) || beta > Scalar(1.)) {
43  throw_pretty("Invalid argument: "
44  << "The range of beta is between 0 and 1");
45  }
46  using std::isfinite;
47  for (std::size_t i = 0; i < static_cast<std::size_t>(lb.size()); ++i) {
48  if (isfinite(lb(i)) && isfinite(ub(i))) {
49  if (lb(i) - ub(i) > 0) {
50  throw_pretty("Invalid argument: "
51  << "The lower and upper bounds are badly defined; ub "
52  "has to be bigger / equals to lb");
53  }
54  }
55  // Assign the maximum value for infinity/nan values
56  if (!isfinite(lb(i))) {
57  lb(i) = -std::numeric_limits<Scalar>::max();
58  }
59  if (!isfinite(ub(i))) {
60  ub(i) = std::numeric_limits<Scalar>::max();
61  }
62  }
63 
64  if (beta >= Scalar(0) && beta <= Scalar(1.)) {
65  VectorXs m = Scalar(0.5) * (lb + ub);
66  VectorXs d = Scalar(0.5) * (ub - lb);
67  lb = m - beta * d;
68  ub = m + beta * d;
69  } else {
70  beta = Scalar(1.);
71  }
72  }
74  : lb(other.lb), ub(other.ub), beta(other.beta) {}
75  ActivationBoundsTpl() : beta(Scalar(1.)) {}
76 
77  ActivationBoundsTpl& operator=(const ActivationBoundsTpl& other) {
78  if (this != &other) {
79  lb = other.lb;
80  ub = other.ub;
81  beta = other.beta;
82  }
83  return *this;
84  }
85 
86  VectorXs lb;
87  VectorXs ub;
88  Scalar beta;
89 };
90 
91 template <typename _Scalar>
93  : public ActivationModelAbstractTpl<_Scalar> {
94  public:
95  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
96 
97  typedef _Scalar Scalar;
103  typedef typename MathBase::VectorXs VectorXs;
104  typedef typename MathBase::MatrixXs MatrixXs;
105 
107  : Base(bounds.lb.size()), bounds_(bounds){};
109 
110  virtual void calc(const boost::shared_ptr<ActivationDataAbstract>& data,
111  const Eigen::Ref<const VectorXs>& r) {
112  if (static_cast<std::size_t>(r.size()) != nr_) {
113  throw_pretty("Invalid argument: "
114  << "r has wrong dimension (it should be " +
115  std::to_string(nr_) + ")");
116  }
117 
118  boost::shared_ptr<Data> d = boost::static_pointer_cast<Data>(data);
119 
120  d->rlb_min_ = (r - bounds_.lb).array().min(Scalar(0.));
121  d->rub_max_ = (r - bounds_.ub).array().max(Scalar(0.));
122  data->a_value = Scalar(0.5) * d->rlb_min_.matrix().squaredNorm() +
123  Scalar(0.5) * d->rub_max_.matrix().squaredNorm();
124  };
125 
126  virtual void calcDiff(const boost::shared_ptr<ActivationDataAbstract>& data,
127  const Eigen::Ref<const VectorXs>& r) {
128  if (static_cast<std::size_t>(r.size()) != nr_) {
129  throw_pretty("Invalid argument: "
130  << "r has wrong dimension (it should be " +
131  std::to_string(nr_) + ")");
132  }
133 
134  boost::shared_ptr<Data> d = boost::static_pointer_cast<Data>(data);
135  data->Ar = (d->rlb_min_ + d->rub_max_).matrix();
136 
137  using pinocchio::internal::if_then_else;
138  for (Eigen::Index i = 0; i < data->Arr.cols(); i++) {
139  data->Arr.diagonal()[i] = if_then_else(
140  pinocchio::internal::LE, r[i] - bounds_.lb[i], Scalar(0.), Scalar(1.),
141  if_then_else(pinocchio::internal::GE, r[i] - bounds_.ub[i],
142  Scalar(0.), Scalar(1.), Scalar(0.)));
143  }
144  };
145 
146  virtual boost::shared_ptr<ActivationDataAbstract> createData() {
147  return boost::allocate_shared<Data>(Eigen::aligned_allocator<Data>(), this);
148  };
149 
150  const ActivationBounds& get_bounds() const { return bounds_; };
151  void set_bounds(const ActivationBounds& bounds) { bounds_ = bounds; };
152 
158  virtual void print(std::ostream& os) const {
159  os << "ActivationModelQuadraticBarrier {nr=" << nr_ << "}";
160  }
161 
162  protected:
163  using Base::nr_;
164 
165  private:
166  ActivationBounds bounds_;
167 };
168 
169 template <typename _Scalar>
171  : public ActivationDataAbstractTpl<_Scalar> {
172  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
173 
174  typedef _Scalar Scalar;
176  typedef typename MathBase::ArrayXs ArrayXs;
178 
179  template <typename Activation>
180  explicit ActivationDataQuadraticBarrierTpl(Activation* const activation)
181  : Base(activation),
182  rlb_min_(activation->get_nr()),
183  rub_max_(activation->get_nr()) {
184  rlb_min_.setZero();
185  rub_max_.setZero();
186  }
187 
188  ArrayXs rlb_min_;
189  ArrayXs rub_max_;
190  using Base::a_value;
191  using Base::Ar;
192  using Base::Arr;
193 };
194 
195 } // namespace crocoddyl
196 
197 #endif // CROCODDYL_CORE_ACTIVATIONS_QUADRATIC_BARRIER_HPP_
virtual void print(std::ostream &os) const
Print relevant information of the quadratic barrier model.