eigen 求解示例


#include 
#include 
#include 

using namespace std;
using namespace Eigen;    

void generateRandomProblemData(MatrixXd* A, VectorXd* b,
			       Eigen::SparseMatrix* A_sparse)
{
  // -- Problem setup.
  int num_vars = 10;
  int num_tr_ex = 1000;
  *b = VectorXd::Random(num_tr_ex);
  
  // -- Set up dense version of A.
  *A = MatrixXd::Zero(num_vars, num_tr_ex);
  int num_nonzero = 0;
  for(int i = 0; i < A->rows(); ++i) {
    for(int j = 0; j < A->cols(); ++j) {
      double val = (double)rand() / (double)RAND_MAX;
      if(val > 0.9) {
	A->coeffRef(i, j) = val;
	++num_nonzero;
      }
    }
  }
  
  // -- Set up sparse version of A.
  *A_sparse = Eigen::SparseMatrix(A->rows(), A->cols());
//   cout << "A: " << A.rows() << " x " << A.cols() << endl;
//   cout << "A_sparse: " << A_sparse.rows() << " x " << A_sparse.cols() << endl;

  A_sparse->startFill(num_nonzero * 1.1);
  int filled = 0;
  for(int j = 0; j < A->cols(); ++j) {
    for(int i = 0; i < A->rows(); ++i) {
      if(A->coeff(i, j) != 0) { 
	A_sparse->fill(i, j) = A->coeff(i, j);
	++filled;
      }
    }
  }
  A_sparse->endFill();
  assert(filled == num_nonzero);
}

TEST(SparseMLS, correctness)
{

//   cout << "A: " << endl << A << endl;
//   cout << "A_sparse: " << endl << A_sparse << endl;
  MatrixXd A;
  VectorXd b;
  Eigen::SparseMatrix A_sparse;
  generateRandomProblemData(&A, &b, &A_sparse);

  // -- Get mean logistic score for a random vector using both methods.
  VectorXd x = VectorXd::Random(A.rows());
  ObjectiveMLS obj_mls(A, b);
  double regular = obj_mls.eval(x);

  ObjectiveMLSSparse obj_mls_sparse(&A_sparse, &b);
  double sparse = obj_mls_sparse.eval(x);

  cout << "Delta: " << regular - sparse << endl;
  EXPECT_DOUBLE_EQ(regular, sparse);

  // -- Get gradient with both methods.
  GradientMLS grad_mls(A, b);
  VectorXd grad = grad_mls.eval(x);
  GradientMLSSparse grad_mls_sparse(&A_sparse, &b);
  VectorXd grad_sparse = grad_mls_sparse.eval(x);
  cout << grad.transpose() << endl << grad_sparse.transpose() << endl;
  cout << "Norm of the gradient difference: " << (grad - grad_sparse).norm() << endl;
  for(int i = 0; i < grad.rows(); ++i)
    EXPECT_DOUBLE_EQ(grad(i), grad_sparse(i));

  // -- Get Hessian with both methods.
  HessianMLS hess_mls(A, b);
  MatrixXd hess = hess_mls.eval(x);
  HessianMLSSparse hess_mls_sparse(&A_sparse, &b);
  MatrixXd hess_sparse = hess_mls_sparse.eval(x);
  double fn = 0;
  for(int i = 0; i < hess.rows(); ++i) { 
    for(int j = 0; j < hess.cols(); ++j) { 
      EXPECT_DOUBLE_EQ(hess(i, j), hess_sparse(i, j));
      fn += pow(hess(i, j) - hess_sparse(i, j), 2);
    }
  }
  cout << "Frobenius norm of hessian difference: " << sqrt(fn) << endl;
//   cout << hess << endl;
//   cout << hess_sparse << endl;
    
}

TEST(UnconstrainedOptimization, SparseMEL_matches_MEL)
{
  MatrixXd A;
  VectorXd b;
  Eigen::SparseMatrix A_sparse;
  generateRandomProblemData(&A, &b, &A_sparse);

  for(int j = 0; j < 10; ++j) { 
    // -- Get mean exponential loss for a random vector using both methods.
    VectorXd x = VectorXd::Random(A.rows());
    ObjectiveMEL obj_mel(A, b);
    double regular = obj_mel.eval(x);
    
    ObjectiveMELSparse obj_mel_sparse(&A_sparse, &b);
    double sparse = obj_mel_sparse.eval(x);
    
    cout << "Delta: " << regular - sparse << endl;
    EXPECT_FLOAT_EQ(regular, sparse);

    // -- Get gradient with both methods.
    GradientMEL grad_mel(A, b);
    VectorXd grad = grad_mel.eval(x);
    GradientMELSparse grad_mel_sparse(&A_sparse, &b);
    VectorXd grad_sparse = grad_mel_sparse.eval(x);
    cout << grad.transpose() << endl << grad_sparse.transpose() << endl;
    cout << "Norm of the gradient difference: " << (grad - grad_sparse).norm() << endl;
    for(int i = 0; i < grad.rows(); ++i)
      EXPECT_FLOAT_EQ(grad(i), grad_sparse(i));
  }
  
//   // -- Get Hessian with both methods.
//   HessianMEL hess_mel(A, b);
//   MatrixXd hess = hess_mel.eval(x);
//   HessianMELSparse hess_mel_sparse(&A_sparse, &b);
//   MatrixXd hess_sparse = hess_mel_sparse.eval(x);
//   double fn = 0;
//   for(int i = 0; i < hess.rows(); ++i) { 
//     for(int j = 0; j < hess.cols(); ++j) { 
//       EXPECT_DOUBLE_EQ(hess(i, j), hess_sparse(i, j));
//       fn += pow(hess(i, j) - hess_sparse(i, j), 2);
//     }
//   }
//   cout << "Frobenius norm of hessian difference: " << sqrt(fn) << endl;

  
}

TEST(UnconstrainedOptimization, NewtonSolver)
{
  int num_vars = 10;
  int num_tr_ex = 1000;
  MatrixXd A = MatrixXd::Random(num_vars, num_tr_ex);
  VectorXd b = VectorXd::Random(num_tr_ex);

  ObjectiveMLS obj_mls(A, b);
  GradientMLS grad_mls(A, b);
  HessianMLS hess_mls(A, b);

  cout << "Solving." << endl;
  VectorXd init = VectorXd::Zero(A.rows());
  double tol = 1e-6;
  double alpha = 0.3;
  double beta = 0.5;
  double stepsize = 1.0;
  NewtonSolver solver_mls(&obj_mls, &grad_mls, &hess_mls, tol, alpha, beta, stepsize, true);
  VectorXd solution = solver_mls.solve(init);
  cout << "Got solution:" << endl << solution.transpose() << endl;

  cout << "Perturbing..." << endl;
  for(int i = 0; i < 1e4; ++i) {
    VectorXd random = VectorXd::Random(solution.rows());
    random *= ((double)rand() / (double)RAND_MAX);
    VectorXd perturbed = solution + random;

    EXPECT_TRUE(obj_mls.eval(perturbed) + 1e-6 >= obj_mls.eval(solution));
  }

  cout << "Solving with Nesterov." << endl;
  NesterovGradientSolver ngs(&obj_mls, &grad_mls, tol, alpha, beta, 0, 1, true);
  ngs.hessian_ = &hess_mls; // Compute condition number.
  VectorXd nesterov_solution = ngs.solve(init);
  cout << "Got solution:" << endl << nesterov_solution.transpose() << endl;
  
  cout << "Perturbing..." << endl;
  for(int i = 0; i < 1e4; ++i) {
    VectorXd random = VectorXd::Random(nesterov_solution.rows());
    random *= ((double)rand() / (double)RAND_MAX);
    VectorXd perturbed = nesterov_solution + random;

    EXPECT_TRUE(obj_mls.eval(perturbed) + 1e-6 >= obj_mls.eval(solution));
  }


  cout << "Solving with Gradient." << endl;
  GradientSolver gs(&obj_mls, &grad_mls, tol, alpha, beta, 0, 1, true);
  VectorXd gradient_solution = gs.solve(init);
  cout << "Got solution:" << endl << gradient_solution.transpose() << endl;

  cout << "Perturbing..." << endl;
  double gradient_objective = obj_mls.eval(gradient_solution);
  for(int i = 0; i < 1e4; ++i) {
    VectorXd random = VectorXd::Random(gradient_solution.rows());
    random *= ((double)rand() / (double)RAND_MAX);
    VectorXd perturbed = gradient_solution + random;
    EXPECT_TRUE(obj_mls.eval(perturbed) >= gradient_objective);
  }
}


int main(int argc, char** argv) {
  testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}


你可能感兴趣的:(eigen 求解示例)