Directory: | ./ |
---|---|
File: | include/hpp/constraints/solver/impl/by-substitution.hh |
Date: | 2025-05-05 12:19:30 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 55 | 69 | 79.7% |
Branches: | 58 | 134 | 43.3% |
Line | Branch | Exec | Source |
---|---|---|---|
1 | // Copyright (c) 2017, Joseph Mirabel | ||
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 | #ifndef HPP_CONSTRAINTS_SOLVER_IMPL_BY_SUBSTITUTION_HH | ||
30 | #define HPP_CONSTRAINTS_SOLVER_IMPL_BY_SUBSTITUTION_HH | ||
31 | |||
32 | namespace hpp { | ||
33 | namespace constraints { | ||
34 | namespace solver { | ||
35 | typedef std::numeric_limits<value_type> numeric_limits; | ||
36 | typedef Eigen::NumTraits<value_type> NumTraits; | ||
37 | |||
38 | template <typename LineSearchType> | ||
39 | 3294 | inline HierarchicalIterative::Status BySubstitution::impl_solve( | |
40 | vectorOut_t arg, bool _optimize, LineSearchType lineSearch) const { | ||
41 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 1647 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
3294 | bool optimize = _optimize && lastIsOptional_; |
42 |
2/4✓ Branch 1 taken 1647 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1647 times.
|
3294 | assert(!arg.hasNaN()); |
43 | |||
44 |
2/4✓ Branch 1 taken 1647 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1647 times.
✗ Branch 5 not taken.
|
3294 | explicit_.solve(arg); |
45 |
2/4✓ Branch 1 taken 1647 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1647 times.
|
3294 | assert(!arg.hasNaN()); |
46 | |||
47 | 3294 | size_type errorDecreased = 3, iter = 0; | |
48 | value_type previousSquaredNorm; | ||
49 | static const value_type dqMinSquaredNorm = NumTraits::dummy_precision(); | ||
50 | 3294 | value_type initSquaredNorm = 0; | |
51 | |||
52 | // Variables for optimization only | ||
53 | 3294 | value_type previousCost = 0; | |
54 | 3294 | value_type scaling = 1.; | |
55 | 3294 | bool onlyLineSearch = false; | |
56 |
1/2✓ Branch 1 taken 1647 times.
✗ Branch 2 not taken.
|
3294 | vector_t qopt; |
57 | |||
58 | // Fill value and Jacobian | ||
59 |
2/4✓ Branch 1 taken 1647 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1647 times.
✗ Branch 5 not taken.
|
3294 | computeValue<true>(arg); |
60 |
1/2✓ Branch 1 taken 1647 times.
✗ Branch 2 not taken.
|
3294 | computeError(); |
61 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 1647 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
3294 | if (optimize) previousCost = datas_.back().error.squaredNorm(); |
62 | |||
63 | 3294 | bool errorWasBelowThr = (squaredNorm_ < squaredErrorThreshold_); | |
64 |
1/2✓ Branch 1 taken 1647 times.
✗ Branch 2 not taken.
|
3294 | vector_t initArg; |
65 |
2/2✓ Branch 0 taken 501 times.
✓ Branch 1 taken 1146 times.
|
3294 | if (errorWasBelowThr) { |
66 |
1/2✓ Branch 1 taken 501 times.
✗ Branch 2 not taken.
|
1002 | initArg = arg; |
67 |
1/2✓ Branch 0 taken 501 times.
✗ Branch 1 not taken.
|
1002 | if (!optimize) iter = std::max(maxIterations_, size_type(2)) - 2; |
68 | 1002 | initSquaredNorm = squaredNorm_; | |
69 | } | ||
70 | |||
71 | 3294 | bool errorIsAboveThr = (squaredNorm_ > .25 * squaredErrorThreshold_); | |
72 |
3/4✓ Branch 0 taken 1146 times.
✓ Branch 1 taken 501 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1146 times.
|
3294 | if (errorIsAboveThr && reducedDimension_ == 0) return INFEASIBLE; |
73 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 1647 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
|
3294 | if (optimize && !errorIsAboveThr) qopt = arg; |
74 | |||
75 | 3294 | Status status = SUCCESS; | |
76 |
5/6✗ Branch 0 not taken.
✓ Branch 1 taken 15037 times.
✓ Branch 2 taken 13427 times.
✓ Branch 3 taken 1610 times.
✓ Branch 4 taken 13426 times.
✓ Branch 5 taken 1 times.
|
30074 | while ((optimize || (errorIsAboveThr && errorDecreased))) { |
77 | // 1. Maximum iterations | ||
78 |
2/2✓ Branch 0 taken 36 times.
✓ Branch 1 taken 13390 times.
|
26852 | if (iter >= maxIterations_) { |
79 | 72 | status = MAX_ITERATION_REACHED; | |
80 | 72 | break; | |
81 | } | ||
82 | 26780 | status = SUCCESS; | |
83 | |||
84 | // 2. Compute step | ||
85 | // onlyLineSearch is true when we only reduced the scaling. | ||
86 |
1/2✓ Branch 0 taken 13390 times.
✗ Branch 1 not taken.
|
26780 | if (!onlyLineSearch) { |
87 | 26780 | previousSquaredNorm = squaredNorm_; | |
88 | // Update the jacobian using the jacobian of the explicit system. | ||
89 |
2/4✓ Branch 1 taken 13390 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 13390 times.
✗ Branch 5 not taken.
|
26780 | updateJacobian(arg); |
90 |
2/4✓ Branch 1 taken 13390 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 13390 times.
✗ Branch 5 not taken.
|
26780 | computeSaturation(arg); |
91 |
1/2✓ Branch 1 taken 13390 times.
✗ Branch 2 not taken.
|
26780 | computeDescentDirection(); |
92 | } | ||
93 | // Apply scaling to avoid too large steps. | ||
94 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 13390 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
26780 | if (optimize) dq_ *= scaling; |
95 |
2/4✓ Branch 1 taken 13390 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 13390 times.
|
26780 | if (dq_.squaredNorm() < dqMinSquaredNorm) { |
96 | // We assume that the algorithm reached a local minima. | ||
97 | ✗ | status = INFEASIBLE; | |
98 | ✗ | break; | |
99 | } | ||
100 | // 3. Apply line search algorithm for the computed step | ||
101 |
3/6✓ Branch 1 taken 13390 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 13390 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 13390 times.
✗ Branch 8 not taken.
|
26780 | lineSearch(*this, arg, dq_); |
102 |
2/4✓ Branch 1 taken 13390 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 13390 times.
✗ Branch 5 not taken.
|
26780 | explicit_.solve(arg); |
103 |
2/4✓ Branch 1 taken 13390 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 13390 times.
|
26780 | assert(!arg.hasNaN()); |
104 | |||
105 | // 4. Evaluate the error at the new point. | ||
106 |
2/4✓ Branch 1 taken 13390 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 13390 times.
✗ Branch 5 not taken.
|
26780 | computeValue<true>(arg); |
107 |
1/2✓ Branch 1 taken 13390 times.
✗ Branch 2 not taken.
|
26780 | computeError(); |
108 | |||
109 | 26780 | --errorDecreased; | |
110 |
2/2✓ Branch 0 taken 13377 times.
✓ Branch 1 taken 13 times.
|
26780 | if (squaredNorm_ < previousSquaredNorm) |
111 | 26754 | errorDecreased = 3; | |
112 | else | ||
113 | 26 | status = ERROR_INCREASED; | |
114 | |||
115 | 26780 | errorIsAboveThr = (squaredNorm_ > .25 * squaredErrorThreshold_); | |
116 | // 5. In case of optimization, | ||
117 | // - if the constraints is satisfied and the cost decreased, increase | ||
118 | // the scaling (amount of confidence in the linear approximation) | ||
119 | // - if the constraints is not satisfied, decrease the scaling and | ||
120 | // and cancel this step. | ||
121 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13390 times.
|
26780 | if (optimize) { |
122 | ✗ | if (!errorIsAboveThr) { | |
123 | ✗ | value_type cost = datas_.back().error.squaredNorm(); | |
124 | ✗ | if (cost < previousCost) { | |
125 | ✗ | qopt = arg; | |
126 | ✗ | previousCost = cost; | |
127 | ✗ | if (scaling < 0.5) scaling *= 2; | |
128 | } | ||
129 | ✗ | onlyLineSearch = false; | |
130 | } else { | ||
131 | ✗ | dq_ /= scaling; | |
132 | ✗ | scaling *= 0.5; | |
133 | ✗ | if (qopt.size() > 0) arg = qopt; | |
134 | ✗ | onlyLineSearch = true; | |
135 | } | ||
136 | } | ||
137 | |||
138 | 26780 | ++iter; | |
139 | } | ||
140 | |||
141 |
3/4✓ Branch 0 taken 1647 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 501 times.
✓ Branch 3 taken 1146 times.
|
3294 | if (!optimize && errorWasBelowThr) { |
142 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 501 times.
|
1002 | if (squaredNorm_ > initSquaredNorm) { |
143 | ✗ | arg = initArg; | |
144 | } | ||
145 | 1002 | return SUCCESS; | |
146 | } | ||
147 | // If optimizing, qopt is the visited configuration that satisfies the | ||
148 | // constraints and has lowest cost. | ||
149 |
2/8✗ Branch 0 not taken.
✓ Branch 1 taken 1146 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 1146 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
|
2292 | if (optimize && qopt.size() > 0) arg = qopt; |
150 | |||
151 |
2/4✓ Branch 1 taken 1146 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1146 times.
|
2292 | assert(!arg.hasNaN()); |
152 | 2292 | return status; | |
153 | 3294 | } | |
154 | } // namespace solver | ||
155 | } // namespace constraints | ||
156 | } // namespace hpp | ||
157 | |||
158 | #endif // HPP_CONSTRAINTS_SOLVER_IMPL_BY_SUBSTITUTION_HH | ||
159 |