L-BFGS-B MATLAB interface on Mac OS X Lion and Ubuntu

I needed to use L-BFGS-B, which unfortunately uses fortran code making it a pain in the arse to compile. Additionally, I’m not that keen on the interface, specifically on how limited the options are for passing in parameters to the objective and gradient callback functions. If I had time I’d rewrite it entirely in C, like the brilliant LibLBFGS (unfortunately, note the missing -B suffix), which is so much easier to compile. But I don’t, so here I am faffing to get it working..

In both cases it was necessary to modify matlabstring.h to change

#include <string>

to

#include <string.h>

on Mac OS X:

  1. Install gfortran
  2. compile the library from within MATLAB:[code title=”mex command”]mex -output lbfgsb arrayofmatrices.cpp \
    matlabexception.cpp matlabprogram.cpp \
    matlabstring.cpp lbfgsb.cpp matlabmatrix.cpp \
    matlabscalar.cpp program.cpp solver.f[/code]

run examplehs038 to test install:

examplehs038
1 573
2 393
3 132
4 11.5
5 1.48
6 1.12
7 0.984
8 0.305
9 0.0847
10 0.0101
11 0.000123
12 0.000113
13 0.000113
14 0.000112
15 0.000109
16 9.75e-05
17 7.93e-05
18 7.17e-05
19 3.55e-05
20 1.46e-05
21 1.71e-06
22 1.94e-07
23 1.47e-07
24 8.84e-10
25 2e-11
26 2.21e-12
27 7.16e-14

 

And on Ubuntu 11.10

  1. Compile gcc-4.3.4 with support for fortran, adapted from here:
    # download gcc 4.3.4
    wget ftp://ftp.mirrorservice.org/sites/sourceware.org/pub/gcc/releases/gcc-4.3.4/gcc-4.3.4.tar.bz2
    # extract, make and cd into separate build dir
    tar -xvf gcc-4.3.4.tar.bz2
    mkdir gcc-4.3.4-build
    cd gcc-4.3.4-build/
    # Install build dependencies, this should get all of them
    sudo apt-get build-dep gcc-4.5
    # the "fix"
    export LIBRARY_PATH=/usr/lib/x86_64-linux-gnu
    # configure, set prefix so install will only touch the /opt/gcc-4.3.4/ directory
    ../gcc-4.3.4/configure --prefix=/opt/gcc-4.3 --program-suffix=4.3 --enable-languages=c,c++,fortran
    # build, specify number of cpu corse after -j
    make -j4
    # install
    sudo make install
  2. Modify the Makefile:
    # Linux settings.
    MEX = /usr/local/MATLAB/R2011b/bin/mex
    MEXSUFFIX =
    MATLAB_HOME = /usr/local/MATLAB/R2011b
    CXX = g++4.3
    F77 = gfortran4.3
    CFLAGS = -O3 -fPIC -pthread
    FFLAGS = -O3 -fPIC -fexceptions
    TARGET = lbfgsb
    OBJS = solver.o matlabexception.o matlabscalar.o matlabstring.o \
    matlabmatrix.o arrayofmatrices.o program.o matlabprogram.o \
    lbfgsb.o
    
    CFLAGS += -Wall -ansi -DMATLAB_MEXFILE
    
    all: $(TARGET)
    
    %.o: %.cpp
    $(CXX) $(CFLAGS) -I$(MATLAB_HOME)/extern/include -o $@ -c $^
    
    %.o: %.f
    $(F77) $(FFLAGS) -o $@ -c $^
    
    $(TARGET): $(OBJS)
    $(MEX) -cxx CXX=$(CXX) CC=$(CXX) FC=$(FCC) LD=$(CXX) -lgfortran -lm \
    -O -output $@ $^
    
    clean:
    rm -f *.o $(TARGET)
  3. run make

Chibios C++ Notifications templates

I’ve found myself using memory pools + mailboxes a lot to pass data between different processes.

For example, I read sensors, pass the data to a process which filters that, and then pass the result to another process which saves it.

Originally I had one memory pool / mailbox per server process, but I found that limiting for several reasons – I didn’t want the main server thread to have to wait if a client was being slow processing the data, and I wanted the client to have control over how much data it needed buffering. So instead I swapped it around, and created a few helper classes for automating the process.

Firstly I define a message:

class SensorData : public NotifierMsg<SensorData> {
public:
    int16_t _acc[3], _gyro[3], _mag[3];
    float acc[3], gyro[3], mag[3];
    systime_t time;
    uint32_t status;
    bool_t magData(void);
};

Then the server:

class SensorHandler : public EnhancedThread<256>, public Notifier<SensorData> {
private:
    Sensor *acc, *mag, *gyro;
protected:
    virtual msg_t Main(void);
public:
    SensorHandler(Sensor*, Sensor*, Sensor*);
};

And then start the process:

SensorHandler sensors( acc, gyro, mag);

The client thread registers a listener on the server, specifying a cache of 2:

Listener<SensorData, 2> sensor_listener(&sensors);

Then in my server thread I populate the message and ‘broadcast’ it:

d.status = (gyro->getData(d._gyro, d.gyro) << SENS_GYR_DATA) |
(acc->getData(d._acc, d.acc) << SENS_ACC_DATA) |
(mag->getData(d._mag, d.mag) << SENS_MAG_DATA);

/* broadcast data */
Notifier::broadcast(&d);

Meanwhile I create a client Listener, and handle the data:

Listener<SensorData, 2> sensor_listener(&sensors);
int i=0;

i = 99;
while(true) {
    SensorData *data = sensor_listener.getData();
    if(++i == 100) {
        cPrintf("[%d %d %d] ", data->_acc[0], data->_acc[1], data->_acc[2]);
        cPrintf("[%d %d %d]\r\n", data->_gyro[0], data->_gyro[1], data->_gyro[2]);
        i = 0;
    }
    sensor_listener.releaseData(data);
}

The full code can be found on GitHub.