GCC Code Coverage Report


Directory: ./
File: src/graph/validation.cc
Date: 2025-03-07 11:10:46
Exec Total Coverage
Lines: 0 105 0.0%
Branches: 0 243 0.0%

Line Branch Exec Source
1 // Copyright (c) 2019, 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/manipulation/graph/validation.hh"
30
31 #include <hpp/constraints/differentiable-function.hh>
32 #include <hpp/core/collision-validation-report.hh>
33 #include <hpp/core/collision-validation.hh>
34 #include <hpp/core/configuration-shooter.hh>
35 #include <hpp/core/relative-motion.hh>
36 #include <hpp/util/indent.hh>
37 #include <sstream>
38
39 #include "hpp/manipulation/graph/edge.hh"
40 #include "hpp/manipulation/graph/state-selector.hh"
41 #include "hpp/manipulation/graph/state.hh"
42 #include "hpp/manipulation/problem.hh"
43
44 namespace hpp {
45 namespace manipulation {
46 namespace graph {
47 bool stateAIncludedInStateB(const StatePtr_t& A, const StatePtr_t& B) {
48 const NumericalConstraints_t& Ancs = A->numericalConstraints();
49 const NumericalConstraints_t& Bncs = B->numericalConstraints();
50 for (NumericalConstraints_t::const_iterator _nc = Bncs.begin();
51 _nc != Bncs.end(); ++_nc)
52 if (std::find(Ancs.begin(), Ancs.end(), *_nc) == Ancs.end()) return false;
53 return true;
54 }
55
56 std::ostream& Validation::print(std::ostream& os) const {
57 for (std::size_t i = 0; i < warnings_.size(); ++i) {
58 os << "Warning " << i << " ("
59 << (warnings_[i].first ? warnings_[i].first->name() : "no component")
60 << ')' << incendl << warnings_[i].second << decendl;
61 }
62 for (std::size_t i = 0; i < errors_.size(); ++i) {
63 os << "Error " << i << " ("
64 << (errors_[i].first ? errors_[i].first->name() : "no component") << ')'
65 << incendl << errors_[i].second << decendl;
66 }
67 return os;
68 }
69
70 bool Validation::validate(const GraphComponentPtr_t& comp) {
71 if (HPP_DYNAMIC_PTR_CAST(State, comp))
72 return validateState(HPP_DYNAMIC_PTR_CAST(State, comp));
73 else if (HPP_DYNAMIC_PTR_CAST(Edge, comp))
74 return validateEdge(HPP_DYNAMIC_PTR_CAST(Edge, comp));
75 else if (HPP_DYNAMIC_PTR_CAST(Graph, comp))
76 return validateGraph(HPP_DYNAMIC_PTR_CAST(Graph, comp));
77 else
78 return true;
79 }
80
81 bool Validation::validateState(const StatePtr_t& state) {
82 bool success = true;
83
84 // 1. Check that all the constraint are not parameterizable.
85 const NumericalConstraints_t& ncs = state->numericalConstraints();
86 for (NumericalConstraints_t::const_iterator _nc = ncs.begin();
87 _nc != ncs.end(); ++_nc)
88 if ((*_nc)->parameterSize() > 0) {
89 std::ostringstream oss;
90 oss << incindent << "Constraint " << (*_nc)->function().name()
91 << " has a varying right hand side while constraints of a state must"
92 " have a constant one.";
93 addError(state, oss.str());
94 }
95
96 // 2. try to generate a configuration in this state.
97 bool projOk;
98 Configuration_t q;
99 std::size_t i, Nrand = 100;
100
101 for (i = 0; i < Nrand; i++) {
102 problem_->configurationShooter()->shoot(q);
103 projOk = state->configConstraint()->apply(q);
104 if (projOk) break;
105 }
106 if (!projOk) {
107 std::ostringstream oss;
108 oss << incindent << "Failed to apply the constraints to " << Nrand
109 << "random configurations.";
110 addError(state, oss.str());
111 return false;
112 }
113 if (4 * i > 3 * Nrand) {
114 std::ostringstream oss;
115 oss << incindent << "Success rate of constraint projection is " << i / Nrand
116 << '.';
117 addWarning(state, oss.str());
118 oss.clear();
119 }
120
121 // 3. check the collision pairs which will be disabled because of the
122 // constraint.
123 core::CollisionValidationPtr_t colValidation(
124 core::CollisionValidation::create(problem_->robot()));
125 for (std::size_t i = 0; i < problem_->collisionObstacles().size(); ++i)
126 colValidation->addObstacle(problem_->collisionObstacles()[i]);
127 colValidation->computeAllContacts(true);
128
129 typedef core::RelativeMotion RelativeMotion;
130 RelativeMotion::matrix_type relMotion =
131 RelativeMotion::matrix(problem_->robot());
132 RelativeMotion::fromConstraint(relMotion, problem_->robot(),
133 state->configConstraint());
134
135 // Invert the relative motions.
136 hppDout(info, "Relative motion matrix:\n" << relMotion);
137 for (size_type r = 0; r < relMotion.rows(); ++r)
138 for (size_type c = 0; c < r; ++c) {
139 if (relMotion(r, c) != relMotion(c, r)) {
140 hppDout(error, "Relative motion matrix not symmetric.");
141 }
142 switch (relMotion(r, c)) {
143 case RelativeMotion::Constrained:
144 relMotion(r, c) = relMotion(c, r) = RelativeMotion::Unconstrained;
145 break;
146 case RelativeMotion::Parameterized:
147 case RelativeMotion::Unconstrained:
148 relMotion(r, c) = relMotion(c, r) = RelativeMotion::Constrained;
149 break;
150 default:
151 throw std::logic_error("Relative motion not understood");
152 }
153 }
154 hppDout(info, "Relative motion matrix:\n" << relMotion);
155
156 colValidation->filterCollisionPairs(relMotion);
157 core::ValidationReportPtr_t colReport;
158 bool colOk = colValidation->validate(q, colReport);
159
160 if (!colOk) {
161 std::ostringstream oss;
162 oss << incindent
163 << "The following collision pairs will always "
164 "collide."
165 << incendl << *colReport << decindent;
166 addError(state, oss.str());
167 if (HPP_DYNAMIC_PTR_CAST(core::CollisionValidationReport, colReport)) {
168 std::pair<std::string, std::string> names =
169 HPP_DYNAMIC_PTR_CAST(core::CollisionValidationReport, colReport)
170 ->getObjectNames();
171 addCollision(state, names.first, names.second);
172 }
173 success = false;
174 }
175
176 return success;
177 }
178
179 bool Validation::validateEdge(const EdgePtr_t&) { return true; }
180
181 bool Validation::validateGraph(const GraphPtr_t& graph) {
182 if (!graph) return false;
183 bool success = true;
184
185 for (std::size_t i = 1; i < graph->nbComponents(); ++i)
186 if (!validate(graph->get(i).lock())) success = false;
187
188 // Check that no state is included in a state which has a higher priority.
189 States_t states = graph->stateSelector()->getStates();
190 for (States_t::const_iterator _state = states.begin(); _state != states.end();
191 ++_state) {
192 for (States_t::const_iterator _stateHO = states.begin(); _stateHO != _state;
193 ++_stateHO) {
194 if (stateAIncludedInStateB(*_state, *_stateHO)) {
195 std::ostringstream oss;
196 oss << "State " << (*_state)->name() << " is included in state "
197 << (*_stateHO)->name() << " but the latter has a higher priority.";
198 addError(*_state, oss.str());
199 success = false;
200 }
201 }
202 }
203
204 return success;
205 }
206 } // namespace graph
207 } // namespace manipulation
208 } // namespace hpp
209