|
| 1 | +/****************************************************************************** |
| 2 | +Copyright (c) 2020, Farbod Farshidian. All rights reserved. |
| 3 | +
|
| 4 | +Redistribution and use in source and binary forms, with or without |
| 5 | +modification, are permitted provided that the following conditions are met: |
| 6 | +
|
| 7 | +* Redistributions of source code must retain the above copyright notice, this |
| 8 | + list of conditions and the following disclaimer. |
| 9 | +
|
| 10 | +* Redistributions in binary form must reproduce the above copyright notice, |
| 11 | + this list of conditions and the following disclaimer in the documentation |
| 12 | + and/or other materials provided with the distribution. |
| 13 | +
|
| 14 | +* Neither the name of the copyright holder nor the names of its |
| 15 | + contributors may be used to endorse or promote products derived from |
| 16 | + this software without specific prior written permission. |
| 17 | +
|
| 18 | +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| 19 | +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 20 | +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| 21 | +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE |
| 22 | +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| 23 | +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| 24 | +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
| 25 | +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| 26 | +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 27 | +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 28 | +******************************************************************************/ |
| 29 | + |
| 30 | +#include <iostream> |
| 31 | + |
| 32 | +#include <gtest/gtest.h> |
| 33 | + |
| 34 | +#include <ocs2_ddp/DDP_HelperFunctions.h> |
| 35 | + |
| 36 | +using namespace ocs2; |
| 37 | + |
| 38 | +TEST(extractPrimalSolution, eventAtInitTime) { |
| 39 | + constexpr size_t numTime = 5; |
| 40 | + constexpr int numSubsystem = 4; |
| 41 | + constexpr scalar_t initTime = 0.0; |
| 42 | + constexpr scalar_t timeStep = 0.2; |
| 43 | + constexpr auto eps = numeric_traits::weakEpsilon<scalar_t>(); |
| 44 | + |
| 45 | + PrimalSolution primalSolution; |
| 46 | + for (int s = 0; s < numSubsystem - 1; ++s) { |
| 47 | + const auto t0 = (s == 0) ? initTime : primalSolution.timeTrajectory_.back(); |
| 48 | + const auto t0Biased = (s == 0) ? t0 : (t0 + eps); |
| 49 | + |
| 50 | + for (size_t n = 0; n <= numTime; ++n) { |
| 51 | + primalSolution.timeTrajectory_.push_back((n == 0) ? t0Biased : t0 + n * timeStep); |
| 52 | + primalSolution.stateTrajectory_.push_back((vector_t(1) << 1.0 + s).finished()); |
| 53 | + primalSolution.inputTrajectory_.push_back((vector_t(1) << -1.0 - s).finished()); |
| 54 | + } // end of n |
| 55 | + |
| 56 | + // there is an extra event at final time |
| 57 | + primalSolution.postEventIndices_.push_back(primalSolution.timeTrajectory_.size()); |
| 58 | + primalSolution.modeSchedule_.modeSequence.push_back(s + 1); |
| 59 | + primalSolution.modeSchedule_.eventTimes.push_back(primalSolution.timeTrajectory_.back()); |
| 60 | + } // end of s |
| 61 | + |
| 62 | + // an extra event at final time |
| 63 | + primalSolution.timeTrajectory_.push_back(primalSolution.timeTrajectory_.back()); |
| 64 | + primalSolution.stateTrajectory_.push_back((vector_t(1) << numSubsystem).finished()); |
| 65 | + primalSolution.inputTrajectory_.push_back((vector_t(1) << -numSubsystem).finished()); |
| 66 | + |
| 67 | + // std::cerr << ">>>>>> original\n" << primalSolution << "\n"; |
| 68 | + |
| 69 | + // test0: initial and final time events |
| 70 | + PrimalSolution PrimalSolutionTest0; |
| 71 | + const std::pair<scalar_t, scalar_t> timePeriodTest0{1.0, 2.0}; |
| 72 | + extractPrimalSolution(timePeriodTest0, primalSolution, PrimalSolutionTest0); |
| 73 | + // std::cerr << ">>>>>> Test 0\n" << PrimalSolutionTest0 << "\n"; |
| 74 | + EXPECT_NEAR(PrimalSolutionTest0.timeTrajectory_.front(), timePeriodTest0.first, 1.5 * eps); |
| 75 | + EXPECT_NEAR(PrimalSolutionTest0.timeTrajectory_.back(), timePeriodTest0.second, 1e-8); |
| 76 | + EXPECT_EQ(PrimalSolutionTest0.postEventIndices_, size_array_t{PrimalSolutionTest0.timeTrajectory_.size() - 1}); |
| 77 | + |
| 78 | + // test1: extracting the whole |
| 79 | + PrimalSolution PrimalSolutionTest1; |
| 80 | + const std::pair<scalar_t, scalar_t> timePeriodTest1{primalSolution.timeTrajectory_.front(), primalSolution.timeTrajectory_.back()}; |
| 81 | + extractPrimalSolution(timePeriodTest1, primalSolution, PrimalSolutionTest1); |
| 82 | + // std::cerr << ">>>>>> Test 1\n" << PrimalSolutionTest1 << "\n"; |
| 83 | + EXPECT_EQ(primalSolution.timeTrajectory_, PrimalSolutionTest1.timeTrajectory_); |
| 84 | + EXPECT_EQ(primalSolution.postEventIndices_, PrimalSolutionTest1.postEventIndices_); |
| 85 | + |
| 86 | + // test2: extracting at non-event time |
| 87 | + PrimalSolution PrimalSolutionTest2; |
| 88 | + const std::pair<scalar_t, scalar_t> timePeriodTest2{1.2, 2.4}; |
| 89 | + extractPrimalSolution(timePeriodTest2, primalSolution, PrimalSolutionTest2); |
| 90 | + // std::cerr << ">>>>>> Test 2\n" << PrimalSolutionTest2 << "\n"; |
| 91 | + EXPECT_EQ(PrimalSolutionTest2.timeTrajectory_.front(), timePeriodTest2.first); |
| 92 | + EXPECT_EQ(PrimalSolutionTest2.timeTrajectory_.back(), timePeriodTest2.second); |
| 93 | + EXPECT_EQ(PrimalSolutionTest2.postEventIndices_.size(), 1); |
| 94 | + |
| 95 | + // test3: extract zero length |
| 96 | + PrimalSolution PrimalSolutionTest3; |
| 97 | + const std::pair<scalar_t, scalar_t> timePeriodTest3{1.2, 1.2}; |
| 98 | + extractPrimalSolution(timePeriodTest3, primalSolution, PrimalSolutionTest3); |
| 99 | + // std::cerr << ">>>>>> Test 3\n" << PrimalSolutionTest3 << "\n"; |
| 100 | + EXPECT_EQ(PrimalSolutionTest3.timeTrajectory_.size(), 1); |
| 101 | +} |
0 commit comments