| Directory: | ./ |
|---|---|
| File: | src/implicit.cc |
| Date: | 2025-05-05 12:19:30 |
| Exec | Total | Coverage | |
|---|---|---|---|
| Lines: | 126 | 143 | 88.1% |
| Branches: | 101 | 226 | 44.7% |
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // Copyright (c) 2015, LAAS-CNRS | ||
| 2 | // Authors: Joseph Mirabel (joseph.mirabel@laas.fr) | ||
| 3 | // | ||
| 4 | |||
| 5 | // Redistribution and use in source and binary forms, with or without | ||
| 6 | // modification, are permitted provided that the following conditions are | ||
| 7 | // met: | ||
| 8 | // | ||
| 9 | // 1. Redistributions of source code must retain the above copyright | ||
| 10 | // notice, this list of conditions and the following disclaimer. | ||
| 11 | // | ||
| 12 | // 2. Redistributions in binary form must reproduce the above copyright | ||
| 13 | // notice, this list of conditions and the following disclaimer in the | ||
| 14 | // documentation and/or other materials provided with the distribution. | ||
| 15 | // | ||
| 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| 17 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| 18 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| 19 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| 20 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
| 21 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
| 22 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| 23 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| 25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| 26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | ||
| 27 | // DAMAGE. | ||
| 28 | |||
| 29 | #include "hpp/constraints/implicit.hh" | ||
| 30 | |||
| 31 | #include <boost/serialization/export.hpp> | ||
| 32 | #include <boost/serialization/vector.hpp> | ||
| 33 | #include <boost/serialization/weak_ptr.hpp> | ||
| 34 | #include <hpp/constraints/differentiable-function.hh> | ||
| 35 | #include <hpp/util/serialization.hh> | ||
| 36 | #include <pinocchio/serialization/eigen.hpp> | ||
| 37 | |||
| 38 | namespace hpp { | ||
| 39 | namespace constraints { | ||
| 40 | 1165 | bool Implicit::operator==(const Implicit& other) const { | |
| 41 | 1165 | bool res = isEqual(other, true); | |
| 42 | 1165 | return res; | |
| 43 | } | ||
| 44 | 9604 | size_type computeParameterSize(const ComparisonTypes_t& comp) { | |
| 45 | 9604 | size_type size = 0; | |
| 46 |
2/2✓ Branch 1 taken 48716 times.
✓ Branch 2 taken 9604 times.
|
58320 | for (std::size_t i = 0; i < comp.size(); ++i) { |
| 47 |
2/2✓ Branch 1 taken 25304 times.
✓ Branch 2 taken 23412 times.
|
48716 | if (comp[i] == Equality) { |
| 48 | 25304 | ++size; | |
| 49 | } | ||
| 50 | } | ||
| 51 | 9604 | return size; | |
| 52 | } | ||
| 53 | |||
| 54 | ✗ | void Implicit::rightHandSideFunction(const DifferentiableFunctionPtr_t& rhsF) { | |
| 55 | ✗ | if (rhsF) { | |
| 56 | ✗ | if (rhsF->inputSize() != 1 || rhsF->inputDerivativeSize() != 1) { | |
| 57 | ✗ | HPP_THROW(std::invalid_argument, | |
| 58 | "Right hand side functions must take" | ||
| 59 | "only one real value as input. Got " | ||
| 60 | << rhsF->inputSize() << " and " | ||
| 61 | << rhsF->inputDerivativeSize()); | ||
| 62 | } | ||
| 63 | ✗ | if (*rhsF->outputSpace() != *function_->outputSpace()) { | |
| 64 | ✗ | HPP_THROW(std::invalid_argument, | |
| 65 | "The right hand side function output" | ||
| 66 | " space (" | ||
| 67 | << *rhsF->outputSpace() | ||
| 68 | << ") differs from the function" | ||
| 69 | " output space (" | ||
| 70 | << *function_->outputSpace() << ")."); | ||
| 71 | } | ||
| 72 | // Check that the right hand side is non-constant on all axis. | ||
| 73 | ✗ | for (std::size_t i = 0; i < comparison_.size(); ++i) { | |
| 74 | ✗ | if (comparison_[i] != constraints::Equality) { | |
| 75 | ✗ | HPP_THROW(std::invalid_argument, | |
| 76 | "The comparison type of implicit " | ||
| 77 | "constraint with right hand side function should be Equality " | ||
| 78 | "on all dimensions."); | ||
| 79 | } | ||
| 80 | } | ||
| 81 | } | ||
| 82 | |||
| 83 | ✗ | rhsFunction_ = rhsF; | |
| 84 | } | ||
| 85 | |||
| 86 | ✗ | vectorIn_t Implicit::rightHandSideAt(const value_type& s) { | |
| 87 | ✗ | if (rhsFunction_) { | |
| 88 | ✗ | vector_t S(1); | |
| 89 | ✗ | S[0] = s; | |
| 90 | ✗ | rhsFunction_->value(output_, S); | |
| 91 | } | ||
| 92 | ✗ | return output_.vector(); | |
| 93 | } | ||
| 94 | |||
| 95 | ✗ | size_type Implicit::parameterSize() const { return parameterSize_; } | |
| 96 | |||
| 97 | 12 | size_type Implicit::rightHandSideSize() const { | |
| 98 | 12 | return function_->outputSpace()->nq(); | |
| 99 | } | ||
| 100 | 94136 | const ComparisonTypes_t& Implicit::comparisonType() const { | |
| 101 | 94136 | return comparison_; | |
| 102 | } | ||
| 103 | |||
| 104 | 6402 | void Implicit::comparisonType(const ComparisonTypes_t& comp) { | |
| 105 | 6402 | comparison_ = comp; | |
| 106 | 6402 | parameterSize_ = computeParameterSize(comparison_); | |
| 107 | 6402 | computeIndices(); | |
| 108 | 6402 | } | |
| 109 | |||
| 110 | 25931 | void Implicit::setInactiveRowsToZero(vectorOut_t error) const { | |
| 111 |
1/2✓ Branch 2 taken 25931 times.
✗ Branch 3 not taken.
|
25931 | inactiveRows_.lview(error).setZero(); |
| 112 | 25931 | } | |
| 113 | |||
| 114 | 3199 | Implicit::Implicit(const DifferentiableFunctionPtr_t& function, | |
| 115 | 3199 | ComparisonTypes_t comp, std::vector<bool> mask) | |
| 116 | 3199 | : comparison_(comp), | |
| 117 |
2/4✓ Branch 3 taken 3199 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 3199 times.
✗ Branch 7 not taken.
|
3199 | rhs_(vector_t::Zero(function->outputSize())), |
| 118 |
1/2✓ Branch 1 taken 3199 times.
✗ Branch 2 not taken.
|
3199 | parameterSize_(computeParameterSize(comparison_)), |
| 119 | 3199 | function_(function), | |
| 120 |
1/2✓ Branch 1 taken 3199 times.
✗ Branch 2 not taken.
|
3199 | mask_(mask), |
| 121 | 3199 | activeRows_(), | |
| 122 |
1/2✓ Branch 1 taken 3199 times.
✗ Branch 2 not taken.
|
3199 | inactiveRows_(), |
| 123 | 3199 | inequalityIndices_(), | |
| 124 |
1/2✓ Branch 1 taken 3199 times.
✗ Branch 2 not taken.
|
3199 | equalityIndices_(), |
| 125 |
1/2✓ Branch 3 taken 3199 times.
✗ Branch 4 not taken.
|
3199 | output_(function->outputSpace()), |
| 126 |
1/2✓ Branch 8 taken 3199 times.
✗ Branch 9 not taken.
|
12796 | logOutput_(function->outputSpace()->nv()) |
| 127 | |||
| 128 | { | ||
| 129 | // This constructor used to set comparison types to Equality if an | ||
| 130 | // empty vector was given as input. Now you should provide the | ||
| 131 | // comparison type at construction. | ||
| 132 |
1/2✗ Branch 3 not taken.
✓ Branch 4 taken 3199 times.
|
3199 | assert(function_->outputDerivativeSize() == (size_type)comparison_.size()); |
| 133 |
1/2✗ Branch 3 not taken.
✓ Branch 4 taken 3199 times.
|
3199 | assert(function_->outputDerivativeSize() == (size_type)mask.size()); |
| 134 |
1/2✓ Branch 1 taken 3199 times.
✗ Branch 2 not taken.
|
3199 | computeActiveRows(); |
| 135 |
1/2✓ Branch 1 taken 3199 times.
✗ Branch 2 not taken.
|
3199 | computeIndices(); |
| 136 | 3199 | } | |
| 137 | |||
| 138 | // Compute active rows | ||
| 139 | 4253 | void Implicit::computeActiveRows() { | |
| 140 | 4253 | segments_t inactiveRows; | |
| 141 |
2/2✓ Branch 1 taken 20459 times.
✓ Branch 2 taken 4253 times.
|
24712 | for (std::size_t i = 0; i < mask_.size(); ++i) { |
| 142 |
3/4✓ Branch 1 taken 20459 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20426 times.
✓ Branch 5 taken 33 times.
|
20459 | if (mask_[i]) |
| 143 |
1/2✓ Branch 2 taken 20426 times.
✗ Branch 3 not taken.
|
20426 | activeRows_.push_back(segment_t(i, 1)); |
| 144 | else | ||
| 145 |
1/2✓ Branch 2 taken 33 times.
✗ Branch 3 not taken.
|
33 | inactiveRows.push_back(segment_t(i, 1)); |
| 146 | } | ||
| 147 |
1/2✓ Branch 1 taken 4253 times.
✗ Branch 2 not taken.
|
4253 | Eigen::BlockIndex::shrink(activeRows_); |
| 148 |
1/2✓ Branch 1 taken 4253 times.
✗ Branch 2 not taken.
|
4253 | Eigen::BlockIndex::shrink(inactiveRows); |
| 149 |
2/4✓ Branch 1 taken 4253 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4253 times.
✗ Branch 5 not taken.
|
4253 | inactiveRows_ = Eigen::RowBlockIndices(inactiveRows); |
| 150 | 4253 | } | |
| 151 | |||
| 152 | 10655 | void Implicit::computeIndices() { | |
| 153 | 10655 | inequalityIndices_.clear(); | |
| 154 | 10655 | equalityIndices_.clearRows(); | |
| 155 |
2/2✓ Branch 1 taken 58861 times.
✓ Branch 2 taken 10655 times.
|
69516 | for (std::size_t i = 0; i < comparison_.size(); ++i) { |
| 156 |
6/6✓ Branch 1 taken 58843 times.
✓ Branch 2 taken 18 times.
✓ Branch 4 taken 27 times.
✓ Branch 5 taken 58816 times.
✓ Branch 6 taken 45 times.
✓ Branch 7 taken 58816 times.
|
58861 | if ((comparison_[i] == Superior) || (comparison_[i] == Inferior)) { |
| 157 |
1/2✓ Branch 1 taken 45 times.
✗ Branch 2 not taken.
|
45 | inequalityIndices_.push_back((size_type)i); |
| 158 |
2/2✓ Branch 1 taken 31380 times.
✓ Branch 2 taken 27436 times.
|
58816 | } else if (comparison_[i] == Equality) { |
| 159 |
1/2✓ Branch 1 taken 31380 times.
✗ Branch 2 not taken.
|
31380 | equalityIndices_.addRow((size_type)i, 1); |
| 160 | } | ||
| 161 | } | ||
| 162 | 10655 | equalityIndices_.updateRows<true, true, true>(); | |
| 163 | 10655 | } | |
| 164 | |||
| 165 | 19 | Implicit::Implicit(const Implicit& other) | |
| 166 | 19 | : comparison_(other.comparison_), | |
| 167 |
1/2✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
|
19 | rhs_(other.rhs_), |
| 168 | 19 | parameterSize_(other.parameterSize_), | |
| 169 | 19 | function_(other.function_), | |
| 170 | 19 | rhsFunction_(other.rhsFunction_), | |
| 171 |
1/2✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
|
19 | mask_(other.mask_), |
| 172 |
1/2✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
|
19 | activeRows_(other.activeRows_), |
| 173 |
1/2✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
|
19 | inactiveRows_(other.inactiveRows_), |
| 174 |
1/2✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
|
19 | inequalityIndices_(other.inequalityIndices_), |
| 175 |
1/2✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
|
19 | equalityIndices_(other.equalityIndices_), |
| 176 |
1/2✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
|
19 | output_(other.output_), |
| 177 |
1/2✓ Branch 3 taken 19 times.
✗ Branch 4 not taken.
|
57 | logOutput_(other.logOutput_) |
| 178 | |||
| 179 | 19 | {} | |
| 180 | |||
| 181 | 2190 | bool Implicit::isEqual(const Implicit& other, bool swapAndTest) const { | |
| 182 |
2/2✓ Branch 1 taken 80 times.
✓ Branch 2 taken 2110 times.
|
2190 | if (comparison_ != other.comparison_) return false; |
| 183 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 2110 times.
|
2110 | if (rhs_.size() != other.rhs_.size()) return false; |
| 184 |
5/6✓ Branch 1 taken 20 times.
✓ Branch 2 taken 2090 times.
✓ Branch 6 taken 20 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 20 times.
✓ Branch 9 taken 2090 times.
|
2110 | if (function_ != other.function_ && *function_ != *other.function_) |
| 185 | 20 | return false; | |
| 186 |
2/2✓ Branch 0 taken 1055 times.
✓ Branch 1 taken 1035 times.
|
2090 | if (swapAndTest) return other.isEqual(*this, false); |
| 187 | 1035 | return true; | |
| 188 | } | ||
| 189 | |||
| 190 | 1066 | ImplicitPtr_t Implicit::create(const DifferentiableFunctionPtr_t& function, | |
| 191 | ComparisonTypes_t comp, std::vector<bool> mask) { | ||
| 192 |
2/2✓ Branch 1 taken 1053 times.
✓ Branch 2 taken 13 times.
|
1066 | if (mask.empty()) { |
| 193 |
1/2✓ Branch 6 taken 1053 times.
✗ Branch 7 not taken.
|
1053 | mask = std::vector<bool>(function->outputSpace()->nv(), true); |
| 194 | } | ||
| 195 |
4/8✓ Branch 1 taken 1066 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1066 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1066 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1066 times.
✗ Branch 11 not taken.
|
1066 | Implicit* ptr = new Implicit(function, comp, mask); |
| 196 |
1/2✓ Branch 1 taken 1066 times.
✗ Branch 2 not taken.
|
1066 | ImplicitPtr_t shPtr(ptr); |
| 197 | 1066 | ImplicitWkPtr_t wkPtr(shPtr); | |
| 198 | 1066 | ptr->init(wkPtr); | |
| 199 | 2132 | return shPtr; | |
| 200 | 1066 | } | |
| 201 | |||
| 202 | 7 | ImplicitPtr_t Implicit::createCopy(const ImplicitPtr_t& other) { | |
| 203 |
2/4✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 7 times.
✗ Branch 6 not taken.
|
7 | Implicit* ptr = new Implicit(*other); |
| 204 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | ImplicitPtr_t shPtr(ptr); |
| 205 | 7 | ImplicitWkPtr_t wkPtr(shPtr); | |
| 206 | 7 | ptr->init(wkPtr); | |
| 207 | 14 | return shPtr; | |
| 208 | 7 | } | |
| 209 | |||
| 210 |
1/2✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
|
14 | ImplicitPtr_t Implicit::copy() const { return createCopy(weak_.lock()); } |
| 211 | |||
| 212 | 3606 | void Implicit::rightHandSideFromConfig(ConfigurationIn_t config, | |
| 213 | LiegroupElementRef rhs) { | ||
| 214 |
2/4✓ Branch 6 taken 3606 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 3606 times.
|
3606 | assert(*rhs.space() == *function_->outputSpace()); |
| 215 |
2/4✓ Branch 3 taken 3606 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 3606 times.
✗ Branch 7 not taken.
|
3606 | function_->value(output_, config); |
| 216 | 3606 | logOutput_.setZero(); | |
| 217 |
3/6✓ Branch 2 taken 3606 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 3606 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 3606 times.
✗ Branch 9 not taken.
|
3606 | equalityIndices_.lview(logOutput_) = equalityIndices_.rview(log(output_)); |
| 218 | // rhs = exp(logOutput_) | ||
| 219 |
2/4✓ Branch 4 taken 3606 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3606 times.
✗ Branch 8 not taken.
|
3606 | rhs = rhs.space()->exp(logOutput_); |
| 220 | 3606 | } | |
| 221 | |||
| 222 | 2101 | bool Implicit::checkRightHandSide(LiegroupElementConstRef rhs) const { | |
| 223 |
1/2✗ Branch 5 not taken.
✓ Branch 6 taken 2101 times.
|
2101 | if (rhs.space() != function_->outputSpace()) return false; |
| 224 | 2101 | logOutput_ = log(rhs); | |
| 225 |
2/2✓ Branch 1 taken 16601 times.
✓ Branch 2 taken 2101 times.
|
18702 | for (std::size_t i = 0; i < comparison_.size(); ++i) |
| 226 |
4/6✓ Branch 1 taken 7000 times.
✓ Branch 2 taken 9601 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 7000 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 16601 times.
|
16601 | if ((comparison_[i] != Equality) && (logOutput_[i] != 0)) return false; |
| 227 | |||
| 228 | 2101 | return true; | |
| 229 | } | ||
| 230 | |||
| 231 | std::pair<JointConstPtr_t, JointConstPtr_t> | ||
| 232 | 9 | Implicit::doesConstrainRelPoseBetween(DeviceConstPtr_t robot) const { | |
| 233 | std::pair<JointConstPtr_t, JointConstPtr_t> joints = | ||
| 234 |
1/2✓ Branch 3 taken 9 times.
✗ Branch 4 not taken.
|
9 | function_->dependsOnRelPoseBetween(robot); |
| 235 | // check that the constraint fully constrains the relative pose | ||
| 236 |
8/12✓ Branch 4 taken 5 times.
✓ Branch 5 taken 4 times.
✓ Branch 7 taken 5 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 2 times.
✓ Branch 10 taken 3 times.
✓ Branch 11 taken 9 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 6 times.
✓ Branch 15 taken 3 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
|
9 | if (function_->outputSpace()->nv() != 6 || !checkAllRowsActive()) { |
| 237 | hppDout( | ||
| 238 | info, "Constraint " | ||
| 239 | << function_->name() | ||
| 240 | << " does not fully constrain the relative pose of joints"); | ||
| 241 | 6 | return std::pair<JointConstPtr_t, JointConstPtr_t>(nullptr, nullptr); | |
| 242 | } | ||
| 243 | 3 | return joints; | |
| 244 | 9 | } | |
| 245 | |||
| 246 | template <class Archive> | ||
| 247 | 12 | void Implicit::serialize(Archive& ar, const unsigned int version) { | |
| 248 | (void)version; | ||
| 249 |
1/2✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
|
12 | ar& BOOST_SERIALIZATION_NVP(comparison_); |
| 250 |
1/2✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
|
12 | ar& BOOST_SERIALIZATION_NVP(rhs_); |
| 251 | if (!Archive::is_saving::value) | ||
| 252 | 6 | parameterSize_ = computeParameterSize(comparison_); | |
| 253 |
1/2✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
|
12 | ar& BOOST_SERIALIZATION_NVP(function_); |
| 254 |
1/2✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
|
12 | ar& BOOST_SERIALIZATION_NVP(rhsFunction_); |
| 255 |
1/2✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
|
12 | ar& BOOST_SERIALIZATION_NVP(mask_); |
| 256 |
1/2✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
|
12 | ar& BOOST_SERIALIZATION_NVP(weak_); |
| 257 | if (!Archive::is_saving::value) { | ||
| 258 | 6 | computeActiveRows(); | |
| 259 | 6 | computeIndices(); | |
| 260 | } | ||
| 261 | } | ||
| 262 | |||
| 263 | HPP_SERIALIZATION_IMPLEMENT(Implicit); | ||
| 264 | } // namespace constraints | ||
| 265 | } // namespace hpp | ||
| 266 |