Crocoddyl
quadratic-barrier.hpp
1 // BSD 3-Clause License
3 //
4 // Copyright (C) 2019-2025, LAAS-CNRS, University of Edinburgh,
5 // University of Oxford, Heriot-Watt University
6 // Copyright note valid unless otherwise stated in individual files. All
7 // rights reserved.
9 
10 #ifndef CROCODDYL_CORE_ACTIVATIONS_QUADRATIC_BARRIER_HPP_
11 #define CROCODDYL_CORE_ACTIVATIONS_QUADRATIC_BARRIER_HPP_
12 
13 #include "crocoddyl/core/activation-base.hpp"
14 #include "crocoddyl/core/fwd.hpp"
15 
16 namespace crocoddyl {
17 
18 template <typename _Scalar>
20  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
21 
22  typedef _Scalar Scalar;
24  typedef typename MathBase::VectorXs VectorXs;
25  typedef typename MathBase::MatrixXs MatrixXs;
26 
27  ActivationBoundsTpl(const VectorXs& lower, const VectorXs& upper,
28  const Scalar b = Scalar(1.))
29  : lb(lower), ub(upper), beta(b) {
30  if (lb.size() != ub.size()) {
31  throw_pretty("Invalid argument: "
32  << "The lower and upper bounds don't have the same "
33  "dimension (lb,ub dimensions equal to " +
34  std::to_string(lb.size()) + "," +
35  std::to_string(ub.size()) + ", respectively)");
36  }
37  if (beta < Scalar(0) || beta > Scalar(1.)) {
38  throw_pretty(
39  "Invalid argument: " << "The range of beta is between 0 and 1");
40  }
41  for (std::size_t i = 0; i < static_cast<std::size_t>(lb.size()); ++i) {
42  if (isfinite(lb(i)) && isfinite(ub(i))) {
43  if (lb(i) - ub(i) > Scalar(0)) {
44  throw_pretty("Invalid argument: "
45  << "The lower and upper bounds are badly defined; ub "
46  "has to be bigger / equals to lb");
47  }
48  }
49  // Assign the maximum value for infinity/nan values
50  if (!isfinite(lb(i))) {
51  lb(i) = -std::numeric_limits<Scalar>::max();
52  }
53  if (!isfinite(ub(i))) {
54  ub(i) = std::numeric_limits<Scalar>::max();
55  }
56  }
57 
58  if (beta >= Scalar(0) && beta <= Scalar(1.)) {
59  for (std::size_t i = 0; i < static_cast<std::size_t>(lb.size()); ++i) {
60  // do not use beta when one of the bounds is inf
61  if (lb(i) != (-std::numeric_limits<Scalar>::max()) &&
62  ub(i) != (std::numeric_limits<Scalar>::max())) {
63  Scalar m = Scalar(0.5) * (lb(i) + ub(i));
64  Scalar d = Scalar(0.5) * (ub(i) - lb(i));
65  lb(i) = m - beta * d;
66  ub(i) = m + beta * d;
67  }
68  }
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  template <typename NewScalar>
78  ActivationBoundsTpl<NewScalar> cast() const {
79  typedef ActivationBoundsTpl<NewScalar> ReturnType;
80  ReturnType res(lb.template cast<NewScalar>(), ub.template cast<NewScalar>(),
81  scalar_cast<NewScalar>(beta));
82  return res;
83  }
84 
85  ActivationBoundsTpl& operator=(const ActivationBoundsTpl& other) {
86  if (this != &other) {
87  lb = other.lb;
88  ub = other.ub;
89  beta = other.beta;
90  }
91  return *this;
92  }
93 
97  friend std::ostream& operator<<(std::ostream& os,
98  const ActivationBoundsTpl& bounds) {
99  bounds.print(os);
100  return os;
101  }
102 
103  void print(std::ostream& os) const {
104  os << "ActivationBounds {lb=" << lb.transpose() << ", ub=" << ub.transpose()
105  << ", beta=" << beta << "}";
106  }
107 
108  VectorXs lb;
109  VectorXs ub;
110  Scalar beta;
111 };
112 
113 template <typename _Scalar>
115  : public ActivationModelAbstractTpl<_Scalar> {
116  public:
117  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
118  CROCODDYL_DERIVED_CAST(ActivationModelBase,
120 
121  typedef _Scalar Scalar;
127  typedef typename MathBase::VectorXs VectorXs;
128  typedef typename MathBase::MatrixXs MatrixXs;
129 
131  : Base(bounds.lb.size()), bounds_(bounds) {};
132  virtual ~ActivationModelQuadraticBarrierTpl() = default;
133 
134  virtual void calc(const std::shared_ptr<ActivationDataAbstract>& data,
135  const Eigen::Ref<const VectorXs>& r) override {
136  if (static_cast<std::size_t>(r.size()) != nr_) {
137  throw_pretty(
138  "Invalid argument: " << "r has wrong dimension (it should be " +
139  std::to_string(nr_) + ")");
140  }
141 
142  std::shared_ptr<Data> d = std::static_pointer_cast<Data>(data);
143 
144  d->rlb_min_ = (r - bounds_.lb).array().min(Scalar(0.));
145  d->rub_max_ = (r - bounds_.ub).array().max(Scalar(0.));
146  data->a_value = Scalar(0.5) * d->rlb_min_.matrix().squaredNorm() +
147  Scalar(0.5) * d->rub_max_.matrix().squaredNorm();
148  };
149 
150  virtual void calcDiff(const std::shared_ptr<ActivationDataAbstract>& data,
151  const Eigen::Ref<const VectorXs>& r) override {
152  if (static_cast<std::size_t>(r.size()) != nr_) {
153  throw_pretty(
154  "Invalid argument: " << "r has wrong dimension (it should be " +
155  std::to_string(nr_) + ")");
156  }
157 
158  std::shared_ptr<Data> d = std::static_pointer_cast<Data>(data);
159  data->Ar = (d->rlb_min_ + d->rub_max_).matrix();
160 
161  using pinocchio::internal::if_then_else;
162  for (Eigen::Index i = 0; i < data->Arr.cols(); i++) {
163  data->Arr.diagonal()[i] = if_then_else(
164  pinocchio::internal::LE, r[i] - bounds_.lb[i], Scalar(0.), Scalar(1.),
165  if_then_else(pinocchio::internal::GE, r[i] - bounds_.ub[i],
166  Scalar(0.), Scalar(1.), Scalar(0.)));
167  }
168  };
169 
170  virtual std::shared_ptr<ActivationDataAbstract> createData() override {
171  return std::allocate_shared<Data>(Eigen::aligned_allocator<Data>(), this);
172  };
173 
174  template <typename NewScalar>
177  ReturnType res(bounds_.template cast<NewScalar>());
178  return res;
179  }
180 
181  const ActivationBounds& get_bounds() const { return bounds_; };
182  void set_bounds(const ActivationBounds& bounds) { bounds_ = bounds; };
183 
189  virtual void print(std::ostream& os) const override {
190  os << "ActivationModelQuadraticBarrier {nr=" << nr_ << "}";
191  }
192 
193  protected:
194  using Base::nr_;
195 
196  private:
197  ActivationBounds bounds_;
198 };
199 
200 template <typename _Scalar>
202  : public ActivationDataAbstractTpl<_Scalar> {
203  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
204 
205  typedef _Scalar Scalar;
207  typedef typename MathBase::ArrayXs ArrayXs;
208  typedef typename MathBase::VectorXs VectorXs;
209  typedef typename MathBase::DiagonalMatrixXs DiagonalMatrixXs;
211 
212  template <typename Activation>
213  explicit ActivationDataQuadraticBarrierTpl(Activation* const activation)
214  : Base(activation),
215  rlb_min_(activation->get_nr()),
216  rub_max_(activation->get_nr()) {
217  rlb_min_.setZero();
218  rub_max_.setZero();
219  }
220 
221  ArrayXs rlb_min_;
222  ArrayXs rub_max_;
223 
224  using Base::a_value;
225  using Base::Ar;
226  using Base::Arr;
227 };
228 
229 } // namespace crocoddyl
230 
231 CROCODDYL_DECLARE_EXTERN_TEMPLATE_STRUCT(crocoddyl::ActivationBoundsTpl)
232 CROCODDYL_DECLARE_EXTERN_TEMPLATE_CLASS(
234 CROCODDYL_DECLARE_EXTERN_TEMPLATE_STRUCT(
236 
237 #endif // CROCODDYL_CORE_ACTIVATIONS_QUADRATIC_BARRIER_HPP_
virtual void print(std::ostream &os) const override
Print relevant information of the quadratic barrier model.
friend std::ostream & operator<<(std::ostream &os, const ActivationBoundsTpl &bounds)
Print information on the activation bounds.