Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,15 @@ doc_DATA = README INSTALL COPYING AUTHORS ChangeLog NEWS
EXTRA_DIST = \
autogen.sh \
lbfgs.sln

##############################
# googletest support
##############################
all-local: googletest/.built
check-recursive: googletest/.built

googletest/.built: googletest/Makefile
cmake --build $(@D)
touch $@
googletest/Makefile: googletest/CMakeLists.txt
cd $(@D); cmake .
13 changes: 13 additions & 0 deletions configure.in → configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ AM_MAINTAINER_MODE
dnl ------------------------------------------------------------------
dnl Checks for program
dnl ------------------------------------------------------------------
AC_PROG_CC
AC_PROG_CXX
AC_PROG_LIBTOOL
AC_PROG_INSTALL
AC_PROG_LN_S
Expand Down Expand Up @@ -100,6 +102,17 @@ AC_SUBST(CFLAGS)
AC_SUBST(LDFLAGS)
AC_SUBST(INCLUDES)

dnl ------------------------------------------------------------------
dnl googletest support
dnl ------------------------------------------------------------------
GTEST_CPPFLAGS="-I\$(top_srcdir)/googletest/googletest/include"
GTEST_LIBS="-L\$(top_srcdir)/googletest/googlemock/gtest -lgtest_main -lgtest"
GTEST_LDFLAGS=
AC_CHECK_LIB(pthread, pthread_create, GTEST_LDFLAGS+=" -pthread", GTEST_CPPFLAGS+=" -DGTEST_HAS_PTHREAD=0")
AC_SUBST([GTEST_CPPFLAGS])
AC_SUBST([GTEST_LDFLAGS])
AC_SUBST([GTEST_LIBS])

dnl ------------------------------------------------------------------
dnl Output the configure results.
dnl ------------------------------------------------------------------
Expand Down
8 changes: 8 additions & 0 deletions lib/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,13 @@ liblbfgs_la_LDFLAGS = \
-no-undefined \
-release @VERSION@

bin_PROGRAMS = lbfgstest
TESTS = lbfgstest

lbfgstest_SOURCES = lbfgs_unittests.cc
lbfgstest_LDFLAGS = $(GTEST_LDFLAGS)
lbfgstest_LDADD = liblbfgs.la $(GTEST_LIBS)
lbfgstest_CPPFLAGS = -I./include $(GTEST_CPPFLAGS)

AM_CFLAGS = @CFLAGS@
INCLUDES = @INCLUDES@
144 changes: 144 additions & 0 deletions lib/lbfgs_unittests.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
#include "lbfgs.h"

#include <gtest/gtest.h>
#include <cstdio>
#include <cmath>

namespace {
class objective_function
{
protected:
lbfgsfloatval_t *m_x;

public:
objective_function() : m_x(NULL)
{
}

virtual ~objective_function()
{
if (m_x != NULL) {
lbfgs_free(m_x);
m_x = NULL;
}
}

lbfgsfloatval_t* getResults() {
return m_x;
}

int run(int N)
{
lbfgsfloatval_t fx;
m_x = lbfgs_malloc(N);

if (m_x == NULL) {
fprintf(stderr, "ERROR: Failed to allocate a memory block for variables.\n");
return 1;
}

/* Initialize the variables. */
for (int i = 0;i < N;i += 2) {
m_x[i] = -1.2;
m_x[i+1] = 1.0;
}

/*
Start the L-BFGS optimization; this will invoke the callback functions
evaluate() and progress() when necessary.
*/
int ret = lbfgs(N, m_x, &fx, &_evaluate, &_progress, this, NULL);

/* Report the result. */
printf("L-BFGS optimization terminated with status code = %d\n", ret);
printf(" fx = %f, x[0] = %f, x[1] = %f\n", fx, m_x[0], m_x[1]);

return ret;
}

protected:
static lbfgsfloatval_t _evaluate(
void *instance,
const lbfgsfloatval_t *x,
lbfgsfloatval_t *g,
const int n,
const lbfgsfloatval_t step
)
{
return reinterpret_cast<objective_function*>(instance)->evaluate(x, g, n, step);
}

lbfgsfloatval_t evaluate(
const lbfgsfloatval_t *x,
lbfgsfloatval_t *g,
const int n,
const lbfgsfloatval_t step
)
{
lbfgsfloatval_t fx = 0.0;

for (int i = 0;i < n;i += 2) {
lbfgsfloatval_t t1 = 1.0 - x[i];
lbfgsfloatval_t t2 = 10.0 * (x[i+1] - x[i] * x[i]);
g[i+1] = 20.0 * t2;
g[i] = -2.0 * (x[i] * g[i+1] + t1);
fx += t1 * t1 + t2 * t2;
}
return fx;
}

static int _progress(
void *instance,
const lbfgsfloatval_t *x,
const lbfgsfloatval_t *g,
const lbfgsfloatval_t fx,
const lbfgsfloatval_t xnorm,
const lbfgsfloatval_t gnorm,
const lbfgsfloatval_t step,
int n,
int k,
int ls
)
{
return reinterpret_cast<objective_function*>(instance)->progress(x, g, fx, xnorm, gnorm, step, n, k, ls);
}

int progress(
const lbfgsfloatval_t *x,
const lbfgsfloatval_t *g,
const lbfgsfloatval_t fx,
const lbfgsfloatval_t xnorm,
const lbfgsfloatval_t gnorm,
const lbfgsfloatval_t step,
int n,
int k,
int ls
)
{
printf("Iteration %d:\n", k);
printf(" fx = %f, x[0] = %f, x[1] = %f\n", fx, x[0], x[1]);
printf(" xnorm = %f, gnorm = %f, step = %f\n", xnorm, gnorm, step);
printf("\n");
return 0;
}
};

}

class LbfgsTest : public ::testing::Test {
protected:
static double const EPSILON = 1e-6;

objective_function obj;
};
double const LbfgsTest::EPSILON;

TEST_F(LbfgsTest, testObjectiveFunction) {
int const N = 100;
int rc = obj.run(N);
ASSERT_EQ(0, rc);
lbfgsfloatval_t* results = obj.getResults();
ASSERT_NE((lbfgsfloatval_t*) NULL, results);
EXPECT_LE(abs(results[0] - 1.0), EPSILON) << results[0] << " not within " << EPSILON << " of 1";
EXPECT_LE(abs(results[1] - 1.0), EPSILON) << results[1] << " not within " << EPSILON << " of 1";
}