• 【slam十四讲第二版】【课后习题】【第九讲~后端2】


    0 前言

    1 课后题

    1.1 将位姿图中的误差交换位置,推导按照此定义的左乘扰动雅可比矩阵

    1.2 参照g2o程序,在Ceres中实现对“球”位姿图的优化

    1.2.1 pose_graph_ceres_SE3.cpp

    #include 
    #include 
    
    #include 
    #include 
    
    
    #include 
    #include 
    
    #include "sophus/so3.h"
    #include "sophus/se3.h"
    
    // 需要设置新的参数域,因此需要继承LocalParameterization
    // 具体可以参考http://www.ceres-solver.org/nnls_modeling.html?highlight=localparameterization#localparameterization
    class SE3Parameterization : public ceres::LocalParameterization
    {
    public:
        SE3Parameterization() {}
        virtual ~SE3Parameterization() {}
    
        // 如果更新,此处使用李代数更新,而不是简单的加减
        virtual bool Plus(const double* x,
                          const double* delta,
                          double* x_plus_delta) const
        {
            Eigen::Map<const Eigen::Matrix<double, 6, 1>> lie(x);
            Eigen::Map<const Eigen::Matrix<double, 6, 1>> delta_lie(delta);
    
            Sophus::SE3 T = Sophus::SE3::exp(lie);
            Sophus::SE3 delta_T = Sophus::SE3::exp(delta_lie);
    
            // 李代数左乘更新
            Eigen::Matrix<double, 6, 1> x_plus_delta_lie = (delta_T * T).log();
    
            for(int i = 0; i < 6; ++i)
                x_plus_delta[i] = x_plus_delta_lie(i, 0);
    
            return true;
        }
    
        // 如果计算Jacobian,此处大概是局部求导;不过由于我已经在残差函数中仔细计算了导数,所以这里单位矩阵就好
        virtual bool ComputeJacobian(const double* x,
                                     double* jacobian) const
        {
            ceres::MatrixRef(jacobian, 6, 6) = ceres::Matrix::Identity(6, 6);
            return true;
        }
        virtual int GlobalSize() const { return 6; }
        virtual int LocalSize() const { return 6; }
    };
    
    // 自己求导数的类,需要重构SizedCostFunction
    class PosegraphBA: public ceres::SizedCostFunction<6,6,6>
    {
    public:
        Sophus::SE3 deltaSE3Inv;
    
        PosegraphBA(double x,double y,double z,
                    double s,double vx,double vy,double vz)
        {
            Eigen::Quaterniond q( s,vx, vy, vz );
            q.normalize();
            deltaSE3Inv = Sophus::SE3( q,Eigen::Vector3d( x, y, z ) ).inverse();
        }
    
        //  Evaluate是很重要的一个函数
        virtual bool Evaluate(double const* const* pose,
                              double *residual,
                              double **jacobians) const
        {
            // Get Pose A
            Eigen::Map<const Eigen::Matrix<double,6,1>> poseAVec6d(pose[0]);
            Sophus::SE3 poseASE3 = Sophus::SE3::exp(poseAVec6d);
    
            // Get Pose B
            Eigen::Map<const Eigen::Matrix<double,6,1>> poseBVec6d(pose[1]);
            Sophus::SE3 poseBSE3 = Sophus::SE3::exp(poseBVec6d);
    
            // Compute Error
            Sophus::SE3 errorSE3 = deltaSE3Inv*poseASE3.inverse()*poseBSE3;
            Eigen::Matrix<double,6,1> errorVec6d = errorSE3.log();
    
            // 残差项
            residual[0] = errorVec6d(0);
            residual[1] = errorVec6d(1);
            residual[2] = errorVec6d(2);
            residual[3] = errorVec6d(3);
            residual[4] = errorVec6d(4);
            residual[5] = errorVec6d(5);
    
            if( !jacobians )
                return true;
    
            if( !jacobians[0] && !jacobians[1] )
                return true;
    
            // 以下都是jacobian的公式,具体也对应了公式
            // 可以参考http://www.ceres-solver.org/nnls_modeling.html?highlight=evaluate#_CPPv2N5ceres12CostFunction8EvaluateEPPCdPdPPd
            {
                // 公式11.10 J_r^{-1}
                Eigen::Matrix<double,6,6> J;
                J.block(0,0,3,3) = Sophus::SO3::hat(errorSE3.so3().log());
                J.block(0,3,3,3) = Sophus::SO3::hat(errorSE3.translation());
                J.block(3,0,3,3) = Eigen::Matrix3d::Zero(3,3);
                J.block(3,3,3,3) = Sophus::SO3::hat(errorSE3.so3().log());
                J = J*0.5 + Eigen::Matrix<double,6,6>::Identity();
    
                // 公式11.8
                // row correspond with error
                // col correspond with parameterA
                Eigen::Matrix<double,6,6> jacA = - J * poseBSE3.inverse().Adj();
    
                jacobians[0][ 0] = jacA(0,0); jacobians[0][ 1] = jacA(1,0); jacobians[0][ 2] = jacA(2,0); jacobians[0][ 3] = jacA(3,0); jacobians[0][ 4] = jacA(4,0); jacobians[0][ 5] = jacA(5,0);
                jacobians[0][ 6] = jacA(0,1); jacobians[0][ 7] = jacA(1,1); jacobians[0][ 8] = jacA(2,1); jacobians[0][ 9] = jacA(3,1); jacobians[0][10] = jacA(4,1); jacobians[0][11] = jacA(5,1);
                jacobians[0][12] = jacA(0,2); jacobians[0][13] = jacA(1,2); jacobians[0][14] = jacA(2,2); jacobians[0][15] = jacA(3,2); jacobians[0][16] = jacA(4,2); jacobians[0][17] = jacA(5,2);
                jacobians[0][18] = jacA(0,3); jacobians[0][19] = jacA(1,3); jacobians[0][20] = jacA(2,3); jacobians[0][21] = jacA(3,3); jacobians[0][22] = jacA(4,3); jacobians[0][23] = jacA(5,3);
                jacobians[0][24] = jacA(0,4); jacobians[0][25] = jacA(1,4); jacobians[0][26] = jacA(2,4); jacobians[0][27] = jacA(3,4); jacobians[0][28] = jacA(4,4); jacobians[0][29] = jacA(5,4);
                jacobians[0][30] = jacA(0,5); jacobians[0][31] = jacA(1,5); jacobians[0][32] = jacA(2,5); jacobians[0][33] = jacA(3,5); jacobians[0][34] = jacA(4,5); jacobians[0][35] = jacA(5,5);
    
                // 公式11.9
                Eigen::Matrix<double,6,6> jacB =   J * poseBSE3.inverse().Adj();
    
                jacobians[1][ 0] = jacB(0,0); jacobians[1][ 1] = jacB(1,0); jacobians[1][ 2] = jacB(2,0); jacobians[1][ 3] = jacB(3,0); jacobians[1][ 4] = jacB(4,0); jacobians[1][ 5] = jacB(5,0);
                jacobians[1][ 6] = jacB(0,1); jacobians[1][ 7] = jacB(1,1); jacobians[1][ 8] = jacB(2,1); jacobians[1][ 9] = jacB(3,1); jacobians[1][10] = jacB(4,1); jacobians[1][11] = jacB(5,1);
                jacobians[1][12] = jacB(0,2); jacobians[1][13] = jacB(1,2); jacobians[1][14] = jacB(2,2); jacobians[1][15] = jacB(3,2); jacobians[1][16] = jacB(4,2); jacobians[1][17] = jacB(5,2);
                jacobians[1][18] = jacB(0,3); jacobians[1][19] = jacB(1,3); jacobians[1][20] = jacB(2,3); jacobians[1][21] = jacB(3,3); jacobians[1][22] = jacB(4,3); jacobians[1][23] = jacB(5,3);
                jacobians[1][24] = jacB(0,4); jacobians[1][25] = jacB(1,4); jacobians[1][26] = jacB(2,4); jacobians[1][27] = jacB(3,4); jacobians[1][28] = jacB(4,4); jacobians[1][29] = jacB(5,4);
                jacobians[1][30] = jacB(0,5); jacobians[1][31] = jacB(1,5); jacobians[1][32] = jacB(2,5); jacobians[1][33] = jacB(3,5); jacobians[1][34] = jacB(4,5); jacobians[1][35] = jacB(5,5);
    
            }
    
            return true;
        }
    };
    
    
    
    int main( int argc, char *argv[] )
    {
        google::InitGoogleLogging(argv[0]);
    
        if(argc<2)
        {
            std::cerr<<"./pose_graph_ceres_SE3 sphere.g2o"<<std::endl;
            return -1;
        }
    
        std::cout<<"Input g2o file: "<<argv[1]<<std::endl;
    
    
        std::ifstream g2oFile( argv[1] );
        if ( !g2oFile )
        {
            std::cout<<"file "<<argv[1]<<" does not exist."<<std::endl;
            return -1;
        }
        // Count Pose and Edge
        int poseCount = 0;
        int edgeCount = 0;
        std::string fileLine;
        while( std::getline(g2oFile,fileLine) )
        {
            if(fileLine[0]=='V')
            {
                poseCount++;
            }
            if(fileLine[0]=='E')
            {
                edgeCount++;
            }
        }
        g2oFile.clear();
        g2oFile.seekg(std::ios::beg);
    
    
        std::cout<<poseCount<<std::endl;
        std::cout<<edgeCount<<std::endl;
    
    
        // Init Ceres
        ceres::Problem problem;
    
        // Load Data
        double *poseData = new double[poseCount*6];
        for( int i=0; i<poseCount; i++ )
        {
            std::string flag;
            int id;
            double x,y,z,s,vx,vy,vz;
            g2oFile>>flag>>id>>x>>y>>z>>vx>>vy>>vz>>s;
            Eigen::Quaterniond q( s,vx, vy, vz );
            q.normalize();
            Eigen::Matrix<double,6,1> poseVec6d = Sophus::SE3( q,Eigen::Vector3d( x, y, z ) ).log();
    
            poseData[6*i+0] = poseVec6d(0);
            poseData[6*i+1] = poseVec6d(1);
            poseData[6*i+2] = poseVec6d(2);
            poseData[6*i+3] = poseVec6d(3);
            poseData[6*i+4] = poseVec6d(4);
            poseData[6*i+5] = poseVec6d(5);
        }
    
        ceres::LocalParameterization *local_parameterization = new SE3Parameterization();
    
        // Add Residual
        for( int i=0; i<edgeCount; i++ )
        {
            std::string flag;
            int idA,idB;
            double x,y,z,s,vx,vy,vz;
            double temp;
            g2oFile>>flag>>idA>>idB>>x>>y>>z>>vx>>vy>>vz>>s;
            // I dont't know how to use info
            for( int j=0; j<21; j++ )
            {
                g2oFile>>temp;
            }
    
            ceres::CostFunction *costFunction = new PosegraphBA(x,y,z,s,vx,vy,vz);
    
            problem.AddResidualBlock (  costFunction,
                                        nullptr,
                                        poseData+6*idA,
                                        poseData+6*idB
            );
    
            problem.SetParameterization(poseData+6*idA,local_parameterization);
            problem.SetParameterization(poseData+6*idB,local_parameterization);
    
        }
        g2oFile.close();
    
    
        // Set Ceres
        ceres::Solver::Options options;
        // options.linear_solver_type = ceres::SPARSE_NORMAL_CHOLESKY;
        options.minimizer_progress_to_stdout = true;
    
        // Solve
        ceres::Solver::Summary summary;
        ceres::Solve ( options, &problem, &summary );
    
        // Report
        std::cout<<summary.FullReport() <<std::endl;
        std::ofstream txt("1.txt");
        for( int i=0; i<poseCount; i++ )
        {
            Eigen::Map<const Eigen::Matrix<double,6,1>> poseAVec6d( poseData+6*i );
            Sophus::SE3 poseSE3 = Sophus::SE3::exp(poseAVec6d);
    
            txt<<poseSE3.translation().transpose()<<std::endl;
        }
    
        txt.close();
    
    
        // Release Data
        delete []poseData;
    
        return 0;
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264

    1.2.2 CMakeLists.txt

    cmake_minimum_required(VERSION 2.8)
    
    project(pose_graph_ceres_SE3)
    set(CMAKE_BUILD_TYPE "Release")
    set(CMAKE_CXX_STANDARD 14)
    
    include_directories("/usr/include/eigen3")
    find_package(Sophus REQUIRED)
    Find_Package(Ceres REQUIRED)
    
    set(Sophus_LIBRARIES "/usr/local/lib/libSophus.so")
    
    include_directories(${Sophus_INCLUDE_DIRS} )
    
    add_executable(pose_graph_ceres_SE3 src/pose_graph_ceres_SE3.cpp)
    
    target_link_libraries(pose_graph_ceres_SE3 ${CERES_LIBRARIES} ${Sophus_LIBRARIES} fmt)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    1.2.3 rotation.h

    #ifndef ROTATION_H
    #define ROTATION_H
    
    #include 
    #include 
    #include 
    
    //
    // math functions needed for rotation conversion. 
    
    // dot and cross production 
    
    template<typename T>
    inline T DotProduct(const T x[3], const T y[3]) {
        return (x[0] * y[0] + x[1] * y[1] + x[2] * y[2]);
    }
    
    template<typename T>
    inline void CrossProduct(const T x[3], const T y[3], T result[3]) {
        result[0] = x[1] * y[2] - x[2] * y[1];
        result[1] = x[2] * y[0] - x[0] * y[2];
        result[2] = x[0] * y[1] - x[1] * y[0];
    }
    
    
    //
    
    
    // Converts from a angle anxis to quaternion : 
    template<typename T>
    inline void AngleAxisToQuaternion(const T *angle_axis, T *quaternion) {
        const T &a0 = angle_axis[0];
        const T &a1 = angle_axis[1];
        const T &a2 = angle_axis[2];
        const T theta_squared = a0 * a0 + a1 * a1 + a2 * a2;
    
        if (theta_squared > T(std::numeric_limits<double>::epsilon())) {
            const T theta = sqrt(theta_squared);
            const T half_theta = theta * T(0.5);
            const T k = sin(half_theta) / theta;
            quaternion[0] = cos(half_theta);
            quaternion[1] = a0 * k;
            quaternion[2] = a1 * k;
            quaternion[3] = a2 * k;
        } else { // in case if theta_squared is zero
            const T k(0.5);
            quaternion[0] = T(1.0);
            quaternion[1] = a0 * k;
            quaternion[2] = a1 * k;
            quaternion[3] = a2 * k;
        }
    }
    
    template<typename T>
    inline void QuaternionToAngleAxis(const T *quaternion, T *angle_axis) {
        const T &q1 = quaternion[1];
        const T &q2 = quaternion[2];
        const T &q3 = quaternion[3];
        const T sin_squared_theta = q1 * q1 + q2 * q2 + q3 * q3;
    
        // For quaternions representing non-zero rotation, the conversion
        // is numercially stable
        if (sin_squared_theta > T(std::numeric_limits<double>::epsilon())) {
            const T sin_theta = sqrt(sin_squared_theta);
            const T &cos_theta = quaternion[0];
    
            // If cos_theta is negative, theta is greater than pi/2, which
            // means that angle for the angle_axis vector which is 2 * theta
            // would be greater than pi...
    
            const T two_theta = T(2.0) * ((cos_theta < 0.0)
                                          ? atan2(-sin_theta, -cos_theta)
                                          : atan2(sin_theta, cos_theta));
            const T k = two_theta / sin_theta;
    
            angle_axis[0] = q1 * k;
            angle_axis[1] = q2 * k;
            angle_axis[2] = q3 * k;
        } else {
            // For zero rotation, sqrt() will produce NaN in derivative since
            // the argument is zero. By approximating with a Taylor series,
            // and truncating at one term, the value and first derivatives will be
            // computed correctly when Jets are used..
            const T k(2.0);
            angle_axis[0] = q1 * k;
            angle_axis[1] = q2 * k;
            angle_axis[2] = q3 * k;
        }
    
    }
    
    template<typename T>
    inline void AngleAxisRotatePoint(const T angle_axis[3], const T pt[3], T result[3]) {//内联函数作用是是pt经过轴角angle_axis旋转后得到的点result
        const T theta2 = DotProduct(angle_axis, angle_axis);
        if (theta2 > T(std::numeric_limits<double>::epsilon())) {
            // Away from zero, use the rodriguez formula 远离零,使用罗德里格斯公式
            //
            //   result = pt costheta +
            //            (w x pt) * sintheta +
            //            w (w . pt) (1 - costheta)
            //
            // We want to be careful to only evaluate the square root if the
            // norm of the angle_axis vector is greater than zero. Otherwise
            // we get a division by zero.
            // 我们要注意的是,仅当轴角向量的范数大于零时才计算平方根。否则我们得到的除法是零。
            const T theta = sqrt(theta2);
            const T costheta = cos(theta);
            const T sintheta = sin(theta);
            const T theta_inverse = 1.0 / theta;
    
            const T w[3] = {angle_axis[0] * theta_inverse,
                            angle_axis[1] * theta_inverse,
                            angle_axis[2] * theta_inverse};//这个表示的单位长度的向量
    
            // Explicitly inlined evaluation of the cross product for
            // performance reasons.
            // 出于性能原因,对交叉积进行了明确的内联评估。
            /*const T w_cross_pt[3] = { w[1] * pt[2] - w[2] * pt[1],
                                      w[2] * pt[0] - w[0] * pt[2],
                                      w[0] * pt[1] - w[1] * pt[0] };*/
            T w_cross_pt[3];
            CrossProduct(w, pt, w_cross_pt);
    
            const T tmp = DotProduct(w, pt) * (T(1.0) - costheta);
            //    (w[0] * pt[0] + w[1] * pt[1] + w[2] * pt[2]) * (T(1.0) - costheta);
    
            result[0] = pt[0] * costheta + w_cross_pt[0] * sintheta + w[0] * tmp;
            result[1] = pt[1] * costheta + w_cross_pt[1] * sintheta + w[1] * tmp;
            result[2] = pt[2] * costheta + w_cross_pt[2] * sintheta + w[2] * tmp;
        } else {
            // Near zero, the first order Taylor approximation of the rotation
            // matrix R corresponding to a vector w and angle w is
            //
            //   R = I + hat(w) * sin(theta)
            //
            // But sintheta ~ theta and theta * w = angle_axis, which gives us
            //
            //  R = I + hat(w)
            //
            // and actually performing multiplication with the point pt, gives us
            // R * pt = pt + w x pt.
            //
            // Switching to the Taylor expansion near zero provides meaningful
            // derivatives when evaluated using Jets.
            //
            // Explicitly inlined evaluation of the cross product for
            // performance reasons.
            /*const T w_cross_pt[3] = { angle_axis[1] * pt[2] - angle_axis[2] * pt[1],
                                      angle_axis[2] * pt[0] - angle_axis[0] * pt[2],
                                      angle_axis[0] * pt[1] - angle_axis[1] * pt[0] };*/
            T w_cross_pt[3];
            CrossProduct(angle_axis, pt, w_cross_pt);
    
            result[0] = pt[0] + w_cross_pt[0];
            result[1] = pt[1] + w_cross_pt[1];
            result[2] = pt[2] + w_cross_pt[2];
        }
    }
    
    #endif // rotation.h
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160

    1.2.4 输出

    /home/bupo/my_study/slam14/slam14_my/cap10/pose_graph_ceres_SE3/cmake-build-debug/pose_graph_ceres_SE3 ./src/sphere.g2o
    Input g2o file: ./src/sphere.g2o
    2500
    9799
    iter      cost      cost_change  |gradient|   |step|    tr_ratio  tr_radius  ls_iter  iter_time  total_time
       0  4.913445e+05    0.00e+00    3.71e+02   0.00e+00   0.00e+00  1.00e+04        0    1.41e-02    1.82e-02
       1  1.707888e+08   -1.70e+08    3.71e+02   6.61e+03  -3.07e+03  5.00e+03        1    2.01e-01    2.20e-01
       2  1.672780e+08   -1.67e+08    3.71e+02   6.61e+03  -3.57e+03  1.25e+03        1    1.91e-01    4.11e-01
       3  1.474954e+08   -1.47e+08    3.71e+02   6.43e+03  -5.09e+03  1.56e+02        1    1.89e-01    6.00e-01
       4  1.225161e+08   -1.22e+08    3.71e+02   6.63e+03  -1.12e+04  9.77e+00        1    1.87e-01    7.87e-01
       5  9.940300e+06   -9.45e+06    3.71e+02   1.79e+03  -5.70e+03  3.05e-01        1    1.86e-01    9.73e-01
       6  4.906778e+05    6.67e+02    3.52e+02   4.37e+02   6.15e+00  9.16e-01        1    1.94e-01    1.17e+00
       7  6.610989e+05   -1.70e+05    3.52e+02   1.05e+02  -7.05e+02  4.58e-01        1    1.84e-01    1.35e+00
       8  5.614216e+05   -7.07e+04    3.52e+02   5.93e+01  -4.94e+02  1.14e-01        1    1.84e-01    1.54e+00
       9  5.033791e+05   -1.27e+04    3.52e+02   1.90e+01  -2.61e+02  1.43e-02        1    1.84e-01    1.72e+00
      10  4.917091e+05   -1.03e+03    3.52e+02   2.79e+00  -1.40e+02  8.94e-04        1    1.89e-01    1.91e+00
      11  4.907347e+05   -5.70e+01    3.52e+02   1.79e-01  -1.20e+02  2.79e-05        1    1.90e-01    2.10e+00
      12  4.906795e+05   -1.76e+00    3.52e+02   5.62e-03  -1.19e+02  4.37e-07        1    1.84e-01    2.28e+00
    
    Solver Summary (v 2.0.0-eigen-(3.3.9)-lapack-suitesparse-(5.1.2)-cxsparse-(3.1.9)-eigensparse-no_openmp)
    
                                         Original                  Reduced
    Parameter blocks                         2500                     2500
    Parameters                              15000                    15000
    Residual blocks                          9799                     9799
    Residuals                               58794                    58794
    
    Minimizer                        TRUST_REGION
    
    Sparse linear algebra library    SUITE_SPARSE
    Trust region strategy     LEVENBERG_MARQUARDT
    
                                            Given                     Used
    Linear solver          SPARSE_NORMAL_CHOLESKY   SPARSE_NORMAL_CHOLESKY
    Threads                                     1                        1
    Linear solver ordering              AUTOMATIC                     2500
    
    Cost:
    Initial                          4.913445e+05
    Final                            4.906778e+05
    Change                           6.667215e+02
    
    Minimizer iterations                       13
    Successful steps                            2
    Unsuccessful steps                         11
    
    Time (in seconds):
    Preprocessor                         0.004068
    
      Residual only evaluation           0.053879 (13)
      Jacobian & residual evaluation     0.020577 (2)
      Linear solver                      2.403726 (13)
    Minimizer                            2.507487
    
    Postprocessor                        0.000336
    Total                                2.511891
    
    Termination:                      CONVERGENCE (Function tolerance reached. |cost_change|/cost: 5.615779e-08 <= 1.000000e-06)
    
    
    进程已结束,退出代码0
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
  • 相关阅读:
    产品生命周期(PLM)发展历程及技术核心分析指导
    plink如何更新表型数据
    使用 Docker 安装 Kibana 8.4.3
    AutoReleasePool 工作机制
    Android学习笔记 63. 添加一个ScrollView
    vue之路由、无痕浏览加Nodejs环境安装及elementui介绍
    web网页大作业:基于html设计与实现的茶文化网站12页(带psd)
    UE5 ChaosVehicles载具 实现大漂移 (连载四)
    简约工作计划微立体PPT模板
    面向对象08:封装详解
  • 原文地址:https://blog.csdn.net/qq_45954434/article/details/126047980