GCC Code Coverage Report


Directory: ./
File: include/multicontact-api/geometry/second-order-cone.hpp
Date: 2025-03-10 16:17:01
Exec Total Coverage
Lines: 28 66 42.4%
Branches: 20 80 25.0%

Line Branch Exec Source
1 // Copyright (c) 2015-2018, CNRS
2 // Authors: Justin Carpentier <jcarpent@laas.fr>
3
4 #ifndef __multicontact_api_geometry_second_order_cone_hpp__
5 #define __multicontact_api_geometry_second_order_cone_hpp__
6
7 #include <Eigen/Dense>
8 #include <iostream>
9
10 #include "multicontact-api/geometry/fwd.hpp"
11 #include "multicontact-api/serialization/archive.hpp"
12 #include "multicontact-api/serialization/eigen-matrix.hpp"
13
14 namespace multicontact_api {
15 namespace geometry {
16
17 template <typename _Scalar, int _dim, int _Options>
18 struct SecondOrderCone : public serialization::Serializable<
19 SecondOrderCone<_Scalar, _dim, _Options> > {
20 EIGEN_MAKE_ALIGNED_OPERATOR_NEW
21 enum { dim = _dim, Options = _Options };
22 typedef _Scalar Scalar;
23 typedef Eigen::Matrix<Scalar, dim, dim, Options> MatrixD;
24 typedef Eigen::Matrix<Scalar, dim, 1, Options> VectorD;
25 typedef Eigen::DenseIndex DenseIndex;
26
27 SecondOrderCone()
28 : m_Q(MatrixD::Identity()),
29 m_QPo(_dim, _dim),
30 m_direction(VectorD::Zero()),
31 m_Pd(_dim, _dim),
32 m_Po(_dim, _dim) {
33 m_direction[_dim - 1] = 1.;
34 computeProjectors();
35 }
36
37 3 SecondOrderCone(const MatrixD& Q, const VectorD& direction)
38 3 : m_Q(Q),
39
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
3 m_QPo(_dim, _dim),
40 3 m_direction(direction.normalized()),
41
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
3 m_Pd(_dim, _dim),
42
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
3 m_Po(_dim, _dim) {
43
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
3 assert(direction.norm() >= Eigen::NumTraits<Scalar>::dummy_precision());
44
3/6
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 2 times.
3 assert((Q - Q.transpose()).isMuchSmallerThan(Q));
45 3 computeProjectors();
46 3 }
47
48 ///
49 /// \brief Build a regular cone from a given friction coefficient and a
50 /// direction.
51 ///
52 /// \param mu Friction coefficient.
53 /// \param direction Direction of the cone.
54 ///
55 /// \returns A second order cone.
56 ///
57 1 static SecondOrderCone RegularCone(const Scalar mu,
58 const VectorD& direction) {
59
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 assert(mu > 0 && "The friction coefficient must be non-negative");
60
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 MatrixD Q(MatrixD::Zero());
61
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 Q.diagonal().fill(1. / mu);
62
63
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 return SecondOrderCone(Q, direction);
64 }
65
66 template <typename S2, int O2>
67 bool operator==(const SecondOrderCone<S2, dim, O2>& other) const {
68 return m_Q == other.m_Q && m_direction == other.m_direction;
69 }
70
71 template <typename S2, int O2>
72 bool operator!=(const SecondOrderCone<S2, dim, O2>& other) const {
73 return !(*this == other);
74 }
75
76 /// \returns the value of lhs of the conic inequality
77 3 Scalar lhsValue(const VectorD& point) const {
78 // const VectorD x_Po(m_Po * point);
79
1/2
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 return (m_QPo * point).norm();
80 }
81
82 /// \returns the value of rhs of the conic inequality
83 3 Scalar rhsValue(const VectorD& point) const { return m_direction.dot(point); }
84
85 /// \returns true if the point is inside the cone
86 3 bool check(const VectorD& point) const { return check(point, 1.); }
87
88 3 bool check(const VectorD& point, const Scalar factor) const {
89 3 return lhsValue(point) <= factor * rhsValue(point);
90 }
91
92 /// \returns the direction of the cone.
93 2 const VectorD& direction() const { return m_direction; }
94 void setDirection(const VectorD& direction) {
95 assert(direction.norm() >= Eigen::NumTraits<Scalar>::dummy_precision());
96 m_direction = direction.normalized();
97 computeProjectors();
98 }
99
100 template <typename S2, int O2>
101 bool isApprox(
102 const SecondOrderCone<S2, dim, O2>& other,
103 const Scalar& prec = Eigen::NumTraits<Scalar>::dummy_precision()) const {
104 return m_direction.isApprox(other.m_direction, prec) &&
105 m_Q.isApprox(other.m_Q, prec);
106 }
107
108 /// \returns the quadratic term of the lhs norm.
109 2 const MatrixD& Q() const { return m_Q; }
110 void setQ(const MatrixD& Q) {
111 assert((Q - Q.transpose()).isMuchSmallerThan(Q));
112 m_Q = Q;
113 computeProjectors();
114 }
115
116 void disp(std::ostream& os) const {
117 os << "Q:\n"
118 << m_Q << std::endl
119 << "direction: " << m_direction.transpose() << std::endl;
120 }
121
122 friend std::ostream& operator<<(std::ostream& os, const SecondOrderCone& C) {
123 C.disp(os);
124 return os;
125 }
126
127 protected:
128 3 inline void computeProjectors() {
129
2/4
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
3 m_Pd = m_direction * m_direction.transpose();
130
2/4
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
3 m_Po = MatrixD::Identity() - m_Pd;
131
2/4
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
3 m_QPo.noalias() = m_Q * m_Po;
132 3 }
133
134 /// \brief Cholesky decomposition matrix reprensenting the conic norm
135 MatrixD m_Q;
136 /// \brief Cholesky decomposition projected on the orthogonal of m_direction
137 MatrixD m_QPo;
138
139 /// \brief Direction of the cone
140 VectorD m_direction;
141
142 /// \brief Projector along the direction of d
143 MatrixD m_Pd;
144 /// \brief Projector orthogonal to d
145 MatrixD m_Po;
146
147 private:
148 // Serialization of the class
149 friend class boost::serialization::access;
150
151 template <class Archive>
152 void save(Archive& ar, const unsigned int /*version*/) const {
153 ar& boost::serialization::make_nvp("quadratic_term", m_Q);
154 ar& boost::serialization::make_nvp("direction", m_direction);
155 }
156
157 template <class Archive>
158 void load(Archive& ar, const unsigned int /*version*/) {
159 ar >> boost::serialization::make_nvp("quadratic_term", m_Q);
160 ar >> boost::serialization::make_nvp("direction", m_direction);
161
162 computeProjectors();
163 }
164
165 BOOST_SERIALIZATION_SPLIT_MEMBER()
166 };
167
168 } // namespace geometry
169 } // namespace multicontact_api
170
171 #endif // ifndef __multicontact_api_geometry_second_order_cone_hpp__
172