GCC Code Coverage Report


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

Line Branch Exec Source
1 // Copyright (c) 2014, 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-path-validation.hh"
30
31 #include <hpp/core/path-vector.hh>
32 #include <hpp/core/path.hh>
33 #include <hpp/manipulation/constraint-set.hh>
34 #include <hpp/manipulation/graph/edge.hh>
35 #include <hpp/manipulation/graph/graph.hh>
36 #include <hpp/manipulation/graph/state.hh>
37 #include <hpp/pinocchio/configuration.hh>
38
39 #ifdef HPP_DEBUG
40 #include <hpp/manipulation/graph/state.hh>
41 #endif
42
43 namespace hpp {
44 namespace manipulation {
45 GraphPathValidationPtr_t GraphPathValidation::create(
46 const PathValidationPtr_t& pathValidation) {
47 GraphPathValidation* p = new GraphPathValidation(pathValidation);
48 return GraphPathValidationPtr_t(p);
49 }
50
51 GraphPathValidation::GraphPathValidation(
52 const PathValidationPtr_t& pathValidation)
53 : pathValidation_(pathValidation), constraintGraph_() {}
54
55 bool GraphPathValidation::validate(const PathPtr_t& path, bool reverse,
56 PathPtr_t& validPart,
57 PathValidationReportPtr_t& report) {
58 assert(path);
59 bool success = impl_validate(path, reverse, validPart, report);
60 assert(constraintGraph_);
61 assert(constraintGraph_->getState(validPart->initial()));
62 assert(constraintGraph_->getState(validPart->end()));
63 return success;
64 }
65
66 bool GraphPathValidation::impl_validate(const PathVectorPtr_t& path,
67 bool reverse, PathPtr_t& validPart,
68 PathValidationReportPtr_t& report) {
69 PathPtr_t validSubPart;
70 if (reverse) {
71 // TODO: This has never been tested.
72 assert(!reverse && "This has never been tested with reverse path");
73 for (long int i = path->numberPaths() - 1; i >= 0; i--) {
74 // We should stop at the first non valid subpath.
75 if (!impl_validate(path->pathAtRank(i), true, validSubPart, report)) {
76 PathVectorPtr_t p = PathVector::create(path->outputSize(),
77 path->outputDerivativeSize());
78 for (long int v = path->numberPaths() - 1; v > i; v--)
79 p->appendPath(path->pathAtRank(i)->copy());
80 // TODO: Make sure this subpart is generated by the steering method.
81 p->appendPath(validSubPart);
82 validPart = p;
83 return false;
84 }
85 }
86 } else {
87 for (size_t i = 0; i != path->numberPaths(); i++) {
88 // We should stop at the first non valid subpath.
89 if (!impl_validate(path->pathAtRank(i), false, validSubPart, report)) {
90 PathVectorPtr_t p = PathVector::create(path->outputSize(),
91 path->outputDerivativeSize());
92 for (size_t v = 0; v < i; v++)
93 p->appendPath(path->pathAtRank(v)->copy());
94 // TODO: Make sure this subpart is generated by the steering method.
95 p->appendPath(validSubPart);
96 validPart = p;
97 return false;
98 }
99 }
100 }
101 // Here, every subpath is valid.
102 validPart = path;
103 return true;
104 }
105
106 bool GraphPathValidation::impl_validate(const PathPtr_t& path, bool reverse,
107 PathPtr_t& validPart,
108 PathValidationReportPtr_t& report) {
109 #ifndef NDEBUG
110 bool success;
111 Configuration_t q0 = path->eval(path->timeRange().second, success);
112 assert(success);
113 assert(!path->constraints() || path->constraints()->isSatisfied(q0));
114 #endif
115 using pinocchio::displayConfig;
116 PathVectorPtr_t pathVector = HPP_DYNAMIC_PTR_CAST(PathVector, path);
117 if (pathVector) return impl_validate(pathVector, reverse, validPart, report);
118
119 PathPtr_t pathNoCollision;
120 ConstraintSetPtr_t c =
121 HPP_DYNAMIC_PTR_CAST(ConstraintSet, path->constraints());
122 hppDout(info,
123 (c ? "Using edge path validation" : "Using default path validation"));
124 PathValidationPtr_t validation(c ? c->edge()->pathValidation()
125 : pathValidation_);
126
127 if (validation->validate(path, reverse, pathNoCollision, report)) {
128 validPart = path;
129 return true;
130 }
131 const Path& newPath(*pathNoCollision);
132 const Path& oldPath(*path);
133 const core::interval_t &newTR = newPath.timeRange(),
134 oldTR = oldPath.timeRange();
135 Configuration_t q(newPath.outputSize());
136 if (!newPath.eval(q, newTR.first))
137 throw std::logic_error(
138 "Initial configuration of the valid part cannot be projected.");
139 const graph::StatePtr_t& origState = constraintGraph_->getState(q);
140 if (!newPath.eval(q, newTR.second))
141 throw std::logic_error(
142 "End configuration of the valid part cannot be projected.");
143 // This may throw in the following case:
144 // - state constraints: object_placement + other_function
145 // - path constraints: other_function, object_lock
146 // This is semantically correct but for a path going from q0 to q1,
147 // we ensure that
148 // - object_placement (q0) = eps_place0
149 // - other_function (q0) = eps_other0
150 // - eps_place0 + eps_other0 < eps
151 // - other_function (q(s)) < eps
152 // - object_placement (q(s)) = object_placement (q0) # thanks to the
153 // object_lock So we only have:
154 // - other_function (q(s)) + object_placement (q(s)) < eps + eps_place0
155 // And not:
156 // - other_function (q(s)) + object_placement (q(s)) < eps
157 // In this case, there is no good way to recover. Just return failure.
158 graph::StatePtr_t destState;
159 try {
160 destState = constraintGraph_->getState(q);
161 } catch (const std::logic_error& e) {
162 ConstraintSetPtr_t c =
163 HPP_DYNAMIC_PTR_CAST(ConstraintSet, path->constraints());
164 hppDout(error, "Edge " << c->edge()->name()
165 << " generated an error: " << e.what());
166 hppDout(error,
167 "Likely, the constraints for paths are relaxed. If "
168 "this problem occurs often, you may want to use the same "
169 "constraints for state and paths in "
170 << c->edge()->state()->name());
171 validPart = path->extract(std::make_pair(oldTR.first, oldTR.first));
172 return false;
173 }
174 if (!oldPath.eval(q, oldTR.first)) {
175 std::stringstream oss;
176 oss << "Initial configuration of the path to be validated failed to"
177 " be projected. After maximal number of iterations, q="
178 << displayConfig(q) << "; error=";
179 vector_t error;
180 oldPath.constraints()->isSatisfied(q, error);
181 oss << displayConfig(error) << ".";
182 throw std::logic_error(oss.str().c_str());
183 }
184 const graph::StatePtr_t& oldOstate = constraintGraph_->getState(q);
185 if (!oldPath.eval(q, oldTR.second)) {
186 std::stringstream oss;
187 oss << "End configuration of the path to be validated failed to"
188 " be projected. After maximal number of iterations, q="
189 << displayConfig(q) << "; error=";
190 vector_t error;
191 oldPath.constraints()->isSatisfied(q, error);
192 oss << displayConfig(error) << ".";
193 throw std::logic_error(oss.str().c_str());
194 }
195 const graph::StatePtr_t& oldDstate = constraintGraph_->getState(q);
196
197 if (origState == oldOstate && destState == oldDstate) {
198 validPart = pathNoCollision;
199 return false;
200 }
201
202 // Here, the full path is not valid. Moreover, it does not correspond to the
203 // same edge of the constraint graph. Two option are possible:
204 // - Use the steering method to create a new path and validate it.
205 // - Return a null path.
206 // validPart = path->extract (std::make_pair (oldTR.first,oldTR.first));
207 validPart = pathNoCollision;
208 return false;
209 }
210 } // namespace manipulation
211 } // namespace hpp
212