Skip to content

Commit

Permalink
- use GoogleTestingFramework
Browse files Browse the repository at this point in the history
- tidy up unit tests
- add makefile
- removed message on wrong gradient (instead return false/true)
- add short intro in README.md
  • Loading branch information
Patrick Wieschollek committed Dec 4, 2014
1 parent 233ad61 commit 7ad417c
Show file tree
Hide file tree
Showing 15 changed files with 433 additions and 353 deletions.
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
CppNumericalSolvers (C++11 implementation with MATLAB bindings)
=================================================================

Quick Intro
-----------
- run `make install` to download and build dependencies
- run `make test` to verify the results by unit tests
- run `make main` to build cpp examples
- run `make.m` within MATLAB to build the MATLAB wrapper

Long Intro
-----------

This repository contains solvers implemented in C++11 using the [Eigen3][eigen3] library. All implementations were written from scratch.
You can use this library in **C++ and [Matlab][matlab]** in an easy way.

The library currently contains the following solvers:
- gradient descent solver
- conjugate gradient descent solver
- Newton descent solver
- BFGS solver
- L-BFGS solver
Expand Down
56 changes: 56 additions & 0 deletions makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
CXX=g++
CXXFLAGS := -Wall -Wextra -pedantic-errors -std=c++11 -fopenmp -Ieigen
CXXFLAGSTEST := -Wall -Wextra -pedantic-errors -std=c++11 -fopenmp -Ieigen -Igtest/include


main: src/main.cpp
$(CXX) $(CXXFLAGS) -o main src/Meta.cpp src/ISolver.cpp src/GradientDescentSolver.cpp src/ConjugateGradientSolver.cpp src/NewtonDescentSolver.cpp src/BfgsSolver.cpp src/LbfgsSolver.cpp src/LbfgsbSolver.cpp src/main.cpp

test: src/unittests.cpp
$(CXX) $(CXXFLAGSTEST) -o test src/Meta.cpp src/ISolver.cpp src/GradientDescentSolver.cpp src/ConjugateGradientSolver.cpp src/NewtonDescentSolver.cpp src/BfgsSolver.cpp src/LbfgsSolver.cpp src/LbfgsbSolver.cpp src/unittests.cpp libgtest.a


install:
# google-testing-framework
rm -f gtest-1.7.0.zip
rm -fR gtest-1.7.0
wget -O gtest-1.7.0.zip https://googletest.googlecode.com/files/gtest-1.7.0.zip
unzip gtest-1.7.0.zip
g++ -Igtest-1.7.0/include -Igtest-1.7.0 -c "gtest-1.7.0/src/gtest-all.cc"
ar -rv libgtest.a gtest-all.o
rm -f gtest-1.7.0.zip
mv gtest-1.7.0 gtest
# eigen library
wget -c http://bitbucket.org/eigen/eigen/get/3.2.2.tar.bz2 -O eigen-3.2.2.tar.bz2
bunzip2 eigen-3.2.2.tar.bz2
tar xvf eigen-3.2.2.tar
mv eigen-eigen-* eigen
rm -Rf eigen-3.2.2.tar
rm -Rf eigen-3.2.2.tar.bz2



# test: unittests.cpp
# $(CXX) $(CXXFLAGSTEST) -o test Neighborhood.hpp Neighborhood.cpp Vector.hpp Vector.cpp ProQuantization.hpp ProQuantization.cpp ProTree.hpp ProTree.cpp unittests.cpp libgtest.a -lglog
# GLOG_logtostderr=1 ./test

# gtest:
# rm -f gtest-1.7.0.zip
# rm -fR gtest-1.7.0
# wget -O gtest-1.7.0.zip https://googletest.googlecode.com/files/gtest-1.7.0.zip
# unzip gtest-1.7.0.zip
# g++ -Igtest-1.7.0/include -Igtest-1.7.0 -c "gtest-1.7.0/src/gtest-all.cc"
# ar -rv libgtest.a gtest-all.o
# rm -f gtest-1.7.0.zip
# mv gtest-1.7.0 gtest


# cleanall:
# rm -f test
# rm -f main

# cleanmain:
# rm -f main

# cleantest:
# rm -f test
2 changes: 1 addition & 1 deletion matlab-bindings/make.m
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

if exist('eigen/Eigen/Dense','file')
disp('compiling ...');
mex -I./../matlab-bindings/eigen ...
mex -I./../eigen ...
../src/Meta.cpp ../src/ISolver.cpp ...
../src/GradientDescentSolver.cpp ...
../src/NewtonDescentSolver.cpp ...
Expand Down
2 changes: 1 addition & 1 deletion src/BfgsSolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ void BfgsSolver::internalSolve(Vector & x,
const GradientOracleType & FunctionGradient,
const HessianOracleType & FunctionHessian)
{

UNUSED(FunctionHessian);

const size_t DIM = x.rows();
size_t iter = 0;
Expand Down
73 changes: 73 additions & 0 deletions src/ConjugateGradientSolver.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/**
* Copyright (c) 2014 Patrick Wieschollek
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

#include "ConjugateGradientSolver.h"
#include <iostream>
namespace pwie
{

ConjugateGradientSolver::ConjugateGradientSolver() : ISolver()
{


}


void ConjugateGradientSolver::internalSolve(Vector & x,
const FunctionOracleType & FunctionValue,
const GradientOracleType & FunctionGradient,
const HessianOracleType & FunctionHessian)
{
UNUSED(FunctionHessian);
size_t iter = 0;

Vector grad(x.rows());
Vector grad_old(x.rows());
Vector Si(x.rows());
Vector Si_old(x.rows());
do
{
FunctionGradient(x, grad);

if(iter==0){
Si = -grad;
}else{
const double beta = grad.dot(grad)/(grad_old.dot(grad_old));
Si = -grad + beta*Si_old;
}

const double rate = linesearch(x, Si, FunctionValue, FunctionGradient) ;

x = x + rate * Si;

iter++;
grad_old = grad;
Si_old = Si;

}
while((grad.lpNorm<Eigen::Infinity>() > settings.gradTol) && (iter < settings.maxIter));


}
}

/* namespace pwie */
42 changes: 42 additions & 0 deletions src/ConjugateGradientSolver.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* Copyright (c) 2014 Patrick Wieschollek
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

#ifndef CONJUGATEGRADIENTSOLVER_H_
#define CONJUGATEGRADIENTSOLVER_H_
#include "ISolver.h"
namespace pwie
{

class ConjugateGradientSolver : public ISolver
{
public:
ConjugateGradientSolver();
void internalSolve(Vector & x0,
const FunctionOracleType & FunctionValue,
const GradientOracleType & FunctionGradient,
const HessianOracleType & FunctionHessian = std::function<void(const Eigen::VectorXd & x, Eigen::MatrixXd & hessian)>());

};

} /* namespace pwie */

#endif /* CONJUGATEGRADIENTSOLVER_H_ */
6 changes: 1 addition & 5 deletions src/GradientDescentSolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,20 +37,16 @@ void GradientDescentSolver::internalSolve(Vector & x,
const GradientOracleType & FunctionGradient,
const HessianOracleType & FunctionHessian)
{
UNUSED(FunctionHessian);
Vector grad(x.rows());

double x_old, x_new = FunctionValue(x);

size_t iter = 0;
do
{
x_old = x_new;
FunctionGradient(x, grad);
const double rate = linesearch(x, -grad, FunctionValue, FunctionGradient) ;

x = x - rate * grad;
x_new = FunctionValue(x);

iter++;
}
while((grad.lpNorm<Eigen::Infinity>() > settings.gradTol) && (iter < settings.maxIter));
Expand Down
2 changes: 1 addition & 1 deletion src/LbfgsSolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ void LbfgsSolver::internalSolve(Vector & x,
const GradientOracleType & FunctionGradient,
const HessianOracleType & FunctionHessian)
{

UNUSED(FunctionHessian);
const size_t m = 10;
const size_t DIM = x.rows();

Expand Down
4 changes: 2 additions & 2 deletions src/LbfgsbSolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ void LbfgsbSolver::internalSolve(Vector & x0,
const GradientOracleType & FunctionGradient,
const HessianOracleType & FunctionHessian)
{

UNUSED(FunctionHessian);
DIM = x0.rows();

if(!hasbound_lower)
Expand Down Expand Up @@ -349,7 +349,7 @@ void LbfgsbSolver::internalSolve(Vector & x0,
Matrix sHistory = Matrix::Zero(DIM, 0);

Vector x = x0, g;
int k = 0;
size_t k = 0;

double f = FunctionObjectiveOracle_(x);

Expand Down
16 changes: 2 additions & 14 deletions src/Meta.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,9 @@ bool checkGradient(const FunctionOracleType & FunctionValue, const Vector & x, c
}
const double error = static_cast<Vector>((finite - grad)).norm() / static_cast<Vector>((finite + grad)).norm();


if(error > eps)
{
std::cout << "Warning! Gradient could be wrong." << std::endl;
return false;
}

return true;
return !(error > eps);
}


void computeGradient(const FunctionOracleType & FunctionValue, const Vector & x, Vector & grad, const double eps)
{
const size_t DIM = x.rows();
Expand All @@ -65,8 +57,8 @@ void computeGradient(const FunctionOracleType & FunctionValue, const Vector & x,
finite[i] = (FunctionValue(xx) - FunctionValue(xy)) / (2.0 * eps);
}
grad = finite;

}

void computeHessian(const FunctionOracleType & FunctionValue, const Vector & x, Matrix & hessian, const double eps)
{
Assert(x.rows() == hessian.rows(), "hessian has wrong dimension (number of rows)");
Expand All @@ -90,12 +82,8 @@ void computeHessian(const FunctionOracleType & FunctionValue, const Vector & x,
double f3 = FunctionValue(xx);

hessian(i, j) = (f1 - f2 - f3 + f4) / (eps * eps);


}
}


}


Expand Down
5 changes: 3 additions & 2 deletions src/Meta.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,14 @@ typedef std::function<void(const Eigen::VectorXd & x, Eigen::MatrixXd & hessian)
typedef Eigen::MatrixXd Matrix;
typedef Eigen::VectorXd Vector;
typedef Eigen::VectorXd::Scalar Scalar;
typedef unsigned int uint;

typedef struct Options
{
double gradTol;
double rate;
size_t maxIter;
int m;
size_t m;

Options()
{
Expand Down Expand Up @@ -89,7 +90,7 @@ bool AssertEqual(T a, T b)
#define INF HUGE_VAL
#define Assert(x,m) if (!(x)) { throw (std::runtime_error(m)); }


#define UNUSED(arg) (void)arg; // trick of Qt

#define FAST

Expand Down
Loading

0 comments on commit 7ad417c

Please sign in to comment.