| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082 | // Ceres Solver - A fast non-linear least squares minimizer// Copyright 2015 Google Inc. All rights reserved.// http://ceres-solver.org///// Redistribution and use in source and binary forms, with or without// modification, are permitted provided that the following conditions are met://// * Redistributions of source code must retain the above copyright notice,//   this list of conditions and the following disclaimer.// * Redistributions in binary form must reproduce the above copyright notice,//   this list of conditions and the following disclaimer in the documentation//   and/or other materials provided with the distribution.// * Neither the name of Google Inc. nor the names of its contributors may be//   used to endorse or promote products derived from this software without//   specific prior written permission.//// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE// POSSIBILITY OF SUCH DAMAGE.//// Author: sameeragarwal@google.com (Sameer Agarwal)//         keir@google.com (Keir Mierle)#include "ceres/problem.h"#include <memory>#include "ceres/autodiff_cost_function.h"#include "ceres/casts.h"#include "ceres/cost_function.h"#include "ceres/crs_matrix.h"#include "ceres/evaluator_test_utils.h"#include "ceres/internal/eigen.h"#include "ceres/local_parameterization.h"#include "ceres/loss_function.h"#include "ceres/map_util.h"#include "ceres/parameter_block.h"#include "ceres/problem_impl.h"#include "ceres/program.h"#include "ceres/sized_cost_function.h"#include "ceres/sparse_matrix.h"#include "ceres/types.h"#include "gtest/gtest.h"namespace ceres {namespace internal {using std::vector;// The following three classes are for the purposes of defining// function signatures. They have dummy Evaluate functions.// Trivial cost function that accepts a single argument.class UnaryCostFunction : public CostFunction { public:  UnaryCostFunction(int num_residuals, int32_t parameter_block_size) {    set_num_residuals(num_residuals);    mutable_parameter_block_sizes()->push_back(parameter_block_size);  }  virtual ~UnaryCostFunction() {}  bool Evaluate(double const* const* parameters,                double* residuals,                double** jacobians) const final {    for (int i = 0; i < num_residuals(); ++i) {      residuals[i] = 1;    }    return true;  }};// Trivial cost function that accepts two arguments.class BinaryCostFunction: public CostFunction { public:  BinaryCostFunction(int num_residuals,                     int32_t parameter_block1_size,                     int32_t parameter_block2_size) {    set_num_residuals(num_residuals);    mutable_parameter_block_sizes()->push_back(parameter_block1_size);    mutable_parameter_block_sizes()->push_back(parameter_block2_size);  }  bool Evaluate(double const* const* parameters,                double* residuals,                double** jacobians) const final {    for (int i = 0; i < num_residuals(); ++i) {      residuals[i] = 2;    }    return true;  }};// Trivial cost function that accepts three arguments.class TernaryCostFunction: public CostFunction { public:  TernaryCostFunction(int num_residuals,                      int32_t parameter_block1_size,                      int32_t parameter_block2_size,                      int32_t parameter_block3_size) {    set_num_residuals(num_residuals);    mutable_parameter_block_sizes()->push_back(parameter_block1_size);    mutable_parameter_block_sizes()->push_back(parameter_block2_size);    mutable_parameter_block_sizes()->push_back(parameter_block3_size);  }  bool Evaluate(double const* const* parameters,                double* residuals,                double** jacobians) const final {    for (int i = 0; i < num_residuals(); ++i) {      residuals[i] = 3;    }    return true;  }};TEST(Problem, AddResidualWithNullCostFunctionDies) {  double x[3], y[4], z[5];  Problem problem;  problem.AddParameterBlock(x, 3);  problem.AddParameterBlock(y, 4);  problem.AddParameterBlock(z, 5);  EXPECT_DEATH_IF_SUPPORTED(problem.AddResidualBlock(NULL, NULL, x),                            "cost_function != nullptr");}TEST(Problem, AddResidualWithIncorrectNumberOfParameterBlocksDies) {  double x[3], y[4], z[5];  Problem problem;  problem.AddParameterBlock(x, 3);  problem.AddParameterBlock(y, 4);  problem.AddParameterBlock(z, 5);  // UnaryCostFunction takes only one parameter, but two are passed.  EXPECT_DEATH_IF_SUPPORTED(      problem.AddResidualBlock(new UnaryCostFunction(2, 3), NULL, x, y),      "num_parameter_blocks");}TEST(Problem, AddResidualWithDifferentSizesOnTheSameVariableDies) {  double x[3];  Problem problem;  problem.AddResidualBlock(new UnaryCostFunction(2, 3), NULL, x);  EXPECT_DEATH_IF_SUPPORTED(problem.AddResidualBlock(                                new UnaryCostFunction(                                    2, 4 /* 4 != 3 */), NULL, x),                            "different block sizes");}TEST(Problem, AddResidualWithDuplicateParametersDies) {  double x[3], z[5];  Problem problem;  EXPECT_DEATH_IF_SUPPORTED(problem.AddResidualBlock(                                new BinaryCostFunction(2, 3, 3), NULL, x, x),                            "Duplicate parameter blocks");  EXPECT_DEATH_IF_SUPPORTED(problem.AddResidualBlock(                                new TernaryCostFunction(1, 5, 3, 5),                                NULL, z, x, z),                            "Duplicate parameter blocks");}TEST(Problem, AddResidualWithIncorrectSizesOfParameterBlockDies) {  double x[3], y[4], z[5];  Problem problem;  problem.AddParameterBlock(x, 3);  problem.AddParameterBlock(y, 4);  problem.AddParameterBlock(z, 5);  // The cost function expects the size of the second parameter, z, to be 4  // instead of 5 as declared above. This is fatal.  EXPECT_DEATH_IF_SUPPORTED(problem.AddResidualBlock(      new BinaryCostFunction(2, 3, 4), NULL, x, z),               "different block sizes");}TEST(Problem, AddResidualAddsDuplicatedParametersOnlyOnce) {  double x[3], y[4], z[5];  Problem problem;  problem.AddResidualBlock(new UnaryCostFunction(2, 3), NULL, x);  problem.AddResidualBlock(new UnaryCostFunction(2, 3), NULL, x);  problem.AddResidualBlock(new UnaryCostFunction(2, 4), NULL, y);  problem.AddResidualBlock(new UnaryCostFunction(2, 5), NULL, z);  EXPECT_EQ(3, problem.NumParameterBlocks());  EXPECT_EQ(12, problem.NumParameters());}TEST(Problem, AddParameterWithDifferentSizesOnTheSameVariableDies) {  double x[3], y[4];  Problem problem;  problem.AddParameterBlock(x, 3);  problem.AddParameterBlock(y, 4);  EXPECT_DEATH_IF_SUPPORTED(problem.AddParameterBlock(x, 4),                            "different block sizes");}static double *IntToPtr(int i) {  return reinterpret_cast<double*>(sizeof(double) * i);  // NOLINT}TEST(Problem, AddParameterWithAliasedParametersDies) {  // Layout is  //  //   0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17  //                 [x] x  x  x  x          [y] y  y  //         o==o==o                 o==o==o           o==o  //               o--o--o     o--o--o     o--o  o--o--o  //  // Parameter block additions are tested as listed above; expected successful  // ones marked with o==o and aliasing ones marked with o--o.  Problem problem;  problem.AddParameterBlock(IntToPtr(5),  5);  // x  problem.AddParameterBlock(IntToPtr(13), 3);  // y  EXPECT_DEATH_IF_SUPPORTED(problem.AddParameterBlock(IntToPtr( 4), 2),                            "Aliasing detected");  EXPECT_DEATH_IF_SUPPORTED(problem.AddParameterBlock(IntToPtr( 4), 3),                            "Aliasing detected");  EXPECT_DEATH_IF_SUPPORTED(problem.AddParameterBlock(IntToPtr( 4), 9),                            "Aliasing detected");  EXPECT_DEATH_IF_SUPPORTED(problem.AddParameterBlock(IntToPtr( 8), 3),                            "Aliasing detected");  EXPECT_DEATH_IF_SUPPORTED(problem.AddParameterBlock(IntToPtr(12), 2),                            "Aliasing detected");  EXPECT_DEATH_IF_SUPPORTED(problem.AddParameterBlock(IntToPtr(14), 3),                            "Aliasing detected");  // These ones should work.  problem.AddParameterBlock(IntToPtr( 2), 3);  problem.AddParameterBlock(IntToPtr(10), 3);  problem.AddParameterBlock(IntToPtr(16), 2);  ASSERT_EQ(5, problem.NumParameterBlocks());}TEST(Problem, AddParameterIgnoresDuplicateCalls) {  double x[3], y[4];  Problem problem;  problem.AddParameterBlock(x, 3);  problem.AddParameterBlock(y, 4);  // Creating parameter blocks multiple times is ignored.  problem.AddParameterBlock(x, 3);  problem.AddResidualBlock(new UnaryCostFunction(2, 3), NULL, x);  // ... even repeatedly.  problem.AddParameterBlock(x, 3);  problem.AddResidualBlock(new UnaryCostFunction(2, 3), NULL, x);  // More parameters are fine.  problem.AddParameterBlock(y, 4);  problem.AddResidualBlock(new UnaryCostFunction(2, 4), NULL, y);  EXPECT_EQ(2, problem.NumParameterBlocks());  EXPECT_EQ(7, problem.NumParameters());}TEST(Problem, AddingParametersAndResidualsResultsInExpectedProblem) {  double x[3], y[4], z[5], w[4];  Problem problem;  problem.AddParameterBlock(x, 3);  EXPECT_EQ(1, problem.NumParameterBlocks());  EXPECT_EQ(3, problem.NumParameters());  problem.AddParameterBlock(y, 4);  EXPECT_EQ(2, problem.NumParameterBlocks());  EXPECT_EQ(7, problem.NumParameters());  problem.AddParameterBlock(z, 5);  EXPECT_EQ(3,  problem.NumParameterBlocks());  EXPECT_EQ(12, problem.NumParameters());  // Add a parameter that has a local parameterization.  w[0] = 1.0; w[1] = 0.0; w[2] = 0.0; w[3] = 0.0;  problem.AddParameterBlock(w, 4, new QuaternionParameterization);  EXPECT_EQ(4,  problem.NumParameterBlocks());  EXPECT_EQ(16, problem.NumParameters());  problem.AddResidualBlock(new UnaryCostFunction(2, 3), NULL, x);  problem.AddResidualBlock(new BinaryCostFunction(6, 5, 4) , NULL, z, y);  problem.AddResidualBlock(new BinaryCostFunction(3, 3, 5), NULL, x, z);  problem.AddResidualBlock(new BinaryCostFunction(7, 5, 3), NULL, z, x);  problem.AddResidualBlock(new TernaryCostFunction(1, 5, 3, 4), NULL, z, x, y);  const int total_residuals = 2 + 6 + 3 + 7 + 1;  EXPECT_EQ(problem.NumResidualBlocks(), 5);  EXPECT_EQ(problem.NumResiduals(), total_residuals);}class DestructorCountingCostFunction : public SizedCostFunction<3, 4, 5> { public:  explicit DestructorCountingCostFunction(int *num_destructions)      : num_destructions_(num_destructions) {}  virtual ~DestructorCountingCostFunction() {    *num_destructions_ += 1;  }  bool Evaluate(double const* const* parameters,                double* residuals,                double** jacobians) const final {    return true;  } private:  int* num_destructions_;};TEST(Problem, ReusedCostFunctionsAreOnlyDeletedOnce) {  double y[4], z[5];  int num_destructions = 0;  // Add a cost function multiple times and check to make sure that  // the destructor on the cost function is only called once.  {    Problem problem;    problem.AddParameterBlock(y, 4);    problem.AddParameterBlock(z, 5);    CostFunction* cost = new DestructorCountingCostFunction(&num_destructions);    problem.AddResidualBlock(cost, NULL, y, z);    problem.AddResidualBlock(cost, NULL, y, z);    problem.AddResidualBlock(cost, NULL, y, z);    EXPECT_EQ(3, problem.NumResidualBlocks());  }  // Check that the destructor was called only once.  CHECK_EQ(num_destructions, 1);}TEST(Problem, GetCostFunctionForResidualBlock) {  double x[3];  Problem problem;  CostFunction* cost_function = new UnaryCostFunction(2, 3);  const ResidualBlockId residual_block =      problem.AddResidualBlock(cost_function, NULL, x);  EXPECT_EQ(problem.GetCostFunctionForResidualBlock(residual_block),            cost_function);  EXPECT_TRUE(problem.GetLossFunctionForResidualBlock(residual_block) == NULL);}TEST(Problem, GetLossFunctionForResidualBlock) {  double x[3];  Problem problem;  CostFunction* cost_function = new UnaryCostFunction(2, 3);  LossFunction* loss_function = new TrivialLoss();  const ResidualBlockId residual_block =      problem.AddResidualBlock(cost_function, loss_function, x);  EXPECT_EQ(problem.GetCostFunctionForResidualBlock(residual_block),            cost_function);  EXPECT_EQ(problem.GetLossFunctionForResidualBlock(residual_block),            loss_function);}TEST(Problem, CostFunctionsAreDeletedEvenWithRemovals) {  double y[4], z[5], w[4];  int num_destructions = 0;  {    Problem problem;    problem.AddParameterBlock(y, 4);    problem.AddParameterBlock(z, 5);    CostFunction* cost_yz =        new DestructorCountingCostFunction(&num_destructions);    CostFunction* cost_wz =        new DestructorCountingCostFunction(&num_destructions);    ResidualBlock* r_yz = problem.AddResidualBlock(cost_yz, NULL, y, z);    ResidualBlock* r_wz = problem.AddResidualBlock(cost_wz, NULL, w, z);    EXPECT_EQ(2, problem.NumResidualBlocks());    problem.RemoveResidualBlock(r_yz);    CHECK_EQ(num_destructions, 1);    problem.RemoveResidualBlock(r_wz);    CHECK_EQ(num_destructions, 2);    EXPECT_EQ(0, problem.NumResidualBlocks());  }  CHECK_EQ(num_destructions, 2);}// Make the dynamic problem tests (e.g. for removing residual blocks)// parameterized on whether the low-latency mode is enabled or not.//// This tests against ProblemImpl instead of Problem in order to inspect the// state of the resulting Program; this is difficult with only the thin Problem// interface.struct DynamicProblem : public ::testing::TestWithParam<bool> {  DynamicProblem() {    Problem::Options options;    options.enable_fast_removal = GetParam();    problem.reset(new ProblemImpl(options));  }  ParameterBlock* GetParameterBlock(int block) {    return problem->program().parameter_blocks()[block];  }  ResidualBlock* GetResidualBlock(int block) {    return problem->program().residual_blocks()[block];  }  bool HasResidualBlock(ResidualBlock* residual_block) {    bool have_residual_block = true;    if (GetParam()) {      have_residual_block &=          (problem->residual_block_set().find(residual_block) !=           problem->residual_block_set().end());    }    have_residual_block &=        find(problem->program().residual_blocks().begin(),             problem->program().residual_blocks().end(),             residual_block) != problem->program().residual_blocks().end();    return have_residual_block;  }  int NumResidualBlocks() {    // Verify that the hash set of residuals is maintained consistently.    if (GetParam()) {      EXPECT_EQ(problem->residual_block_set().size(),                problem->NumResidualBlocks());    }    return problem->NumResidualBlocks();  }  // The next block of functions until the end are only for testing the  // residual block removals.  void ExpectParameterBlockContainsResidualBlock(      double* values,      ResidualBlock* residual_block) {    ParameterBlock* parameter_block =        FindOrDie(problem->parameter_map(), values);    EXPECT_TRUE(ContainsKey(*(parameter_block->mutable_residual_blocks()),                            residual_block));  }  void ExpectSize(double* values, int size) {    ParameterBlock* parameter_block =        FindOrDie(problem->parameter_map(), values);    EXPECT_EQ(size, parameter_block->mutable_residual_blocks()->size());  }  // Degenerate case.  void ExpectParameterBlockContains(double* values) {    ExpectSize(values, 0);  }  void ExpectParameterBlockContains(double* values,                                    ResidualBlock* r1) {    ExpectSize(values, 1);    ExpectParameterBlockContainsResidualBlock(values, r1);  }  void ExpectParameterBlockContains(double* values,                                    ResidualBlock* r1,                                    ResidualBlock* r2) {    ExpectSize(values, 2);    ExpectParameterBlockContainsResidualBlock(values, r1);    ExpectParameterBlockContainsResidualBlock(values, r2);  }  void ExpectParameterBlockContains(double* values,                                    ResidualBlock* r1,                                    ResidualBlock* r2,                                    ResidualBlock* r3) {    ExpectSize(values, 3);    ExpectParameterBlockContainsResidualBlock(values, r1);    ExpectParameterBlockContainsResidualBlock(values, r2);    ExpectParameterBlockContainsResidualBlock(values, r3);  }  void ExpectParameterBlockContains(double* values,                                    ResidualBlock* r1,                                    ResidualBlock* r2,                                    ResidualBlock* r3,                                    ResidualBlock* r4) {    ExpectSize(values, 4);    ExpectParameterBlockContainsResidualBlock(values, r1);    ExpectParameterBlockContainsResidualBlock(values, r2);    ExpectParameterBlockContainsResidualBlock(values, r3);    ExpectParameterBlockContainsResidualBlock(values, r4);  }  std::unique_ptr<ProblemImpl> problem;  double y[4], z[5], w[3];};TEST(Problem, SetParameterBlockConstantWithUnknownPtrDies) {  double x[3];  double y[2];  Problem problem;  problem.AddParameterBlock(x, 3);  EXPECT_DEATH_IF_SUPPORTED(problem.SetParameterBlockConstant(y),                            "Parameter block not found:");}TEST(Problem, SetParameterBlockVariableWithUnknownPtrDies) {  double x[3];  double y[2];  Problem problem;  problem.AddParameterBlock(x, 3);  EXPECT_DEATH_IF_SUPPORTED(problem.SetParameterBlockVariable(y),                            "Parameter block not found:");}TEST(Problem, IsParameterBlockConstant) {  double x1[3];  double x2[3];  Problem problem;  problem.AddParameterBlock(x1, 3);  problem.AddParameterBlock(x2, 3);  EXPECT_FALSE(problem.IsParameterBlockConstant(x1));  EXPECT_FALSE(problem.IsParameterBlockConstant(x2));  problem.SetParameterBlockConstant(x1);  EXPECT_TRUE(problem.IsParameterBlockConstant(x1));  EXPECT_FALSE(problem.IsParameterBlockConstant(x2));  problem.SetParameterBlockConstant(x2);  EXPECT_TRUE(problem.IsParameterBlockConstant(x1));  EXPECT_TRUE(problem.IsParameterBlockConstant(x2));  problem.SetParameterBlockVariable(x1);  EXPECT_FALSE(problem.IsParameterBlockConstant(x1));  EXPECT_TRUE(problem.IsParameterBlockConstant(x2));}TEST(Problem, IsParameterBlockConstantWithUnknownPtrDies) {  double x[3];  double y[2];  Problem problem;  problem.AddParameterBlock(x, 3);  EXPECT_DEATH_IF_SUPPORTED(problem.IsParameterBlockConstant(y),                            "Parameter block not found:");}TEST(Problem, SetLocalParameterizationWithUnknownPtrDies) {  double x[3];  double y[2];  Problem problem;  problem.AddParameterBlock(x, 3);  EXPECT_DEATH_IF_SUPPORTED(      problem.SetParameterization(y, new IdentityParameterization(3)),      "Parameter block not found:");}TEST(Problem, RemoveParameterBlockWithUnknownPtrDies) {  double x[3];  double y[2];  Problem problem;  problem.AddParameterBlock(x, 3);  EXPECT_DEATH_IF_SUPPORTED(      problem.RemoveParameterBlock(y), "Parameter block not found:");}TEST(Problem, GetParameterization) {  double x[3];  double y[2];  Problem problem;  problem.AddParameterBlock(x, 3);  problem.AddParameterBlock(y, 2);  LocalParameterization* parameterization =  new IdentityParameterization(3);  problem.SetParameterization(x, parameterization);  EXPECT_EQ(problem.GetParameterization(x), parameterization);  EXPECT_TRUE(problem.GetParameterization(y) == NULL);}TEST(Problem, ParameterBlockQueryTest) {  double x[3];  double y[4];  Problem problem;  problem.AddParameterBlock(x, 3);  problem.AddParameterBlock(y, 4);  vector<int> constant_parameters;  constant_parameters.push_back(0);  problem.SetParameterization(      x,      new SubsetParameterization(3, constant_parameters));  EXPECT_EQ(problem.ParameterBlockSize(x), 3);  EXPECT_EQ(problem.ParameterBlockLocalSize(x), 2);  EXPECT_EQ(problem.ParameterBlockLocalSize(y), 4);  vector<double*> parameter_blocks;  problem.GetParameterBlocks(¶meter_blocks);  EXPECT_EQ(parameter_blocks.size(), 2);  EXPECT_NE(parameter_blocks[0], parameter_blocks[1]);  EXPECT_TRUE(parameter_blocks[0] == x || parameter_blocks[0] == y);  EXPECT_TRUE(parameter_blocks[1] == x || parameter_blocks[1] == y);  EXPECT_TRUE(problem.HasParameterBlock(x));  problem.RemoveParameterBlock(x);  EXPECT_FALSE(problem.HasParameterBlock(x));  problem.GetParameterBlocks(¶meter_blocks);  EXPECT_EQ(parameter_blocks.size(), 1);  EXPECT_TRUE(parameter_blocks[0] == y);}TEST_P(DynamicProblem, RemoveParameterBlockWithNoResiduals) {  problem->AddParameterBlock(y, 4);  problem->AddParameterBlock(z, 5);  problem->AddParameterBlock(w, 3);  ASSERT_EQ(3, problem->NumParameterBlocks());  ASSERT_EQ(0, NumResidualBlocks());  EXPECT_EQ(y, GetParameterBlock(0)->user_state());  EXPECT_EQ(z, GetParameterBlock(1)->user_state());  EXPECT_EQ(w, GetParameterBlock(2)->user_state());  // w is at the end, which might break the swapping logic so try adding and  // removing it.  problem->RemoveParameterBlock(w);  ASSERT_EQ(2, problem->NumParameterBlocks());  ASSERT_EQ(0, NumResidualBlocks());  EXPECT_EQ(y, GetParameterBlock(0)->user_state());  EXPECT_EQ(z, GetParameterBlock(1)->user_state());  problem->AddParameterBlock(w, 3);  ASSERT_EQ(3, problem->NumParameterBlocks());  ASSERT_EQ(0, NumResidualBlocks());  EXPECT_EQ(y, GetParameterBlock(0)->user_state());  EXPECT_EQ(z, GetParameterBlock(1)->user_state());  EXPECT_EQ(w, GetParameterBlock(2)->user_state());  // Now remove z, which is in the middle, and add it back.  problem->RemoveParameterBlock(z);  ASSERT_EQ(2, problem->NumParameterBlocks());  ASSERT_EQ(0, NumResidualBlocks());  EXPECT_EQ(y, GetParameterBlock(0)->user_state());  EXPECT_EQ(w, GetParameterBlock(1)->user_state());  problem->AddParameterBlock(z, 5);  ASSERT_EQ(3, problem->NumParameterBlocks());  ASSERT_EQ(0, NumResidualBlocks());  EXPECT_EQ(y, GetParameterBlock(0)->user_state());  EXPECT_EQ(w, GetParameterBlock(1)->user_state());  EXPECT_EQ(z, GetParameterBlock(2)->user_state());  // Now remove everything.  // y  problem->RemoveParameterBlock(y);  ASSERT_EQ(2, problem->NumParameterBlocks());  ASSERT_EQ(0, NumResidualBlocks());  EXPECT_EQ(z, GetParameterBlock(0)->user_state());  EXPECT_EQ(w, GetParameterBlock(1)->user_state());  // z  problem->RemoveParameterBlock(z);  ASSERT_EQ(1, problem->NumParameterBlocks());  ASSERT_EQ(0, NumResidualBlocks());  EXPECT_EQ(w, GetParameterBlock(0)->user_state());  // w  problem->RemoveParameterBlock(w);  EXPECT_EQ(0, problem->NumParameterBlocks());  EXPECT_EQ(0, NumResidualBlocks());}TEST_P(DynamicProblem, RemoveParameterBlockWithResiduals) {  problem->AddParameterBlock(y, 4);  problem->AddParameterBlock(z, 5);  problem->AddParameterBlock(w, 3);  ASSERT_EQ(3, problem->NumParameterBlocks());  ASSERT_EQ(0, NumResidualBlocks());  EXPECT_EQ(y, GetParameterBlock(0)->user_state());  EXPECT_EQ(z, GetParameterBlock(1)->user_state());  EXPECT_EQ(w, GetParameterBlock(2)->user_state());  // Add all combinations of cost functions.  CostFunction* cost_yzw = new TernaryCostFunction(1, 4, 5, 3);  CostFunction* cost_yz  = new BinaryCostFunction (1, 4, 5);  CostFunction* cost_yw  = new BinaryCostFunction (1, 4, 3);  CostFunction* cost_zw  = new BinaryCostFunction (1, 5, 3);  CostFunction* cost_y   = new UnaryCostFunction  (1, 4);  CostFunction* cost_z   = new UnaryCostFunction  (1, 5);  CostFunction* cost_w   = new UnaryCostFunction  (1, 3);  ResidualBlock* r_yzw = problem->AddResidualBlock(cost_yzw, NULL, y, z, w);  ResidualBlock* r_yz  = problem->AddResidualBlock(cost_yz,  NULL, y, z);  ResidualBlock* r_yw  = problem->AddResidualBlock(cost_yw,  NULL, y, w);  ResidualBlock* r_zw  = problem->AddResidualBlock(cost_zw,  NULL, z, w);  ResidualBlock* r_y   = problem->AddResidualBlock(cost_y,   NULL, y);  ResidualBlock* r_z   = problem->AddResidualBlock(cost_z,   NULL, z);  ResidualBlock* r_w   = problem->AddResidualBlock(cost_w,   NULL, w);  EXPECT_EQ(3, problem->NumParameterBlocks());  EXPECT_EQ(7, NumResidualBlocks());  // Remove w, which should remove r_yzw, r_yw, r_zw, r_w.  problem->RemoveParameterBlock(w);  ASSERT_EQ(2, problem->NumParameterBlocks());  ASSERT_EQ(3, NumResidualBlocks());  ASSERT_FALSE(HasResidualBlock(r_yzw));  ASSERT_TRUE (HasResidualBlock(r_yz ));  ASSERT_FALSE(HasResidualBlock(r_yw ));  ASSERT_FALSE(HasResidualBlock(r_zw ));  ASSERT_TRUE (HasResidualBlock(r_y  ));  ASSERT_TRUE (HasResidualBlock(r_z  ));  ASSERT_FALSE(HasResidualBlock(r_w  ));  // Remove z, which will remove almost everything else.  problem->RemoveParameterBlock(z);  ASSERT_EQ(1, problem->NumParameterBlocks());  ASSERT_EQ(1, NumResidualBlocks());  ASSERT_FALSE(HasResidualBlock(r_yzw));  ASSERT_FALSE(HasResidualBlock(r_yz ));  ASSERT_FALSE(HasResidualBlock(r_yw ));  ASSERT_FALSE(HasResidualBlock(r_zw ));  ASSERT_TRUE (HasResidualBlock(r_y  ));  ASSERT_FALSE(HasResidualBlock(r_z  ));  ASSERT_FALSE(HasResidualBlock(r_w  ));  // Remove y; all gone.  problem->RemoveParameterBlock(y);  EXPECT_EQ(0, problem->NumParameterBlocks());  EXPECT_EQ(0, NumResidualBlocks());}TEST_P(DynamicProblem, RemoveResidualBlock) {  problem->AddParameterBlock(y, 4);  problem->AddParameterBlock(z, 5);  problem->AddParameterBlock(w, 3);  // Add all combinations of cost functions.  CostFunction* cost_yzw = new TernaryCostFunction(1, 4, 5, 3);  CostFunction* cost_yz  = new BinaryCostFunction (1, 4, 5);  CostFunction* cost_yw  = new BinaryCostFunction (1, 4, 3);  CostFunction* cost_zw  = new BinaryCostFunction (1, 5, 3);  CostFunction* cost_y   = new UnaryCostFunction  (1, 4);  CostFunction* cost_z   = new UnaryCostFunction  (1, 5);  CostFunction* cost_w   = new UnaryCostFunction  (1, 3);  ResidualBlock* r_yzw = problem->AddResidualBlock(cost_yzw, NULL, y, z, w);  ResidualBlock* r_yz  = problem->AddResidualBlock(cost_yz,  NULL, y, z);  ResidualBlock* r_yw  = problem->AddResidualBlock(cost_yw,  NULL, y, w);  ResidualBlock* r_zw  = problem->AddResidualBlock(cost_zw,  NULL, z, w);  ResidualBlock* r_y   = problem->AddResidualBlock(cost_y,   NULL, y);  ResidualBlock* r_z   = problem->AddResidualBlock(cost_z,   NULL, z);  ResidualBlock* r_w   = problem->AddResidualBlock(cost_w,   NULL, w);  if (GetParam()) {    // In this test parameterization, there should be back-pointers from the    // parameter blocks to the residual blocks.    ExpectParameterBlockContains(y, r_yzw, r_yz, r_yw, r_y);    ExpectParameterBlockContains(z, r_yzw, r_yz, r_zw, r_z);    ExpectParameterBlockContains(w, r_yzw, r_yw, r_zw, r_w);  } else {    // Otherwise, nothing.    EXPECT_TRUE(GetParameterBlock(0)->mutable_residual_blocks() == NULL);    EXPECT_TRUE(GetParameterBlock(1)->mutable_residual_blocks() == NULL);    EXPECT_TRUE(GetParameterBlock(2)->mutable_residual_blocks() == NULL);  }  EXPECT_EQ(3, problem->NumParameterBlocks());  EXPECT_EQ(7, NumResidualBlocks());  // Remove each residual and check the state after each removal.  // Remove r_yzw.  problem->RemoveResidualBlock(r_yzw);  ASSERT_EQ(3, problem->NumParameterBlocks());  ASSERT_EQ(6, NumResidualBlocks());  if (GetParam()) {    ExpectParameterBlockContains(y, r_yz, r_yw, r_y);    ExpectParameterBlockContains(z, r_yz, r_zw, r_z);    ExpectParameterBlockContains(w, r_yw, r_zw, r_w);  }  ASSERT_TRUE (HasResidualBlock(r_yz ));  ASSERT_TRUE (HasResidualBlock(r_yw ));  ASSERT_TRUE (HasResidualBlock(r_zw ));  ASSERT_TRUE (HasResidualBlock(r_y  ));  ASSERT_TRUE (HasResidualBlock(r_z  ));  ASSERT_TRUE (HasResidualBlock(r_w  ));  // Remove r_yw.  problem->RemoveResidualBlock(r_yw);  ASSERT_EQ(3, problem->NumParameterBlocks());  ASSERT_EQ(5, NumResidualBlocks());  if (GetParam()) {    ExpectParameterBlockContains(y, r_yz, r_y);    ExpectParameterBlockContains(z, r_yz, r_zw, r_z);    ExpectParameterBlockContains(w, r_zw, r_w);  }  ASSERT_TRUE (HasResidualBlock(r_yz ));  ASSERT_TRUE (HasResidualBlock(r_zw ));  ASSERT_TRUE (HasResidualBlock(r_y  ));  ASSERT_TRUE (HasResidualBlock(r_z  ));  ASSERT_TRUE (HasResidualBlock(r_w  ));  // Remove r_zw.  problem->RemoveResidualBlock(r_zw);  ASSERT_EQ(3, problem->NumParameterBlocks());  ASSERT_EQ(4, NumResidualBlocks());  if (GetParam()) {    ExpectParameterBlockContains(y, r_yz, r_y);    ExpectParameterBlockContains(z, r_yz, r_z);    ExpectParameterBlockContains(w, r_w);  }  ASSERT_TRUE (HasResidualBlock(r_yz ));  ASSERT_TRUE (HasResidualBlock(r_y  ));  ASSERT_TRUE (HasResidualBlock(r_z  ));  ASSERT_TRUE (HasResidualBlock(r_w  ));  // Remove r_w.  problem->RemoveResidualBlock(r_w);  ASSERT_EQ(3, problem->NumParameterBlocks());  ASSERT_EQ(3, NumResidualBlocks());  if (GetParam()) {    ExpectParameterBlockContains(y, r_yz, r_y);    ExpectParameterBlockContains(z, r_yz, r_z);    ExpectParameterBlockContains(w);  }  ASSERT_TRUE (HasResidualBlock(r_yz ));  ASSERT_TRUE (HasResidualBlock(r_y  ));  ASSERT_TRUE (HasResidualBlock(r_z  ));  // Remove r_yz.  problem->RemoveResidualBlock(r_yz);  ASSERT_EQ(3, problem->NumParameterBlocks());  ASSERT_EQ(2, NumResidualBlocks());  if (GetParam()) {    ExpectParameterBlockContains(y, r_y);    ExpectParameterBlockContains(z, r_z);    ExpectParameterBlockContains(w);  }  ASSERT_TRUE (HasResidualBlock(r_y  ));  ASSERT_TRUE (HasResidualBlock(r_z  ));  // Remove the last two.  problem->RemoveResidualBlock(r_z);  problem->RemoveResidualBlock(r_y);  ASSERT_EQ(3, problem->NumParameterBlocks());  ASSERT_EQ(0, NumResidualBlocks());  if (GetParam()) {    ExpectParameterBlockContains(y);    ExpectParameterBlockContains(z);    ExpectParameterBlockContains(w);  }}TEST_P(DynamicProblem, RemoveInvalidResidualBlockDies) {  problem->AddParameterBlock(y, 4);  problem->AddParameterBlock(z, 5);  problem->AddParameterBlock(w, 3);  // Add all combinations of cost functions.  CostFunction* cost_yzw = new TernaryCostFunction(1, 4, 5, 3);  CostFunction* cost_yz  = new BinaryCostFunction (1, 4, 5);  CostFunction* cost_yw  = new BinaryCostFunction (1, 4, 3);  CostFunction* cost_zw  = new BinaryCostFunction (1, 5, 3);  CostFunction* cost_y   = new UnaryCostFunction  (1, 4);  CostFunction* cost_z   = new UnaryCostFunction  (1, 5);  CostFunction* cost_w   = new UnaryCostFunction  (1, 3);  ResidualBlock* r_yzw = problem->AddResidualBlock(cost_yzw, NULL, y, z, w);  ResidualBlock* r_yz  = problem->AddResidualBlock(cost_yz,  NULL, y, z);  ResidualBlock* r_yw  = problem->AddResidualBlock(cost_yw,  NULL, y, w);  ResidualBlock* r_zw  = problem->AddResidualBlock(cost_zw,  NULL, z, w);  ResidualBlock* r_y   = problem->AddResidualBlock(cost_y,   NULL, y);  ResidualBlock* r_z   = problem->AddResidualBlock(cost_z,   NULL, z);  ResidualBlock* r_w   = problem->AddResidualBlock(cost_w,   NULL, w);  // Remove r_yzw.  problem->RemoveResidualBlock(r_yzw);  ASSERT_EQ(3, problem->NumParameterBlocks());  ASSERT_EQ(6, NumResidualBlocks());  // Attempt to remove r_yzw again.  EXPECT_DEATH_IF_SUPPORTED(problem->RemoveResidualBlock(r_yzw), "not found");  // Attempt to remove a cast pointer never added as a residual.  int trash_memory = 1234;  ResidualBlock* invalid_residual =      reinterpret_cast<ResidualBlock*>(&trash_memory);  EXPECT_DEATH_IF_SUPPORTED(problem->RemoveResidualBlock(invalid_residual),                            "not found");  // Remove a parameter block, which in turn removes the dependent residuals  // then attempt to remove them directly.  problem->RemoveParameterBlock(z);  ASSERT_EQ(2, problem->NumParameterBlocks());  ASSERT_EQ(3, NumResidualBlocks());  EXPECT_DEATH_IF_SUPPORTED(problem->RemoveResidualBlock(r_yz), "not found");  EXPECT_DEATH_IF_SUPPORTED(problem->RemoveResidualBlock(r_zw), "not found");  EXPECT_DEATH_IF_SUPPORTED(problem->RemoveResidualBlock(r_z), "not found");  problem->RemoveResidualBlock(r_yw);  problem->RemoveResidualBlock(r_w);  problem->RemoveResidualBlock(r_y);}// Check that a null-terminated array, a, has the same elements as b.template<typename T>void ExpectVectorContainsUnordered(const T* a, const vector<T>& b) {  // Compute the size of a.  int size = 0;  while (a[size]) {    ++size;  }  ASSERT_EQ(size, b.size());  // Sort a.  vector<T> a_sorted(size);  copy(a, a + size, a_sorted.begin());  sort(a_sorted.begin(), a_sorted.end());  // Sort b.  vector<T> b_sorted(b);  sort(b_sorted.begin(), b_sorted.end());  // Compare.  for (int i = 0; i < size; ++i) {    EXPECT_EQ(a_sorted[i], b_sorted[i]);  }}static void ExpectProblemHasResidualBlocks(    const ProblemImpl &problem,    const ResidualBlockId *expected_residual_blocks) {  vector<ResidualBlockId> residual_blocks;  problem.GetResidualBlocks(&residual_blocks);  ExpectVectorContainsUnordered(expected_residual_blocks, residual_blocks);}TEST_P(DynamicProblem, GetXXXBlocksForYYYBlock) {  problem->AddParameterBlock(y, 4);  problem->AddParameterBlock(z, 5);  problem->AddParameterBlock(w, 3);  // Add all combinations of cost functions.  CostFunction* cost_yzw = new TernaryCostFunction(1, 4, 5, 3);  CostFunction* cost_yz  = new BinaryCostFunction (1, 4, 5);  CostFunction* cost_yw  = new BinaryCostFunction (1, 4, 3);  CostFunction* cost_zw  = new BinaryCostFunction (1, 5, 3);  CostFunction* cost_y   = new UnaryCostFunction  (1, 4);  CostFunction* cost_z   = new UnaryCostFunction  (1, 5);  CostFunction* cost_w   = new UnaryCostFunction  (1, 3);  ResidualBlock* r_yzw = problem->AddResidualBlock(cost_yzw, NULL, y, z, w);  {    ResidualBlockId expected_residuals[] = {r_yzw, 0};    ExpectProblemHasResidualBlocks(*problem, expected_residuals);  }  ResidualBlock* r_yz  = problem->AddResidualBlock(cost_yz,  NULL, y, z);  {    ResidualBlockId expected_residuals[] = {r_yzw, r_yz, 0};    ExpectProblemHasResidualBlocks(*problem, expected_residuals);  }  ResidualBlock* r_yw  = problem->AddResidualBlock(cost_yw,  NULL, y, w);  {    ResidualBlock *expected_residuals[] = {r_yzw, r_yz, r_yw, 0};    ExpectProblemHasResidualBlocks(*problem, expected_residuals);  }  ResidualBlock* r_zw  = problem->AddResidualBlock(cost_zw,  NULL, z, w);  {    ResidualBlock *expected_residuals[] = {r_yzw, r_yz, r_yw, r_zw, 0};    ExpectProblemHasResidualBlocks(*problem, expected_residuals);  }  ResidualBlock* r_y   = problem->AddResidualBlock(cost_y,   NULL, y);  {    ResidualBlock *expected_residuals[] = {r_yzw, r_yz, r_yw, r_zw, r_y, 0};    ExpectProblemHasResidualBlocks(*problem, expected_residuals);  }  ResidualBlock* r_z   = problem->AddResidualBlock(cost_z,   NULL, z);  {    ResidualBlock *expected_residuals[] = {      r_yzw, r_yz, r_yw, r_zw, r_y, r_z, 0    };    ExpectProblemHasResidualBlocks(*problem, expected_residuals);  }  ResidualBlock* r_w   = problem->AddResidualBlock(cost_w,   NULL, w);  {    ResidualBlock *expected_residuals[] = {      r_yzw, r_yz, r_yw, r_zw, r_y, r_z, r_w, 0    };    ExpectProblemHasResidualBlocks(*problem, expected_residuals);  }  vector<double*> parameter_blocks;  vector<ResidualBlockId> residual_blocks;  // Check GetResidualBlocksForParameterBlock() for all parameter blocks.  struct GetResidualBlocksForParameterBlockTestCase {    double* parameter_block;    ResidualBlockId expected_residual_blocks[10];  };  GetResidualBlocksForParameterBlockTestCase get_residual_blocks_cases[] = {    { y, { r_yzw, r_yz, r_yw, r_y, NULL} },    { z, { r_yzw, r_yz, r_zw, r_z, NULL} },    { w, { r_yzw, r_yw, r_zw, r_w, NULL} },    { NULL }  };  for (int i = 0; get_residual_blocks_cases[i].parameter_block; ++i) {    problem->GetResidualBlocksForParameterBlock(        get_residual_blocks_cases[i].parameter_block,        &residual_blocks);    ExpectVectorContainsUnordered(        get_residual_blocks_cases[i].expected_residual_blocks,        residual_blocks);  }  // Check GetParameterBlocksForResidualBlock() for all residual blocks.  struct GetParameterBlocksForResidualBlockTestCase {    ResidualBlockId residual_block;    double* expected_parameter_blocks[10];  };  GetParameterBlocksForResidualBlockTestCase get_parameter_blocks_cases[] = {    { r_yzw, { y, z, w, NULL } },    { r_yz , { y, z, NULL } },    { r_yw , { y, w, NULL } },    { r_zw , { z, w, NULL } },    { r_y  , { y, NULL } },    { r_z  , { z, NULL } },    { r_w  , { w, NULL } },    { NULL }  };  for (int i = 0; get_parameter_blocks_cases[i].residual_block; ++i) {    problem->GetParameterBlocksForResidualBlock(        get_parameter_blocks_cases[i].residual_block,        ¶meter_blocks);    ExpectVectorContainsUnordered(        get_parameter_blocks_cases[i].expected_parameter_blocks,        parameter_blocks);  }}INSTANTIATE_TEST_SUITE_P(OptionsInstantiation,                         DynamicProblem,                         ::testing::Values(true, false));// Test for Problem::Evaluate// r_i = i - (j + 1) * x_ij^2template <int kNumResiduals, int kNumParameterBlocks>class QuadraticCostFunction : public CostFunction { public:  QuadraticCostFunction() {    CHECK_GT(kNumResiduals, 0);    CHECK_GT(kNumParameterBlocks, 0);    set_num_residuals(kNumResiduals);    for (int i = 0; i < kNumParameterBlocks; ++i) {      mutable_parameter_block_sizes()->push_back(kNumResiduals);    }  }  bool Evaluate(double const* const* parameters,                double* residuals,                double** jacobians) const final {    for (int i = 0; i < kNumResiduals; ++i) {      residuals[i] = i;      for (int j = 0; j < kNumParameterBlocks; ++j) {        residuals[i] -= (j + 1.0) * parameters[j][i] * parameters[j][i];      }    }    if (jacobians == NULL) {      return true;    }    for (int j = 0; j < kNumParameterBlocks; ++j) {      if (jacobians[j] != NULL) {        MatrixRef(jacobians[j], kNumResiduals, kNumResiduals) =            (-2.0 * (j + 1.0) *             ConstVectorRef(parameters[j], kNumResiduals)).asDiagonal();      }    }    return true;  }};// Convert a CRSMatrix to a dense Eigen matrix.static void CRSToDenseMatrix(const CRSMatrix& input, Matrix* output) {  CHECK(output != nullptr);  Matrix& m = *output;  m.resize(input.num_rows, input.num_cols);  m.setZero();  for (int row = 0; row < input.num_rows; ++row) {    for (int j = input.rows[row]; j < input.rows[row + 1]; ++j) {      const int col = input.cols[j];      m(row, col) = input.values[j];    }  }}class ProblemEvaluateTest : public ::testing::Test { protected:  void SetUp() {    for (int i = 0; i < 6; ++i) {      parameters_[i] = static_cast<double>(i + 1);    }    parameter_blocks_.push_back(parameters_);    parameter_blocks_.push_back(parameters_ + 2);    parameter_blocks_.push_back(parameters_ + 4);    CostFunction* cost_function = new QuadraticCostFunction<2, 2>;    // f(x, y)    residual_blocks_.push_back(        problem_.AddResidualBlock(cost_function,                                  NULL,                                  parameters_,                                  parameters_ + 2));    // g(y, z)    residual_blocks_.push_back(        problem_.AddResidualBlock(cost_function,                                  NULL, parameters_ + 2,                                  parameters_ + 4));    // h(z, x)    residual_blocks_.push_back(        problem_.AddResidualBlock(cost_function,                                  NULL,                                  parameters_ + 4,                                  parameters_));  }  void TearDown() {    EXPECT_TRUE(problem_.program().IsValid());  }  void EvaluateAndCompare(const Problem::EvaluateOptions& options,                          const int expected_num_rows,                          const int expected_num_cols,                          const double expected_cost,                          const double* expected_residuals,                          const double* expected_gradient,                          const double* expected_jacobian) {    double cost;    vector<double> residuals;    vector<double> gradient;    CRSMatrix jacobian;    EXPECT_TRUE(        problem_.Evaluate(options,                          &cost,                          expected_residuals != NULL ? &residuals : NULL,                          expected_gradient != NULL ? &gradient : NULL,                          expected_jacobian != NULL ? &jacobian : NULL));    if (expected_residuals != NULL) {      EXPECT_EQ(residuals.size(), expected_num_rows);    }    if (expected_gradient != NULL) {      EXPECT_EQ(gradient.size(), expected_num_cols);    }    if (expected_jacobian != NULL) {      EXPECT_EQ(jacobian.num_rows, expected_num_rows);      EXPECT_EQ(jacobian.num_cols, expected_num_cols);    }    Matrix dense_jacobian;    if (expected_jacobian != NULL) {      CRSToDenseMatrix(jacobian, &dense_jacobian);    }    CompareEvaluations(expected_num_rows,                       expected_num_cols,                       expected_cost,                       expected_residuals,                       expected_gradient,                       expected_jacobian,                       cost,                       residuals.size() > 0 ? &residuals[0] : NULL,                       gradient.size() > 0 ? &gradient[0] : NULL,                       dense_jacobian.data());  }  void CheckAllEvaluationCombinations(const Problem::EvaluateOptions& options,                                      const ExpectedEvaluation& expected) {    for (int i = 0; i < 8; ++i) {      EvaluateAndCompare(options,                         expected.num_rows,                         expected.num_cols,                         expected.cost,                         (i & 1) ? expected.residuals : NULL,                         (i & 2) ? expected.gradient  : NULL,                         (i & 4) ? expected.jacobian  : NULL);    }  }  ProblemImpl problem_;  double parameters_[6];  vector<double*> parameter_blocks_;  vector<ResidualBlockId> residual_blocks_;};TEST_F(ProblemEvaluateTest, MultipleParameterAndResidualBlocks) {  ExpectedEvaluation expected = {    // Rows/columns    6, 6,    // Cost    7607.0,    // Residuals    { -19.0, -35.0,  // f      -59.0, -87.0,  // g      -27.0, -43.0   // h    },    // Gradient    {  146.0,  484.0,   // x       582.0, 1256.0,   // y      1450.0, 2604.0,   // z    },    // Jacobian    //                       x             y             z    { /* f(x, y) */ -2.0,  0.0, -12.0,   0.0,   0.0,   0.0,                     0.0, -4.0,   0.0, -16.0,   0.0,   0.0,      /* g(y, z) */  0.0,  0.0,  -6.0,   0.0, -20.0,   0.0,                     0.0,  0.0,   0.0,  -8.0,   0.0, -24.0,      /* h(z, x) */ -4.0,  0.0,   0.0,   0.0, -10.0,   0.0,                     0.0, -8.0,   0.0,   0.0,   0.0, -12.0    }  };  CheckAllEvaluationCombinations(Problem::EvaluateOptions(), expected);}TEST_F(ProblemEvaluateTest, ParameterAndResidualBlocksPassedInOptions) {  ExpectedEvaluation expected = {    // Rows/columns    6, 6,    // Cost    7607.0,    // Residuals    { -19.0, -35.0,  // f      -59.0, -87.0,  // g      -27.0, -43.0   // h    },    // Gradient    {  146.0,  484.0,   // x       582.0, 1256.0,   // y      1450.0, 2604.0,   // z    },    // Jacobian    //                       x             y             z    { /* f(x, y) */ -2.0,  0.0, -12.0,   0.0,   0.0,   0.0,                     0.0, -4.0,   0.0, -16.0,   0.0,   0.0,      /* g(y, z) */  0.0,  0.0,  -6.0,   0.0, -20.0,   0.0,                     0.0,  0.0,   0.0,  -8.0,   0.0, -24.0,      /* h(z, x) */ -4.0,  0.0,   0.0,   0.0, -10.0,   0.0,                     0.0, -8.0,   0.0,   0.0,   0.0, -12.0    }  };  Problem::EvaluateOptions evaluate_options;  evaluate_options.parameter_blocks = parameter_blocks_;  evaluate_options.residual_blocks = residual_blocks_;  CheckAllEvaluationCombinations(evaluate_options, expected);}TEST_F(ProblemEvaluateTest, ReorderedResidualBlocks) {  ExpectedEvaluation expected = {    // Rows/columns    6, 6,    // Cost    7607.0,    // Residuals    { -19.0, -35.0,  // f      -27.0, -43.0,  // h      -59.0, -87.0   // g    },    // Gradient    {  146.0,  484.0,   // x       582.0, 1256.0,   // y      1450.0, 2604.0,   // z    },    // Jacobian    //                       x             y             z    { /* f(x, y) */ -2.0,  0.0, -12.0,   0.0,   0.0,   0.0,                     0.0, -4.0,   0.0, -16.0,   0.0,   0.0,      /* h(z, x) */ -4.0,  0.0,   0.0,   0.0, -10.0,   0.0,                     0.0, -8.0,   0.0,   0.0,   0.0, -12.0,      /* g(y, z) */  0.0,  0.0,  -6.0,   0.0, -20.0,   0.0,                     0.0,  0.0,   0.0,  -8.0,   0.0, -24.0    }  };  Problem::EvaluateOptions evaluate_options;  evaluate_options.parameter_blocks = parameter_blocks_;  // f, h, g  evaluate_options.residual_blocks.push_back(residual_blocks_[0]);  evaluate_options.residual_blocks.push_back(residual_blocks_[2]);  evaluate_options.residual_blocks.push_back(residual_blocks_[1]);  CheckAllEvaluationCombinations(evaluate_options, expected);}TEST_F(ProblemEvaluateTest, ReorderedResidualBlocksAndReorderedParameterBlocks) {  ExpectedEvaluation expected = {    // Rows/columns    6, 6,    // Cost    7607.0,    // Residuals    { -19.0, -35.0,  // f      -27.0, -43.0,  // h      -59.0, -87.0   // g    },    // Gradient    {  1450.0, 2604.0,   // z        582.0, 1256.0,   // y        146.0,  484.0,   // x    },     // Jacobian    //                       z             y             x    { /* f(x, y) */   0.0,   0.0, -12.0,   0.0,  -2.0,   0.0,                      0.0,   0.0,   0.0, -16.0,   0.0,  -4.0,      /* h(z, x) */ -10.0,   0.0,   0.0,   0.0,  -4.0,   0.0,                      0.0, -12.0,   0.0,   0.0,   0.0,  -8.0,      /* g(y, z) */ -20.0,   0.0,  -6.0,   0.0,   0.0,   0.0,                      0.0, -24.0,   0.0,  -8.0,   0.0,   0.0    }  };  Problem::EvaluateOptions evaluate_options;  // z, y, x  evaluate_options.parameter_blocks.push_back(parameter_blocks_[2]);  evaluate_options.parameter_blocks.push_back(parameter_blocks_[1]);  evaluate_options.parameter_blocks.push_back(parameter_blocks_[0]);  // f, h, g  evaluate_options.residual_blocks.push_back(residual_blocks_[0]);  evaluate_options.residual_blocks.push_back(residual_blocks_[2]);  evaluate_options.residual_blocks.push_back(residual_blocks_[1]);  CheckAllEvaluationCombinations(evaluate_options, expected);}TEST_F(ProblemEvaluateTest, ConstantParameterBlock) {  ExpectedEvaluation expected = {    // Rows/columns    6, 6,    // Cost    7607.0,    // Residuals    { -19.0, -35.0,  // f      -59.0, -87.0,  // g      -27.0, -43.0   // h    },    // Gradient    {  146.0,  484.0,  // x         0.0,    0.0,  // y      1450.0, 2604.0,  // z    },    // Jacobian    //                       x             y             z    { /* f(x, y) */ -2.0,  0.0,   0.0,   0.0,   0.0,   0.0,                     0.0, -4.0,   0.0,   0.0,   0.0,   0.0,      /* g(y, z) */  0.0,  0.0,   0.0,   0.0, -20.0,   0.0,                     0.0,  0.0,   0.0,   0.0,   0.0, -24.0,      /* h(z, x) */ -4.0,  0.0,   0.0,   0.0, -10.0,   0.0,                     0.0, -8.0,   0.0,   0.0,   0.0, -12.0    }  };  problem_.SetParameterBlockConstant(parameters_ + 2);  CheckAllEvaluationCombinations(Problem::EvaluateOptions(), expected);}TEST_F(ProblemEvaluateTest, ExcludedAResidualBlock) {  ExpectedEvaluation expected = {    // Rows/columns    4, 6,    // Cost    2082.0,    // Residuals    { -19.0, -35.0,  // f      -27.0, -43.0   // h    },    // Gradient    {  146.0,  484.0,   // x       228.0,  560.0,   // y       270.0,  516.0,   // z    },    // Jacobian    //                       x             y             z    { /* f(x, y) */ -2.0,  0.0, -12.0,   0.0,   0.0,   0.0,                     0.0, -4.0,   0.0, -16.0,   0.0,   0.0,      /* h(z, x) */ -4.0,  0.0,   0.0,   0.0, -10.0,   0.0,                     0.0, -8.0,   0.0,   0.0,   0.0, -12.0    }  };  Problem::EvaluateOptions evaluate_options;  evaluate_options.residual_blocks.push_back(residual_blocks_[0]);  evaluate_options.residual_blocks.push_back(residual_blocks_[2]);  CheckAllEvaluationCombinations(evaluate_options, expected);}TEST_F(ProblemEvaluateTest, ExcludedParameterBlock) {  ExpectedEvaluation expected = {    // Rows/columns    6, 4,    // Cost    7607.0,    // Residuals    { -19.0, -35.0,  // f      -59.0, -87.0,  // g      -27.0, -43.0   // h    },    // Gradient    {  146.0,  484.0,  // x      1450.0, 2604.0,  // z    },    // Jacobian    //                       x             z    { /* f(x, y) */ -2.0,  0.0,   0.0,   0.0,                     0.0, -4.0,   0.0,   0.0,      /* g(y, z) */  0.0,  0.0, -20.0,   0.0,                     0.0,  0.0,   0.0, -24.0,      /* h(z, x) */ -4.0,  0.0, -10.0,   0.0,                     0.0, -8.0,   0.0, -12.0    }  };  Problem::EvaluateOptions evaluate_options;  // x, z  evaluate_options.parameter_blocks.push_back(parameter_blocks_[0]);  evaluate_options.parameter_blocks.push_back(parameter_blocks_[2]);  evaluate_options.residual_blocks = residual_blocks_;  CheckAllEvaluationCombinations(evaluate_options, expected);}TEST_F(ProblemEvaluateTest, ExcludedParameterBlockAndExcludedResidualBlock) {  ExpectedEvaluation expected = {    // Rows/columns    4, 4,    // Cost    6318.0,    // Residuals    { -19.0, -35.0,  // f      -59.0, -87.0,  // g    },    // Gradient    {   38.0,  140.0,  // x      1180.0, 2088.0,  // z    },    // Jacobian    //                       x             z    { /* f(x, y) */ -2.0,  0.0,   0.0,   0.0,                     0.0, -4.0,   0.0,   0.0,      /* g(y, z) */  0.0,  0.0, -20.0,   0.0,                     0.0,  0.0,   0.0, -24.0,    }  };  Problem::EvaluateOptions evaluate_options;  // x, z  evaluate_options.parameter_blocks.push_back(parameter_blocks_[0]);  evaluate_options.parameter_blocks.push_back(parameter_blocks_[2]);  evaluate_options.residual_blocks.push_back(residual_blocks_[0]);  evaluate_options.residual_blocks.push_back(residual_blocks_[1]);  CheckAllEvaluationCombinations(evaluate_options, expected);}TEST_F(ProblemEvaluateTest, LocalParameterization) {  ExpectedEvaluation expected = {    // Rows/columns    6, 5,    // Cost    7607.0,    // Residuals    { -19.0, -35.0,  // f      -59.0, -87.0,  // g      -27.0, -43.0   // h    },    // Gradient    {  146.0,  484.0,  // x      1256.0,          // y with SubsetParameterization      1450.0, 2604.0,  // z    },    // Jacobian    //                       x      y             z    { /* f(x, y) */ -2.0,  0.0,   0.0,   0.0,   0.0,                     0.0, -4.0, -16.0,   0.0,   0.0,      /* g(y, z) */  0.0,  0.0,   0.0, -20.0,   0.0,                     0.0,  0.0,  -8.0,   0.0, -24.0,      /* h(z, x) */ -4.0,  0.0,   0.0, -10.0,   0.0,                     0.0, -8.0,   0.0,   0.0, -12.0    }  };  vector<int> constant_parameters;  constant_parameters.push_back(0);  problem_.SetParameterization(parameters_ + 2,                               new SubsetParameterization(2,                                                          constant_parameters));  CheckAllEvaluationCombinations(Problem::EvaluateOptions(), expected);}struct IdentityFunctor {  template <typename T>  bool operator()(const T* x, const T* y, T* residuals) const {    residuals[0] = x[0];    residuals[1] = x[1];    residuals[2] = y[0];    residuals[3] = y[1];    residuals[4] = y[2];    return true;  }  static CostFunction* Create() {    return new AutoDiffCostFunction<IdentityFunctor, 5, 2, 3>(        new IdentityFunctor);  }};class ProblemEvaluateResidualBlockTest : public ::testing::Test { public:  static constexpr bool kApplyLossFunction = true;  static constexpr bool kDoNotApplyLossFunction = false;  static double loss_function_scale_; protected:  ProblemImpl problem_;  double x_[2] = {1, 2};  double y_[3] = {1, 2, 3};};double ProblemEvaluateResidualBlockTest::loss_function_scale_ = 2.0;TEST_F(ProblemEvaluateResidualBlockTest,       OneResidualBlockNoLossFunctionFullEval) {  ResidualBlockId residual_block_id =      problem_.AddResidualBlock(IdentityFunctor::Create(), nullptr, x_, y_);  Vector expected_f(5);  expected_f << 1, 2, 1, 2, 3;  Matrix expected_dfdx = Matrix::Zero(5, 2);  expected_dfdx.block(0, 0, 2, 2) = Matrix::Identity(2, 2);  Matrix expected_dfdy = Matrix::Zero(5, 3);  expected_dfdy.block(2, 0, 3, 3) = Matrix::Identity(3, 3);  double expected_cost = expected_f.squaredNorm() / 2.0;  double actual_cost;  Vector actual_f(5);  Matrix actual_dfdx(5, 2);  Matrix actual_dfdy(5, 3);  double* jacobians[2] = {actual_dfdx.data(), actual_dfdy.data()};  EXPECT_TRUE(problem_.EvaluateResidualBlock(residual_block_id,                                             kApplyLossFunction,                                             &actual_cost,                                             actual_f.data(),                                             jacobians));  EXPECT_NEAR(std::abs(expected_cost - actual_cost) / actual_cost,              0,              std::numeric_limits<double>::epsilon())      << actual_cost;  EXPECT_NEAR((expected_f - actual_f).norm() / actual_f.norm(),              0,              std::numeric_limits<double>::epsilon())      << actual_f;  EXPECT_NEAR((expected_dfdx - actual_dfdx).norm() / actual_dfdx.norm(),              0,              std::numeric_limits<double>::epsilon())      << actual_dfdx;  EXPECT_NEAR((expected_dfdy - actual_dfdy).norm() / actual_dfdy.norm(),              0,              std::numeric_limits<double>::epsilon())      << actual_dfdy;}TEST_F(ProblemEvaluateResidualBlockTest,       OneResidualBlockNoLossFunctionNullEval) {  ResidualBlockId residual_block_id =      problem_.AddResidualBlock(IdentityFunctor::Create(), nullptr, x_, y_);  EXPECT_TRUE(problem_.EvaluateResidualBlock(      residual_block_id, kApplyLossFunction, nullptr, nullptr, nullptr));}TEST_F(ProblemEvaluateResidualBlockTest, OneResidualBlockNoLossFunctionCost) {  ResidualBlockId residual_block_id =      problem_.AddResidualBlock(IdentityFunctor::Create(), nullptr, x_, y_);  Vector expected_f(5);  expected_f << 1, 2, 1, 2, 3;  double expected_cost = expected_f.squaredNorm() / 2.0;  double actual_cost;  EXPECT_TRUE(problem_.EvaluateResidualBlock(      residual_block_id, kApplyLossFunction, &actual_cost, nullptr, nullptr));  EXPECT_NEAR(std::abs(expected_cost - actual_cost) / actual_cost,              0,              std::numeric_limits<double>::epsilon())      << actual_cost;}TEST_F(ProblemEvaluateResidualBlockTest,       OneResidualBlockNoLossFunctionCostAndResidual) {  ResidualBlockId residual_block_id =      problem_.AddResidualBlock(IdentityFunctor::Create(), nullptr, x_, y_);  Vector expected_f(5);  expected_f << 1, 2, 1, 2, 3;  double expected_cost = expected_f.squaredNorm() / 2.0;  double actual_cost;  Vector actual_f(5);  EXPECT_TRUE(problem_.EvaluateResidualBlock(residual_block_id,                                             kApplyLossFunction,                                             &actual_cost,                                             actual_f.data(),                                             nullptr));  EXPECT_NEAR(std::abs(expected_cost - actual_cost) / actual_cost,              0,              std::numeric_limits<double>::epsilon())      << actual_cost;  EXPECT_NEAR((expected_f - actual_f).norm() / actual_f.norm(),              0,              std::numeric_limits<double>::epsilon())      << actual_f;}TEST_F(ProblemEvaluateResidualBlockTest,       OneResidualBlockNoLossFunctionCostResidualAndOneJacobian) {  ResidualBlockId residual_block_id =      problem_.AddResidualBlock(IdentityFunctor::Create(), nullptr, x_, y_);  Vector expected_f(5);  expected_f << 1, 2, 1, 2, 3;  Matrix expected_dfdx = Matrix::Zero(5, 2);  expected_dfdx.block(0, 0, 2, 2) = Matrix::Identity(2, 2);  double expected_cost = expected_f.squaredNorm() / 2.0;  double actual_cost;  Vector actual_f(5);  Matrix actual_dfdx(5, 2);  double* jacobians[2] = {actual_dfdx.data(), nullptr};  EXPECT_TRUE(problem_.EvaluateResidualBlock(residual_block_id,                                             kApplyLossFunction,                                             &actual_cost,                                             actual_f.data(),                                             jacobians));  EXPECT_NEAR(std::abs(expected_cost - actual_cost) / actual_cost,              0,              std::numeric_limits<double>::epsilon())      << actual_cost;  EXPECT_NEAR((expected_f - actual_f).norm() / actual_f.norm(),              0,              std::numeric_limits<double>::epsilon())      << actual_f;  EXPECT_NEAR((expected_dfdx - actual_dfdx).norm() / actual_dfdx.norm(),              0,              std::numeric_limits<double>::epsilon())      << actual_dfdx;}TEST_F(ProblemEvaluateResidualBlockTest,       OneResidualBlockNoLossFunctionResidual) {  ResidualBlockId residual_block_id =      problem_.AddResidualBlock(IdentityFunctor::Create(), nullptr, x_, y_);  Vector expected_f(5);  expected_f << 1, 2, 1, 2, 3;  Vector actual_f(5);  EXPECT_TRUE(problem_.EvaluateResidualBlock(residual_block_id,                                             kApplyLossFunction,                                             nullptr,                                             actual_f.data(),                                             nullptr));  EXPECT_NEAR((expected_f - actual_f).norm() / actual_f.norm(),              0,              std::numeric_limits<double>::epsilon())      << actual_f;}TEST_F(ProblemEvaluateResidualBlockTest, OneResidualBlockWithLossFunction) {  ResidualBlockId residual_block_id =      problem_.AddResidualBlock(IdentityFunctor::Create(),                                new ScaledLoss(nullptr, 2.0, TAKE_OWNERSHIP),                                x_,                                y_);  Vector expected_f(5);  expected_f << 1, 2, 1, 2, 3;  expected_f *= std::sqrt(loss_function_scale_);  Matrix expected_dfdx = Matrix::Zero(5, 2);  expected_dfdx.block(0, 0, 2, 2) = Matrix::Identity(2, 2);  expected_dfdx *= std::sqrt(loss_function_scale_);  Matrix expected_dfdy = Matrix::Zero(5, 3);  expected_dfdy.block(2, 0, 3, 3) = Matrix::Identity(3, 3);  expected_dfdy *= std::sqrt(loss_function_scale_);  double expected_cost = expected_f.squaredNorm() / 2.0;  double actual_cost;  Vector actual_f(5);  Matrix actual_dfdx(5, 2);  Matrix actual_dfdy(5, 3);  double* jacobians[2] = {actual_dfdx.data(), actual_dfdy.data()};  EXPECT_TRUE(problem_.EvaluateResidualBlock(residual_block_id,                                             kApplyLossFunction,                                             &actual_cost,                                             actual_f.data(),                                             jacobians));  EXPECT_NEAR(std::abs(expected_cost - actual_cost) / actual_cost,              0,              std::numeric_limits<double>::epsilon())      << actual_cost;  EXPECT_NEAR((expected_f - actual_f).norm() / actual_f.norm(),              0,              std::numeric_limits<double>::epsilon())      << actual_f;  EXPECT_NEAR((expected_dfdx - actual_dfdx).norm() / actual_dfdx.norm(),              0,              std::numeric_limits<double>::epsilon())      << actual_dfdx;  EXPECT_NEAR((expected_dfdy - actual_dfdy).norm() / actual_dfdy.norm(),              0,              std::numeric_limits<double>::epsilon())      << actual_dfdy;}TEST_F(ProblemEvaluateResidualBlockTest,       OneResidualBlockWithLossFunctionDisabled) {  ResidualBlockId residual_block_id =      problem_.AddResidualBlock(IdentityFunctor::Create(),                                new ScaledLoss(nullptr, 2.0, TAKE_OWNERSHIP),                                x_,                                y_);  Vector expected_f(5);  expected_f << 1, 2, 1, 2, 3;  Matrix expected_dfdx = Matrix::Zero(5, 2);  expected_dfdx.block(0, 0, 2, 2) = Matrix::Identity(2, 2);  Matrix expected_dfdy = Matrix::Zero(5, 3);  expected_dfdy.block(2, 0, 3, 3) = Matrix::Identity(3, 3);  double expected_cost = expected_f.squaredNorm() / 2.0;  double actual_cost;  Vector actual_f(5);  Matrix actual_dfdx(5, 2);  Matrix actual_dfdy(5, 3);  double* jacobians[2] = {actual_dfdx.data(), actual_dfdy.data()};  EXPECT_TRUE(problem_.EvaluateResidualBlock(residual_block_id,                                             kDoNotApplyLossFunction,                                             &actual_cost,                                             actual_f.data(),                                             jacobians));  EXPECT_NEAR(std::abs(expected_cost - actual_cost) / actual_cost,              0,              std::numeric_limits<double>::epsilon())      << actual_cost;  EXPECT_NEAR((expected_f - actual_f).norm() / actual_f.norm(),              0,              std::numeric_limits<double>::epsilon())      << actual_f;  EXPECT_NEAR((expected_dfdx - actual_dfdx).norm() / actual_dfdx.norm(),              0,              std::numeric_limits<double>::epsilon())      << actual_dfdx;  EXPECT_NEAR((expected_dfdy - actual_dfdy).norm() / actual_dfdy.norm(),              0,              std::numeric_limits<double>::epsilon())      << actual_dfdy;}TEST_F(ProblemEvaluateResidualBlockTest,       OneResidualBlockWithOneLocalParameterization) {  ResidualBlockId residual_block_id =      problem_.AddResidualBlock(IdentityFunctor::Create(), nullptr, x_, y_);  problem_.SetParameterization(x_, new SubsetParameterization(2, {1}));  Vector expected_f(5);  expected_f << 1, 2, 1, 2, 3;  Matrix expected_dfdx = Matrix::Zero(5, 1);  expected_dfdx.block(0, 0, 1, 1) = Matrix::Identity(1, 1);  Matrix expected_dfdy = Matrix::Zero(5, 3);  expected_dfdy.block(2, 0, 3, 3) = Matrix::Identity(3, 3);  double expected_cost = expected_f.squaredNorm() / 2.0;  double actual_cost;  Vector actual_f(5);  Matrix actual_dfdx(5, 1);  Matrix actual_dfdy(5, 3);  double* jacobians[2] = {actual_dfdx.data(), actual_dfdy.data()};  EXPECT_TRUE(problem_.EvaluateResidualBlock(residual_block_id,                                             kApplyLossFunction,                                             &actual_cost,                                             actual_f.data(),                                             jacobians));  EXPECT_NEAR(std::abs(expected_cost - actual_cost) / actual_cost,              0,              std::numeric_limits<double>::epsilon())      << actual_cost;  EXPECT_NEAR((expected_f - actual_f).norm() / actual_f.norm(),              0,              std::numeric_limits<double>::epsilon())      << actual_f;  EXPECT_NEAR((expected_dfdx - actual_dfdx).norm() / actual_dfdx.norm(),              0,              std::numeric_limits<double>::epsilon())      << actual_dfdx;  EXPECT_NEAR((expected_dfdy - actual_dfdy).norm() / actual_dfdy.norm(),              0,              std::numeric_limits<double>::epsilon())      << actual_dfdy;}TEST_F(ProblemEvaluateResidualBlockTest,       OneResidualBlockWithTwoLocalParameterizations) {  ResidualBlockId residual_block_id =      problem_.AddResidualBlock(IdentityFunctor::Create(), nullptr, x_, y_);  problem_.SetParameterization(x_, new SubsetParameterization(2, {1}));  problem_.SetParameterization(y_, new SubsetParameterization(3, {2}));  Vector expected_f(5);  expected_f << 1, 2, 1, 2, 3;  Matrix expected_dfdx = Matrix::Zero(5, 1);  expected_dfdx.block(0, 0, 1, 1) = Matrix::Identity(1, 1);  Matrix expected_dfdy = Matrix::Zero(5, 2);  expected_dfdy.block(2, 0, 2, 2) = Matrix::Identity(2, 2);  double expected_cost = expected_f.squaredNorm() / 2.0;  double actual_cost;  Vector actual_f(5);  Matrix actual_dfdx(5, 1);  Matrix actual_dfdy(5, 2);  double* jacobians[2] = {actual_dfdx.data(), actual_dfdy.data()};  EXPECT_TRUE(problem_.EvaluateResidualBlock(residual_block_id,                                             kApplyLossFunction,                                             &actual_cost,                                             actual_f.data(),                                             jacobians));  EXPECT_NEAR(std::abs(expected_cost - actual_cost) / actual_cost,              0,              std::numeric_limits<double>::epsilon())      << actual_cost;  EXPECT_NEAR((expected_f - actual_f).norm() / actual_f.norm(),              0,              std::numeric_limits<double>::epsilon())      << actual_f;  EXPECT_NEAR((expected_dfdx - actual_dfdx).norm() / actual_dfdx.norm(),              0,              std::numeric_limits<double>::epsilon())      << actual_dfdx;  EXPECT_NEAR((expected_dfdy - actual_dfdy).norm() / actual_dfdy.norm(),              0,              std::numeric_limits<double>::epsilon())      << actual_dfdy;}TEST_F(ProblemEvaluateResidualBlockTest,       OneResidualBlockWithOneConstantParameterBlock) {  ResidualBlockId residual_block_id =      problem_.AddResidualBlock(IdentityFunctor::Create(), nullptr, x_, y_);  problem_.SetParameterBlockConstant(x_);  Vector expected_f(5);  expected_f << 1, 2, 1, 2, 3;  Matrix expected_dfdy = Matrix::Zero(5, 3);  expected_dfdy.block(2, 0, 3, 3) = Matrix::Identity(3, 3);  double expected_cost = expected_f.squaredNorm() / 2.0;  double actual_cost;  Vector actual_f(5);  Matrix actual_dfdx(5, 2);  Matrix actual_dfdy(5, 3);  // Try evaluating both Jacobians, this should fail.  double* jacobians[2] = {actual_dfdx.data(), actual_dfdy.data()};  EXPECT_FALSE(problem_.EvaluateResidualBlock(residual_block_id,                                              kApplyLossFunction,                                              &actual_cost,                                              actual_f.data(),                                              jacobians));  jacobians[0] = nullptr;  EXPECT_TRUE(problem_.EvaluateResidualBlock(residual_block_id,                                             kApplyLossFunction,                                             &actual_cost,                                             actual_f.data(),                                             jacobians));  EXPECT_NEAR(std::abs(expected_cost - actual_cost) / actual_cost,              0,              std::numeric_limits<double>::epsilon())      << actual_cost;  EXPECT_NEAR((expected_f - actual_f).norm() / actual_f.norm(),              0,              std::numeric_limits<double>::epsilon())      << actual_f;  EXPECT_NEAR((expected_dfdy - actual_dfdy).norm() / actual_dfdy.norm(),              0,              std::numeric_limits<double>::epsilon())      << actual_dfdy;}TEST_F(ProblemEvaluateResidualBlockTest,       OneResidualBlockWithAllConstantParameterBlocks) {  ResidualBlockId residual_block_id =      problem_.AddResidualBlock(IdentityFunctor::Create(), nullptr, x_, y_);  problem_.SetParameterBlockConstant(x_);  problem_.SetParameterBlockConstant(y_);  Vector expected_f(5);  expected_f << 1, 2, 1, 2, 3;  double expected_cost = expected_f.squaredNorm() / 2.0;  double actual_cost;  Vector actual_f(5);  Matrix actual_dfdx(5, 2);  Matrix actual_dfdy(5, 3);  // Try evaluating with one or more Jacobians, this should fail.  double* jacobians[2] = {actual_dfdx.data(), actual_dfdy.data()};  EXPECT_FALSE(problem_.EvaluateResidualBlock(residual_block_id,                                              kApplyLossFunction,                                              &actual_cost,                                              actual_f.data(),                                              jacobians));  jacobians[0] = nullptr;  EXPECT_FALSE(problem_.EvaluateResidualBlock(residual_block_id,                                              kApplyLossFunction,                                              &actual_cost,                                              actual_f.data(),                                              jacobians));  jacobians[1] = nullptr;  EXPECT_TRUE(problem_.EvaluateResidualBlock(residual_block_id,                                             kApplyLossFunction,                                             &actual_cost,                                             actual_f.data(),                                             jacobians));  EXPECT_NEAR(std::abs(expected_cost - actual_cost) / actual_cost,              0,              std::numeric_limits<double>::epsilon())      << actual_cost;  EXPECT_NEAR((expected_f - actual_f).norm() / actual_f.norm(),              0,              std::numeric_limits<double>::epsilon())      << actual_f;}TEST_F(ProblemEvaluateResidualBlockTest,       OneResidualBlockWithOneParameterBlockConstantAndParameterBlockChanged) {  ResidualBlockId residual_block_id =      problem_.AddResidualBlock(IdentityFunctor::Create(), nullptr, x_, y_);  problem_.SetParameterBlockConstant(x_);  x_[0] = 2;  y_[2] = 1;  Vector expected_f(5);  expected_f << 2, 2, 1, 2, 1;  Matrix expected_dfdy = Matrix::Zero(5, 3);  expected_dfdy.block(2, 0, 3, 3) = Matrix::Identity(3, 3);  double expected_cost = expected_f.squaredNorm() / 2.0;  double actual_cost;  Vector actual_f(5);  Matrix actual_dfdx(5, 2);  Matrix actual_dfdy(5, 3);  // Try evaluating with one or more Jacobians, this should fail.  double* jacobians[2] = {actual_dfdx.data(), actual_dfdy.data()};  EXPECT_FALSE(problem_.EvaluateResidualBlock(residual_block_id,                                              kApplyLossFunction,                                              &actual_cost,                                              actual_f.data(),                                              jacobians));  jacobians[0] = nullptr;  EXPECT_TRUE(problem_.EvaluateResidualBlock(residual_block_id,                                             kApplyLossFunction,                                             &actual_cost,                                             actual_f.data(),                                             jacobians));  EXPECT_NEAR(std::abs(expected_cost - actual_cost) / actual_cost,              0,              std::numeric_limits<double>::epsilon())      << actual_cost;  EXPECT_NEAR((expected_f - actual_f).norm() / actual_f.norm(),              0,              std::numeric_limits<double>::epsilon())      << actual_f;  EXPECT_NEAR((expected_dfdy - actual_dfdy).norm() / actual_dfdy.norm(),              0,              std::numeric_limits<double>::epsilon())      << actual_dfdy;}TEST(Problem, SetAndGetParameterLowerBound) {  Problem problem;  double x[] = {1.0, 2.0};  problem.AddParameterBlock(x, 2);  EXPECT_EQ(problem.GetParameterLowerBound(x, 0),            -std::numeric_limits<double>::max());  EXPECT_EQ(problem.GetParameterLowerBound(x, 1),            -std::numeric_limits<double>::max());  problem.SetParameterLowerBound(x, 0, -1.0);  EXPECT_EQ(problem.GetParameterLowerBound(x, 0), -1.0);  EXPECT_EQ(problem.GetParameterLowerBound(x, 1),            -std::numeric_limits<double>::max());  problem.SetParameterLowerBound(x, 0, -2.0);  EXPECT_EQ(problem.GetParameterLowerBound(x, 0), -2.0);  EXPECT_EQ(problem.GetParameterLowerBound(x, 1),            -std::numeric_limits<double>::max());  problem.SetParameterLowerBound(x, 0, -std::numeric_limits<double>::max());  EXPECT_EQ(problem.GetParameterLowerBound(x, 0),            -std::numeric_limits<double>::max());  EXPECT_EQ(problem.GetParameterLowerBound(x, 1),            -std::numeric_limits<double>::max());}TEST(Problem, SetAndGetParameterUpperBound) {  Problem problem;  double x[] = {1.0, 2.0};  problem.AddParameterBlock(x, 2);  EXPECT_EQ(problem.GetParameterUpperBound(x, 0),            std::numeric_limits<double>::max());  EXPECT_EQ(problem.GetParameterUpperBound(x, 1),            std::numeric_limits<double>::max());  problem.SetParameterUpperBound(x, 0, -1.0);  EXPECT_EQ(problem.GetParameterUpperBound(x, 0), -1.0);  EXPECT_EQ(problem.GetParameterUpperBound(x, 1),            std::numeric_limits<double>::max());  problem.SetParameterUpperBound(x, 0, -2.0);  EXPECT_EQ(problem.GetParameterUpperBound(x, 0), -2.0);  EXPECT_EQ(problem.GetParameterUpperBound(x, 1),            std::numeric_limits<double>::max());  problem.SetParameterUpperBound(x, 0, std::numeric_limits<double>::max());  EXPECT_EQ(problem.GetParameterUpperBound(x, 0),            std::numeric_limits<double>::max());  EXPECT_EQ(problem.GetParameterUpperBound(x, 1),            std::numeric_limits<double>::max());}}  // namespace internal}  // namespace ceres
 |