[libocas] 01/01: Imported Upstream version 0.95

Christian Kastner chrisk-guest at moszumanska.debian.org
Mon Aug 25 03:36:34 UTC 2014


This is an automated email from the git hooks/post-receive script.

chrisk-guest pushed a commit to annotated tag upstream/0.95
in repository libocas.

commit cdc2a80d2f6a42e0392416b1e6c51c0c6adf9e48
Author: Christian Kastner <debian at kvr.at>
Date:   Sat Jun 30 02:02:23 2012 +0200

    Imported Upstream version 0.95
---
 ChangeLog                                         |   7 +
 Contents.m                                        |  40 +-
 INSTALL                                           |  48 +-
 Makefile                                          |  50 +-
 README                                            |  27 +-
 compute_auc.m                                     |  15 +
 compute_auc.mexa64                                | Bin 0 -> 27573 bytes
 compute_errors_mex.c => compute_auc_mex.c         |  26 +-
 data/reference_solution.mat                       | Bin 0 -> 2424860 bytes
 data/refernce_solution.mat                        | Bin 5824 -> 0 bytes
 features_double.c                                 | 372 ++++++++++++++
 features_double.h                                 |  37 ++
 features_int8.c                                   |  89 ++++
 features_int8.h                                   |  20 +
 features_single.c                                 |  91 ++++
 features_single.h                                 |  20 +
 html/ChangeLog                                    |   2 +
 html/index.html                                   |  29 +-
 lbpfilter_mex.c                                   |  78 ---
 lbppyr.m                                          |  59 ---
 lbppyr_features.mexa64                            | Bin 0 -> 25711 bytes
 lbppyr_features_mex.c                             |  17 +-
 lbppyr_mex.c                                      | 134 -----
 libocas.so                                        | Bin 0 -> 41123 bytes
 libocas_test.m                                    | 348 ++++++++-----
 linclassif                                        | Bin 0 -> 17743 bytes
 linclass.c => linclassif.c                        |  12 +-
 svmlight_linclass.m => linclassif_light.m         |  13 +-
 linclassif_light.mexa64                           | Bin 0 -> 31853 bytes
 svmlight_linclass_mex.c => linclassif_light_mex.c |  62 ++-
 msvmocas                                          | Bin 0 -> 78218 bytes
 msvmocas.c                                        |  11 +-
 msvmocas.m                                        |  38 +-
 msvmocas.mexa64                                   | Bin 0 -> 65734 bytes
 msvmocas.m => msvmocas_light.m                    |  39 +-
 msvmocas_light.mexa64                             | Bin 0 -> 65780 bytes
 msvmocas_test.m => msvmocas_light_example.m       |  14 +-
 msvmocas_mex.c => msvmocas_light_mex.c            | 301 +++++-------
 msvmocas_mex.c                                    | 312 +++++-------
 ocas_helper.c                                     | 566 +++-------------------
 ocas_helper.h                                     |  91 ++--
 ocas_lbp_helper.c                                 |   7 +-
 svmocas                                           | Bin 0 -> 82262 bytes
 svmocas.c                                         |  29 +-
 svmocas.m                                         |  51 +-
 svmocas.mexa64                                    | Bin 0 -> 70189 bytes
 svmocas_lbp.mexa64                                | Bin 0 -> 51481 bytes
 svmocas_lbp_mex.c                                 |  79 +--
 svmocas.m => svmocas_light.m                      |  41 +-
 svmocas_light.mexa64                              | Bin 0 -> 65826 bytes
 svmocas_lbp_mex.c => svmocas_light_mex.c          | 307 ++++++------
 svmocas_mex.c                                     | 502 +++++++++----------
 version.h                                         |   2 +-
 53 files changed, 1963 insertions(+), 2023 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 5e762e3..f20ff02 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2012-02-06 Vojtech Franc
+        * Release of v0.95
+        * Helper functions for different data types put to separate files -
+        * features_double.c/h, features_single.c/h, features_int8.c.h.
+        * Programmed support for data stored in int8 and float single precision.
+        * Separate MEX funtions for training from SVM^light format.
+        * Removed unused functions for computing LBP features. 
 2010-06-11  Vojtech Franc
         * Added functions which implement the COFFIN framework for training 
         * translation invariant image classifier from virtual example.
diff --git a/Contents.m b/Contents.m
index 9644ca0..deb8ec7 100644
--- a/Contents.m
+++ b/Contents.m
@@ -1,29 +1,27 @@
 % OCAS solver for training linear SVM classifiers from large-scale data
 %
-% Copyright (C) 2008,2009,2010 
+% Copyright (C) 2008,2009,2010,2012 
 % Vojtech Franc, xfrancv at cmp.felk.cvut.cz
 % Soeren Sonnenburg, soeren.sonnenburg at tu-berlin.de
 %
-% SVM solvers:
-%   svmocas             Train linear binary (two-class) SVM classifier using 
-%                       OCAS solver.
-%   svmocas_lbp         Train linear SVM classifier for images represented by 
-%                       LBP features. 
-%   msvmocas            Train multi-class linear SVM classifier using OCAS solver.
+% SVM solvers for training linear two-class classifiers:
+%   svmocas             Accepts examples stored in dense double or sparse 
+%                       double or dense single or dense int8 matrix.
+%   svmocas_light       Loads examples from file in SVM^light format.
+%   svmocas_lbp         Examples are LBP features computed on a set of
+%                       given grayscale images.
 %
-% Auxciliary functions:
-%   svmlight_linclass   Classify examples in SVM^light file by linear rule.
-%   svmocas_parseout    Parsing of text output of SVMOCAS solver.
-%
-% Examples
-%   libocas_test        This script tests functionality of SVMOCAS and 
-%                       MSVMOCAS solvers.
-%   svmocas_lbp_example Example on using SVMOCAS_LBP from training translation
-%                       invariant image classifiers.
+% SVM solver for training linear multi-class classifiers:
+%   msvmocas            Accepts examples stored in dense double or 
+%                       sparse double matrix.
+%   msvmocas_light      Loads examples from file in SVM^light format.
 %
-% LBP features for image classification:
-%   lbpfilter           Computes LBP for each 3x3 subwindow in input image.
-%   lbppyr              Computes LBP features on scale-pyramid of input image.
-%   lbppyr_features     Computes pyramid of LBP features for each defined 
-%                       window in input images. 
+% Auxciliary functions:
+%   compute_auc             Computes area under ROC.
+%   lbppyr_features         Computes LBP feature representation for given images. 
+%   libocas_test            This script tests all SVM solvers in the LIBOCAS.
+%   linclassif_light        Classifies examples in SVM^light file by linear rule.
+%   msvmocas_light_example  Example on using multi-class SVM solver. 
+%   svmocas_lbp_example     Example on training translation invariant image classifiers.
+%   svmocas_parseout        Parsing out text output of SVMOCAS solver.
 %
\ No newline at end of file
diff --git a/INSTALL b/INSTALL
index 447497f..c0f1189 100644
--- a/INSTALL
+++ b/INSTALL
@@ -1,4 +1,12 @@
-Issue make 
+DEPENDENCES
+===========
+LIBOCAS requires only standard C libraries. 
+
+
+INSTALL
+=======
+
+Unpack the library to a folder of your choice, jump to the folder and issue 
 
     make
 
@@ -6,30 +14,42 @@ which should produce
 
     svmocas         ... standalone application for training binary linear SVM classifiers
     msvmocas        ... standalone application for training multi-class linear SVM classifiers
-    linclass        ... implementation of linear classification rule
+    linclassif      ... implementation of linear classification rule
     svmocas.so      ... Linux library
 
-In addition, if mex compiler is in path then the following Matlab functions
+In addition, if Matlab mex compiler is in path then the following MEX functions will be generated
     
     msvmocas.mexXXX          ... Training multi-class linear SVM classifier
+    msvmocas_light.mexXXX    ... Training multi-class linear SVM classifier from SVM^light file
     svmocas.mexXXX           ... Training two-class linear SVM classifier
-    svmlight_linclass.mexXXX ... Linear classifier loading examples directly form SVM^light file
     svmocas_lbp.mexXXX       ... Training two-class linear SVM classifier for grey-scale images
-    
-    lbpfilter.mexXXX         ... functions computing LBP features on grey-scale images
-    lbppyr_features.mexXXX 
-    lbppyr.mexXXX
+    svmocas_light.mexXXX     ... Training two-class linear SVM classifier from SVM^light file
+    linclassif_light.mexXXX  ... Linear classifier loading examples directly form SVM^light file
+
+    compute_auc              ... Computes area under ROC.
+    lbppyr_features.mexXXX   ... Computing LBP feature descriptor for given images.
 
 
 MATLAB
 ======
 
-First, CD to the root folder of OCASLIB and then:
+First, CD to the root folder of LIBOCAS and then:
 
-To test LIBOCAS library type
+To get list of all implemented functions type 
+  help Contents
+
+Each of the implemented SVM solvers has its detailed help together with a simple example of use, 
+just try
+  help svmocas
+  help svmocas_light
+  help svmocas_lbp
+  help msvmocas
+  help msvmocas_light
+
+To test all implemented SVM solvers type
     libocas_test
 
-To test SVMOCAS_LBP try
+To test SVMOCAS_LBP for training translation invariant image classifiers try
     svmocas_lbp_example
 
 To get help type 
@@ -44,3 +64,9 @@ To get help type
     ./msvmocas
     ./linclass
 
+
+TROUBLESHOOTING
+===============
+
+Do not hasitate to send us email
+  xfrancv at cmp.felk.cvut.cz
diff --git a/Makefile b/Makefile
index 2ed4145..6bc4c9a 100644
--- a/Makefile
+++ b/Makefile
@@ -4,30 +4,32 @@ MEXFLAGS := $(shell if uname -m | grep -q x86_64 ; then echo -largeArrayDims ; f
 MEXSUFFIX := $(shell if uname -m | grep -q x86_64 ; then echo mexa64 ; else echo mexglx ; fi)
 CC := gcc
 #CFLAGS := -g -lm -Wall -pthread
-CFLAGS := -lm -msse -O3 -fPIC -fstrict-aliasing -fomit-frame-pointer -Wall -pthread
+CFLAGS := -msse -O3 -fPIC -fstrict-aliasing -fomit-frame-pointer -Wall -pthread
+CLIBS := -lm
 #CFLAGS := -lm -msse -O3 -fPIC -fstrict-aliasing -fomit-frame-pointer -Wall
 #CFLAGS := -lm -msse -O3 -fPIC -fopenmp -fstrict-aliasing -fomit-frame-pointer -Wall
 
 
 ifeq (yes,$(MEXDETECTED))
-all: svmocas.$(MEXSUFFIX) svmlight_linclass.$(MEXSUFFIX) libocas.so svmocas msvmocas linclass msvmocas.$(MEXSUFFIX) compute_errors.$(MEXSUFFIX) lbppyr.$(MEXSUFFIX) svmocas_lbp.$(MEXSUFFIX) lbppyr_features.$(MEXSUFFIX) lbpfilter.$(MEXSUFFIX)
+all: svmocas.$(MEXSUFFIX) svmocas_light.$(MEXSUFFIX) linclassif_light.$(MEXSUFFIX) libocas.so svmocas msvmocas linclassif msvmocas.$(MEXSUFFIX) msvmocas_light.$(MEXSUFFIX) compute_auc.$(MEXSUFFIX) svmocas_lbp.$(MEXSUFFIX) lbppyr_features.$(MEXSUFFIX) 
 
-compute_errors.$(MEXSUFFIX): compute_errors_mex.c libocas.h ocas_helper.h ocas_helper.c
-		$(MEX) $(MEXFLAGS) -DLIBOCAS_MATLAB -O -output compute_errors.$(MEXSUFFIX) compute_errors_mex.c ocas_helper.c lib_svmlight_format.c
+compute_auc.$(MEXSUFFIX): compute_auc_mex.c libocas.h ocas_helper.h ocas_helper.c
+		$(MEX) $(MEXFLAGS) -DLIBOCAS_MATLAB -O -output compute_auc.$(MEXSUFFIX) compute_auc_mex.c ocas_helper.c lib_svmlight_format.c
 
-svmocas.$(MEXSUFFIX): libocas.c libocas.h libqp_splx.c libqp.h svmocas_mex.c lib_svmlight_format.c lib_svmlight_format.h ocas_helper.c ocas_helper.h
-		$(MEX) $(MEXFLAGS) -DLIBOCAS_MATLAB -O -output svmocas.$(MEXSUFFIX) svmocas_mex.c lib_svmlight_format.c ocas_helper.c  libocas.c libqp_splx.c
-		
-		
-linclass_light.$(MEXSUFFIX): linclass_light_mex.c lib_svmlight_format.c lib_svmlight_format.h ocas_helper.c ocas_helper.h
-		$(MEX) $(MEXFLAGS) -DLIBOCAS_MATLAB -O -output linclass_light.$(MEXSUFFIX) linclass_light_mex.c lib_svmlight_format.c ocas_helper.c
+svmocas.$(MEXSUFFIX): libocas.c libocas.h libqp_splx.c libqp.h svmocas_mex.c lib_svmlight_format.c lib_svmlight_format.h ocas_helper.c ocas_helper.h features_int8.h features_int8.c features_double.h features_double.c features_single.h features_single.c
+		$(MEX) $(MEXFLAGS) -DLIBOCAS_MATLAB -O -output svmocas.$(MEXSUFFIX) svmocas_mex.c lib_svmlight_format.c ocas_helper.c features_int8.c features_double.c features_single.c libocas.c libqp_splx.c
 
+svmocas_light.$(MEXSUFFIX): libocas.c libocas.h libqp_splx.c libqp.h svmocas_light_mex.c lib_svmlight_format.c lib_svmlight_format.h ocas_helper.c ocas_helper.h features_double.h features_double.c
+		$(MEX) $(MEXFLAGS) -DLIBOCAS_MATLAB -O -output svmocas_light.$(MEXSUFFIX) svmocas_light_mex.c lib_svmlight_format.c ocas_helper.c features_double.c libocas.c libqp_splx.c
 		
-svmlight_linclass.$(MEXSUFFIX): svmlight_linclass_mex.c lib_svmlight_format.c lib_svmlight_format.h ocas_helper.c ocas_helper.h
-		$(MEX) $(MEXFLAGS) -DLIBOCAS_MATLAB -O -output svmlight_linclass.$(MEXSUFFIX) svmlight_linclass_mex.c lib_svmlight_format.c ocas_helper.c
-		
-msvmocas.$(MEXSUFFIX): libocas.c libocas.h libqp_splx.c libqp.h msvmocas_mex.c lib_svmlight_format.c lib_svmlight_format.h ocas_helper.c ocas_helper.h
-		$(MEX) $(MEXFLAGS) -DLIBOCAS_MATLAB -O -output msvmocas.$(MEXSUFFIX) msvmocas_mex.c lib_svmlight_format.c ocas_helper.c libocas.c libqp_splx.c
+linclassif_light.$(MEXSUFFIX): linclassif_light_mex.c lib_svmlight_format.c lib_svmlight_format.h ocas_helper.c ocas_helper.h
+		$(MEX) $(MEXFLAGS) -DLIBOCAS_MATLAB -O -output linclassif_light.$(MEXSUFFIX) linclassif_light_mex.c lib_svmlight_format.c ocas_helper.c
+
+msvmocas.$(MEXSUFFIX): libocas.c libocas.h libqp_splx.c libqp.h msvmocas_mex.c lib_svmlight_format.c lib_svmlight_format.h ocas_helper.c ocas_helper.h features_double.h features_double.c
+		$(MEX) $(MEXFLAGS) -DLIBOCAS_MATLAB -O -output msvmocas.$(MEXSUFFIX) msvmocas_mex.c lib_svmlight_format.c ocas_helper.c features_double.c libocas.c libqp_splx.c
+
+msvmocas_light.$(MEXSUFFIX): libocas.c libocas.h libqp_splx.c libqp.h msvmocas_light_mex.c lib_svmlight_format.c lib_svmlight_format.h ocas_helper.c ocas_helper.h features_double.h features_double.c
+		$(MEX) $(MEXFLAGS) -DLIBOCAS_MATLAB -O -output msvmocas_light.$(MEXSUFFIX) msvmocas_light_mex.c lib_svmlight_format.c ocas_helper.c features_double.c libocas.c libqp_splx.c
 		
 lbppyr.$(MEXSUFFIX): lbppyr_mex.c
 		$(MEX) $(MEXFLAGS) -O -output lbppyr.$(MEXSUFFIX) lbppyr_mex.c 	
@@ -43,21 +45,21 @@ lbpfilter.$(MEXSUFFIX): lbpfilter_mex.c
 
 
 else 
-all: libocas.so svmocas msvmocas
+all: libocas.so svmocas msvmocas linclass
 endif
 
-svmocas:	svmocas.c lib_svmlight_format.c sparse_mat.c ocas_helper.c ocas_helper.h libocas.h sparse_mat.h libocas.c
-		$(CC) $(CFLAGS) -o $@ svmocas.c lib_svmlight_format.c sparse_mat.c ocas_helper.c libocas.c libqp_splx.c
+svmocas:	svmocas.c lib_svmlight_format.c sparse_mat.c ocas_helper.c ocas_helper.h libocas.h sparse_mat.h libocas.c features_double.h features_double.c
+		$(CC) $(CFLAGS) -o $@ svmocas.c lib_svmlight_format.c sparse_mat.c ocas_helper.c features_double.c libocas.c libqp_splx.c $(CLIBS)
 
-msvmocas:	msvmocas.c lib_svmlight_format.c sparse_mat.c ocas_helper.c ocas_helper.h libocas.h sparse_mat.h libocas.c
-		$(CC) $(CFLAGS) -o $@ msvmocas.c lib_svmlight_format.c sparse_mat.c ocas_helper.c libocas.c libqp_splx.c
+msvmocas:	msvmocas.c lib_svmlight_format.c sparse_mat.c ocas_helper.c ocas_helper.h libocas.h sparse_mat.h libocas.c features_double.h features_double.c
+		$(CC) $(CFLAGS) -o $@ msvmocas.c lib_svmlight_format.c sparse_mat.c ocas_helper.c features_double.c libocas.c libqp_splx.c $(CLIBS)
 
-linclass:	linclass.c lib_svmlight_format.c libocas.h 
-		$(CC) $(CFLAGS) -o $@ linclass.c lib_svmlight_format.c  
+linclassif:	linclassif.c lib_svmlight_format.c libocas.h 
+		$(CC) $(CFLAGS) -o $@ linclassif.c lib_svmlight_format.c $(CLIBS)
 
 
 libocas.so:	libocas.c libocas.h libqp_splx.c libqp.h 
-		$(CC) $(CFLAGS) -shared -o $@ libocas.c libqp_splx.c
+		$(CC) $(CFLAGS) -shared -o $@ libocas.c libqp_splx.c $(CLIBS)
 
 clean: 
-		rm -f *~ svmocas.$(MEXSUFFIX) svmlight_linclass.$(MEXSUFFIX) svmocas msvmocas linclass libocas.so msvmocas.$(MEXSUFFIX) lbpfilter.$(MEXSUFFIX) lbppyr_features.$(MEXSUFFIX) svmocas_lbp.$(MEXSUFFIX) lbppyr.$(MEXSUFFIX) compute_errors.$(MEXSUFFIX)
+		rm -f *~ svmocas.$(MEXSUFFIX) svmocas_light.$(MEXSUFFIX) linclassif_light.$(MEXSUFFIX) svmocas msvmocas linclassif libocas.so msvmocas.$(MEXSUFFIX) msvmocas_light.$(MEXSUFFIX) lbppyr_features.$(MEXSUFFIX) svmocas_lbp.$(MEXSUFFIX) compute_auc.$(MEXSUFFIX)
diff --git a/README b/README
index da840c9..4cd3837 100644
--- a/README
+++ b/README
@@ -3,15 +3,14 @@ solver for training linear SVM classifiers
 
 FEATURES
  - SVM solvers for training linear classifiers from large scale-data.
- - Binary (two-class) and genuine multi-class SVM formulations.
- - Optimized code written in C.
+ - Two-class and genuine multi-class SVM formulations.
  - A stand alone application and MEX interface for Matlab.
+ - Optimized for features represented in by different data types: 
+   sparse/dense, double/single precision, int8.
  - Reads examples from SVM^light format.
- - Optimized for both sparse and dense features.
- - Parallelized version of the binary solver.
- - Allows using different C for each training example (Matlab's interace to binary solver).
- - Tools for classification.
- - Training translation invariant image classifiers from virtual examples.
+ - Parallelized version of the two-class SVM solver.
+ - Allows using different C for each training example (only for Matlab).
+ - Training translation invariant image classifier from virtual examples using LBP features.
  - Functions for computing image features based on Local Binary Patterns (LBP).
 
 
@@ -22,12 +21,13 @@ SVM classifiers:
 
 1. Binary case: OCAS solves the following unconstrained convex optimization task
     
-   W^*,W0^* = argmin 0.5*(W'*W+W0^2) + C*sum max( 0, 1-y(i)*(W'*X(:,i)+W0*X0) )
+   W^*,W0^* = argmin 0.5*(W'*W+W0^2) + sum C(i)*max( 0, 1-y(i)*(W'*X(:,i)+W0*X0) )
                 W,W0                  i=1:nData
 
-where C is the regularization constant, X [nDim x nData] are training feature
-vectors and y [nData x 1] are their binary labels (+1/-1). The result are 
-parameters W^* [nDim x 1], W0^* [1 x 1] of the linear rule
+where C [nData x 1] is the regularization constant for each example, 
+X [nDim x nData] are training feature vectors and y [nData x 1] are their
+binary labels (+1/-1). The result are parameters W^* [nDim x 1], W0^* [1 x 1] of
+the linear rule
 
       f(X) = sign( X'*W + W0 )
 
@@ -50,8 +50,7 @@ LIBOCAS can be downloaded from
 
 PLATFORMS
 
-GNU/Linux. 
-
+Developed and tested under GNU/Linux. 
 
 LICENSE
 
@@ -71,4 +70,4 @@ V. Franc, S. Sonnenburg. OCAS optimized cutting plane algorithm for Support Vect
 S. Sonnenburg, V. Franc.  COFFIN: A Computational Framework for Linear SVMs.  
   In Proceedings of the 27nd International Machine Learning Conference (ICML'10). 
   Haifa 2010.
-  http://cmp.felk.cvut.cz/~xfrancv/papers/Sonnenburg-COFFIN-ICML10.pdf
+  http://cmp.felk.cvut.cz/~xfrancv/papers/Sonnenburg-COFFIN-ICML10.pdf
\ No newline at end of file
diff --git a/compute_auc.m b/compute_auc.m
new file mode 100644
index 0000000..a7bc74a
--- /dev/null
+++ b/compute_auc.m
@@ -0,0 +1,15 @@
+% COMPUTE_AUC computes area under ROC.
+%
+% Synopsis:
+%  auc = compute_auc(score,trueLabels)
+% 
+% Input:
+%   score [N x 1 (double)] score of two-class classifier; positive class has 
+%       score >= 0 while negative class has score < 0 
+%   trueLabels [N x 1 (double)] positive class 1; negative class ~= 1
+% Output: 
+%   auc [1x1] Area Under ROC.
+%
+% Example:
+%   help svmocas
+%
diff --git a/compute_auc.mexa64 b/compute_auc.mexa64
new file mode 100755
index 0000000..975441d
Binary files /dev/null and b/compute_auc.mexa64 differ
diff --git a/compute_errors_mex.c b/compute_auc_mex.c
similarity index 69%
rename from compute_errors_mex.c
rename to compute_auc_mex.c
index de418d6..417034b 100644
--- a/compute_errors_mex.c
+++ b/compute_auc_mex.c
@@ -1,8 +1,8 @@
 /*=================================================================
- * COMPUTE_ERRORS computes classification error and area under ROC.
+ * COMPUTE_AUC computes area under ROC.
  *
  *  Synopsis:
- *    [error,auc] = compute_errors(score,true_labels)
+ *    auc = compute_auc(score,true_labels)
  *
  *  Input:
  *   scores [1 x n] scores of binary classifier; the classifier decides 
@@ -10,7 +10,6 @@
  *   true_labels [1 x n] true labels; 1st class label = 1, 
  *                                    2nd class label != 1
  *  Output:
- *   error [1x1] number of mis-classifications
  *   auc [1x1] Area under ROC 
  *
  *=================================================================*/
@@ -39,18 +38,17 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
 {
   int *true_labels_int;
   uint32_t n1, n2, i;
-  double auc, error;
+  double auc; /*, error;*/
 
   double *scores, *true_labels;
 
   if( nrhs != 2 )
     mexErrMsgTxt("Two input arguments must be passed.\n"
                  "\n"
-                 "[error,auc] = compute_errors(score,true_labels)\n"
-                 "Inputs: score [N x 1 (double)] positive class score >= 0 otherwise negative class \n"
-                 "        true_labels [N x 1 (double)] positive class 1; negative class ~= 1\n"
-                 "Outputs: error [1x1] number of misclassifications\n"
-                 "         auc [1x1] Arrea Under ROC\n");
+                 "auc = compute_auc(score,trueLabels)\n"
+                 "Inputs:  score [N x 1 (double)] positive class score >= 0 otherwise negative class \n"
+                 "         trueLabels [N x 1 (double)] positive class 1; negative class ~= 1\n"
+                 "Outputs: auc [1x1] Arrea Under ROC\n");
 
   scores = mxGetPr(prhs[0]);
   true_labels = mxGetPr(prhs[1]);
@@ -66,21 +64,21 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
   if(true_labels_int == NULL)
     mexErrMsgTxt("Not enough memory.");
 
-  error = 0;
+  /*error = 0;*/
   for(i = 0; i < n1; i++)
   {
     true_labels_int[i] = (int)true_labels[i];
 
-    if((true_labels[i] == 1 && scores[i] <= 0) || (true_labels[i] != 1 && scores[i] > 0))
-      error++;
+/*    if((true_labels[i] == 1 && scores[i] <= 0) || (true_labels[i] != 1 && scores[i] > 0))
+      error++;*/
   }
 
   auc = compute_auc(scores, true_labels_int, n1);
 
   mxFree(true_labels_int);
 
-  plhs[0] = mxCreateDoubleScalar(error);
-  plhs[1] = mxCreateDoubleScalar(auc);
+  /*plhs[0] = mxCreateDoubleScalar(error);*/
+  plhs[0] = mxCreateDoubleScalar(auc);
 
   return;
 }
diff --git a/data/reference_solution.mat b/data/reference_solution.mat
new file mode 100644
index 0000000..174450d
Binary files /dev/null and b/data/reference_solution.mat differ
diff --git a/data/refernce_solution.mat b/data/refernce_solution.mat
deleted file mode 100644
index ad939e0..0000000
Binary files a/data/refernce_solution.mat and /dev/null differ
diff --git a/features_double.c b/features_double.c
new file mode 100644
index 0000000..9bed263
--- /dev/null
+++ b/features_double.c
@@ -0,0 +1,372 @@
+/*-----------------------------------------------------------------------
+ * features_double.c: Helper functions for the OCAS solver working with 
+ *                    features in double precision.
+ *-------------------------------------------------------------------- */
+
+
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "ocas_helper.h"
+#include "features_double.h"
+
+/*----------------------------------------------------------------------------------
+  sparse_add_new_cut( new_col_H, new_cut, cut_length, nSel ) does the following:
+
+    new_a = zeros(nDim,nY);
+    for i=1:nData
+       if new_cut(i) ~= data_y(i)
+          new_a(:,data_y(i)) = new_a(:,data_y(i)) + X(;,i);
+          new_a(:,new_cut(i)) = new_a(:,new_cut(i)) - X(;,i);
+       end
+    end
+
+    new_col_H = [sparse_A(:,1:nSel)'*new_a ; new_a'*new_a];
+    sparse_A(:,nSel+1) = new_a;
+
+    Warning: data_y is 1-based while new_cut is 0-based
+
+  ---------------------------------------------------------------------------------*/
+int msvm_sparse_add_new_cut( double *new_col_H, 
+                         uint32_t *new_cut, 
+                         uint32_t nSel, 
+                         void* user_data )
+{
+/*  double *new_a, */
+  double sq_norm_a;
+  uint32_t i, j, nz_dims, ptr, y;
+
+  memset(new_a, 0, sizeof(double)*nY*nDim);
+  
+  for(i=0; i < nData; i++)
+  {
+    y = (uint32_t)(data_y[i]-1);
+    if(new_cut[i] != y)
+    {
+      add_sparse_col(&new_a[nDim*y], data_X, i);
+      subtract_sparse_col(&new_a[nDim*(uint32_t)new_cut[i]], data_X, i);
+    }
+  }
+ 
+  /* compute new_a'*new_a and count number of non-zero dimensions */
+  nz_dims = 0; 
+  sq_norm_a = 0;
+  for(j=0; j < nY*nDim; j++ ) {
+    if(new_a[j] != 0) {
+      nz_dims++;
+      sq_norm_a += new_a[j]*new_a[j];
+    }
+  }
+
+  /* sparsify new_a and insert it to the last column  of sparse_A */
+  sparse_A.nz_dims[nSel] = nz_dims;
+  if(nz_dims > 0) {
+    sparse_A.index[nSel] = NULL;
+    sparse_A.value[nSel] = NULL;
+    sparse_A.index[nSel] = mxCalloc(nz_dims,sizeof(uint32_t));
+    sparse_A.value[nSel] = mxCalloc(nz_dims,sizeof(double));
+    if(sparse_A.index[nSel]==NULL || sparse_A.value[nSel]==NULL)
+    {
+/*      mexErrMsgTxt("Not enough memory for vector sparse_A.index[nSel], sparse_A.value[nSel].");*/
+      mxFree(sparse_A.index[nSel]);
+      mxFree(sparse_A.value[nSel]);
+      return(-1);
+    }
+
+    ptr = 0;
+    for(j=0; j < nY*nDim; j++ ) {
+      if(new_a[j] != 0) {
+        sparse_A.index[nSel][ptr] = j;
+        sparse_A.value[nSel][ptr++] = new_a[j];
+      }
+    }
+  }
+   
+  new_col_H[nSel] = sq_norm_a;
+  for(i=0; i < nSel; i++) {
+    double tmp = 0;
+
+    for(j=0; j < sparse_A.nz_dims[i]; j++) {
+      tmp += new_a[sparse_A.index[i][j]]*sparse_A.value[i][j];
+    }
+      
+    new_col_H[i] = tmp;
+  }
+
+  return 0;
+}
+
+
+/*----------------------------------------------------------------------
+  sparse_compute_output( output ) does the follwing:
+
+  output = W'*data_X;
+  ----------------------------------------------------------------------*/
+int msvm_sparse_compute_output( double *output, void* user_data )
+{
+  uint32_t i,y;
+
+  for(i=0; i < nData; i++) 
+  {
+    for(y=0; y < nY; y++)
+    {
+      output[LIBOCAS_INDEX(y,i,nY)] = dp_sparse_col(&W[y*nDim], data_X, i);
+    }
+  }
+  
+  return 0;
+}
+
+/*----------------------------------------------------------------------------------
+  full_add_new_cut( new_col_H, new_cut, cut_length, nSel ) does the following:
+
+    new_a = sum(data_X(:,find(new_cut ~=0 )),2);
+    new_col_H = [full_A(:,1:nSel)'*new_a ; new_a'*new_a];
+    full_A(:,nSel+1) = new_a;
+
+  ---------------------------------------------------------------------------------*/
+int msvm_full_add_new_cut( double *new_col_H, uint32_t *new_cut, uint32_t nSel, void* user_data)
+{
+  double sq_norm_a, *ptr;
+  uint32_t i, j, y, y2;
+
+  ptr = mxGetPr(data_X);
+
+  memset(new_a, 0, sizeof(double)*nDim*nY);
+
+  for(i=0; i < nData; i++)
+  {
+    y = (uint32_t)(data_y[i]-1);
+    y2 = (uint32_t)new_cut[i];
+    if(y2 != y)
+    {
+      for(j=0; j < nDim; j++ ) 
+      {
+        new_a[LIBOCAS_INDEX(j,y,nDim)] += ptr[LIBOCAS_INDEX(j,i,nDim)];
+        new_a[LIBOCAS_INDEX(j,y2,nDim)] -= ptr[LIBOCAS_INDEX(j,i,nDim)];
+      }
+    }
+  }
+
+  /* compute new_a'*new_a and insert new_a to the last column of full_A */
+  sq_norm_a = 0;
+  for(j=0; j < nDim*nY; j++ ) {
+    sq_norm_a += new_a[j]*new_a[j];
+    full_A[LIBOCAS_INDEX(j,nSel,nDim*nY)] = new_a[j];
+  }
+
+  new_col_H[nSel] = sq_norm_a;
+  for(i=0; i < nSel; i++) {
+    double tmp = 0;
+
+    for(j=0; j < nDim*nY; j++ ) {
+      tmp += new_a[j]*full_A[LIBOCAS_INDEX(j,i,nDim*nY)];
+    }
+    new_col_H[i] = tmp;
+  }
+
+  return 0;
+}
+
+
+/*----------------------------------------------------------------------
+  full_compute_output( output ) does the follwing:
+
+  output = data_X'*W;
+  ----------------------------------------------------------------------*/
+int msvm_full_compute_output( double *output, void* user_data )
+{
+  uint32_t i, j, y;
+  double *ptr, tmp;
+
+  ptr = mxGetPr( data_X );
+
+  for(i=0; i < nData; i++) 
+  { 
+    for(y=0; y < nY; y++)
+    {
+      tmp = 0;
+
+      for(j=0; j < nDim; j++ ) 
+      {
+        tmp += W[LIBOCAS_INDEX(j,y,nDim)]*ptr[LIBOCAS_INDEX(j,i,nDim)];
+      }
+      
+      output[LIBOCAS_INDEX(y,i,nY)] = tmp;
+    }
+  }
+  
+  return 0;
+}
+
+/*----------------------------------------------------------------------------------
+  sparse_add_new_cut( new_col_H, new_cut, cut_length, nSel ) does the following:
+
+    new_a = sum(data_X(:,find(new_cut ~=0 )),2);
+    new_col_H = [sparse_A(:,1:nSel)'*new_a ; new_a'*new_a];
+    sparse_A(:,nSel+1) = new_a;
+
+  ---------------------------------------------------------------------------------*/
+int sparse_add_new_cut( double *new_col_H, 
+                         uint32_t *new_cut, 
+                         uint32_t cut_length, 
+                         uint32_t nSel, 
+                         void* user_data )
+{
+/*  double *new_a, */
+  double sq_norm_a;
+  uint32_t i, j, nz_dims, ptr;
+
+  memset(new_a, 0, sizeof(double)*nDim);
+  
+  for(i=0; i < cut_length; i++) {
+    add_sparse_col(new_a, data_X, new_cut[i]);
+
+    A0[nSel] += X0*data_y[new_cut[i]];    
+  }
+ 
+  /* compute new_a'*new_a and count number of non-zero dimensions */
+  nz_dims = 0; 
+  sq_norm_a = A0[nSel]*A0[nSel];
+  for(j=0; j < nDim; j++ ) {
+    if(new_a[j] != 0) {
+      nz_dims++;
+      sq_norm_a += new_a[j]*new_a[j];
+    }
+  }
+
+  /* sparsify new_a and insert it to the last column  of sparse_A */
+  sparse_A.nz_dims[nSel] = nz_dims;
+  if(nz_dims > 0) {
+    sparse_A.index[nSel] = NULL;
+    sparse_A.value[nSel] = NULL;
+    sparse_A.index[nSel] = mxCalloc(nz_dims,sizeof(uint32_t));
+    sparse_A.value[nSel] = mxCalloc(nz_dims,sizeof(double));
+    if(sparse_A.index[nSel]==NULL || sparse_A.value[nSel]==NULL)
+    {
+/*      mexErrMsgTxt("Not enough memory for vector sparse_A.index[nSel], sparse_A.value[nSel].");*/
+      mxFree(sparse_A.index[nSel]);
+      mxFree(sparse_A.value[nSel]);
+      return(-1);
+    }
+
+    ptr = 0;
+    for(j=0; j < nDim; j++ ) {
+      if(new_a[j] != 0) {
+        sparse_A.index[nSel][ptr] = j;
+        sparse_A.value[nSel][ptr++] = new_a[j];
+      }
+    }
+  }
+   
+  new_col_H[nSel] = sq_norm_a;
+  for(i=0; i < nSel; i++) {
+    double tmp = A0[nSel]*A0[i];
+
+    for(j=0; j < sparse_A.nz_dims[i]; j++) {
+      tmp += new_a[sparse_A.index[i][j]]*sparse_A.value[i][j];
+    }
+      
+    new_col_H[i] = tmp;
+  }
+
+/*  mxFree( new_a );*/
+
+  return 0;
+}
+
+
+/*----------------------------------------------------------------------------------
+  full_add_new_cut( new_col_H, new_cut, cut_length, nSel ) does the following:
+
+    new_a = sum(data_X(:,find(new_cut ~=0 )),2);
+    new_col_H = [full_A(:,1:nSel)'*new_a ; new_a'*new_a];
+    full_A(:,nSel+1) = new_a;
+
+  ---------------------------------------------------------------------------------*/
+int full_add_new_cut( double *new_col_H, 
+                       uint32_t *new_cut, 
+                       uint32_t cut_length, 
+                       uint32_t nSel,
+                       void* user_data)
+{
+/*  double *new_a, */
+  double sq_norm_a, *ptr;
+  uint32_t i, j;
+
+  ptr = mxGetPr(data_X);
+
+  memset(new_a, 0, sizeof(double)*nDim);
+
+
+  for(i=0; i < cut_length; i++) {
+    for(j=0; j < nDim; j++ ) {
+      new_a[j] += ptr[LIBOCAS_INDEX(j,new_cut[i],nDim)];
+    }
+
+    A0[nSel] += X0*data_y[new_cut[i]];    
+  }
+
+  /* compute new_a'*new_a and insert new_a to the last column of full_A */
+  sq_norm_a = A0[nSel]*A0[nSel];
+  for(j=0; j < nDim; j++ ) {
+    sq_norm_a += new_a[j]*new_a[j];
+    full_A[LIBOCAS_INDEX(j,nSel,nDim)] = new_a[j];
+  }
+
+  new_col_H[nSel] = sq_norm_a;
+  for(i=0; i < nSel; i++) {
+    double tmp = A0[nSel]*A0[i];
+
+    for(j=0; j < nDim; j++ ) {
+      tmp += new_a[j]*full_A[LIBOCAS_INDEX(j,i,nDim)];
+    }
+    new_col_H[i] = tmp;
+  }
+
+/*  mxFree( new_a );*/
+
+  return 0;
+}
+
+
+/*----------------------------------------------------------------------
+  sparse_compute_output( output ) does the follwing:
+
+  output = data_X'*W;
+  ----------------------------------------------------------------------*/
+int sparse_compute_output( double *output, void* user_data )
+{
+  uint32_t i;
+
+  for(i=0; i < nData; i++) { 
+    output[i] = data_y[i]*X0*W0 + dp_sparse_col(W, data_X, i);
+  }
+  
+  return 0;
+}
+
+/*----------------------------------------------------------------------
+  full_compute_output( output ) does the follwing:
+
+  output = data_X'*W;
+  ----------------------------------------------------------------------*/
+int full_compute_output( double *output, void* user_data )
+{
+  uint32_t i, j;
+  double *ptr, tmp;
+
+  ptr = mxGetPr( data_X );
+
+  for(i=0; i < nData; i++) { 
+    tmp = data_y[i]*X0*W0;
+
+    for(j=0; j < nDim; j++ ) {
+      tmp += W[j]*ptr[LIBOCAS_INDEX(j,i,nDim)];
+    }
+    output[i] = tmp;
+  }
+  
+  return 0;
+}
\ No newline at end of file
diff --git a/features_double.h b/features_double.h
new file mode 100644
index 0000000..a44ed60
--- /dev/null
+++ b/features_double.h
@@ -0,0 +1,37 @@
+/*-----------------------------------------------------------------------
+ * features_double.h: Helper functions for the OCAS solver working with 
+ *                   features in double precision.
+ *-------------------------------------------------------------------- */
+
+#ifndef _features_double_h
+#define _features_double_h
+
+#include <stdint.h>
+
+/* dense double features */
+extern int full_compute_output( double *output, void* user_data );
+extern int full_add_new_cut( double *new_col_H, 
+                       uint32_t *new_cut, 
+                       uint32_t cut_length, 
+                       uint32_t nSel,
+                       void* user_data);
+
+/* sparse double features */
+extern int sparse_add_new_cut( double *new_col_H, 
+                         uint32_t *new_cut, 
+                         uint32_t cut_length, 
+                         uint32_t nSel, 
+                         void* user_data );
+extern int sparse_compute_output( double *output, void* user_data );
+
+
+/* dense double features for multi-class solver */
+extern int msvm_full_add_new_cut( double *new_col_H, uint32_t *new_cut, uint32_t nSel, void* user_data);
+extern int msvm_full_compute_output( double *output, void* user_data );
+
+/* sparse double features for multi-class solver */
+extern int msvm_sparse_add_new_cut( double *new_col_H, uint32_t *new_cut, uint32_t nSel, void* user_data );
+extern int msvm_sparse_compute_output( double *output, void* user_data );
+
+
+#endif
diff --git a/features_int8.c b/features_int8.c
new file mode 100644
index 0000000..e6f8918
--- /dev/null
+++ b/features_int8.c
@@ -0,0 +1,89 @@
+/*-----------------------------------------------------------------------
+ * features_int8.c: Helper functions for the OCAS solver working with 
+ *                 INT8 features.
+ *-------------------------------------------------------------------- */
+
+#include <stdint.h>
+#include <string.h>
+
+#include "ocas_helper.h"
+#include "features_int8.h"
+
+
+/*----------------------------------------------------------------------------------
+  full_add_new_cut( new_col_H, new_cut, cut_length, nSel ) does the following:
+
+    new_a = sum(data_X(:,find(new_cut ~=0 )),2);
+    new_col_H = [full_A(:,1:nSel)'*new_a ; new_a'*new_a];
+    full_A(:,nSel+1) = new_a;
+
+  ---------------------------------------------------------------------------------*/
+int full_int8_add_new_cut( double *new_col_H, 
+                           uint32_t *new_cut, 
+                           uint32_t cut_length, 
+                           uint32_t nSel,
+                           void* user_data)
+{
+/*  double *new_a, */
+  double sq_norm_a;
+  uint32_t i, j;
+  int8_t *ptr;
+
+  ptr = (int8_t*)mxGetPr(data_X);
+
+  memset(new_a, 0, sizeof(double)*nDim);
+
+
+  for(i=0; i < cut_length; i++) {
+    for(j=0; j < nDim; j++ ) {
+      new_a[j] += (double)ptr[LIBOCAS_INDEX(j,new_cut[i],nDim)];
+    }
+
+    A0[nSel] += X0*data_y[new_cut[i]];    
+  }
+
+  /* compute new_a'*new_a and insert new_a to the last column of full_A */
+  sq_norm_a = A0[nSel]*A0[nSel];
+  for(j=0; j < nDim; j++ ) {
+    sq_norm_a += new_a[j]*new_a[j];
+    full_A[LIBOCAS_INDEX(j,nSel,nDim)] = new_a[j];
+  }
+
+  new_col_H[nSel] = sq_norm_a;
+  for(i=0; i < nSel; i++) {
+    double tmp = A0[nSel]*A0[i];
+
+    for(j=0; j < nDim; j++ ) {
+      tmp += new_a[j]*full_A[LIBOCAS_INDEX(j,i,nDim)];
+    }
+    new_col_H[i] = tmp;
+  }
+
+  return 0;
+}
+
+/*----------------------------------------------------------------------
+  full_int8_compute_output( output ) does the follwing:
+
+  output = data_X'*W;
+  ----------------------------------------------------------------------*/
+int full_int8_compute_output( double *output, void* user_data )
+{
+  uint32_t i, j;
+  double tmp;
+  int8_t* ptr;
+
+  ptr = (int8_t*)mxGetPr( data_X );
+
+  for(i=0; i < nData; i++) { 
+    tmp = data_y[i]*X0*W0;
+
+    for(j=0; j < nDim; j++ ) {
+      tmp += W[j]*(double)ptr[LIBOCAS_INDEX(j,i,nDim)];
+    }
+    output[i] = tmp;
+  }
+  
+  return 0;
+}
+
diff --git a/features_int8.h b/features_int8.h
new file mode 100644
index 0000000..b7a0222
--- /dev/null
+++ b/features_int8.h
@@ -0,0 +1,20 @@
+/*-----------------------------------------------------------------------
+ * features_int8.h: Helper functions for the OCAS solver working with 
+ *                 INT8 features.
+ *
+ *-------------------------------------------------------------------- */
+
+#ifndef _features_int8_h
+#define _features_int8_h
+
+#include <stdint.h>
+
+
+extern int full_int8_compute_output( double *output, void* user_data );
+extern int full_int8_add_new_cut( double *new_col_H, 
+                       uint32_t *new_cut, 
+                       uint32_t cut_length, 
+                       uint32_t nSel,
+                       void* user_data);
+
+#endif
diff --git a/features_single.c b/features_single.c
new file mode 100644
index 0000000..0b8296e
--- /dev/null
+++ b/features_single.c
@@ -0,0 +1,91 @@
+/*-----------------------------------------------------------------------
+ * features_single.c: Helper functions for the OCAS solver working with 
+ *                    features in single precision.
+ *-------------------------------------------------------------------- */
+
+
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "ocas_helper.h"
+#include "features_single.h"
+
+/*----------------------------------------------------------------------------------
+  full_add_new_cut( new_col_H, new_cut, cut_length, nSel ) does the following:
+
+    new_a = sum(data_X(:,find(new_cut ~=0 )),2);
+    new_col_H = [full_A(:,1:nSel)'*new_a ; new_a'*new_a];
+    full_A(:,nSel+1) = new_a;
+
+  ---------------------------------------------------------------------------------*/
+int full_single_add_new_cut( double *new_col_H, 
+                       uint32_t *new_cut, 
+                       uint32_t cut_length, 
+                       uint32_t nSel,
+                       void* user_data)
+{
+  double sq_norm_a;
+  float *ptr;
+  uint32_t i, j;
+
+  ptr = (float*)mxGetPr(data_X);
+
+  memset(new_a, 0, sizeof(double)*nDim);
+
+
+  for(i=0; i < cut_length; i++) {
+    for(j=0; j < nDim; j++ ) {
+      new_a[j] += (double)ptr[LIBOCAS_INDEX(j,new_cut[i],nDim)];
+    }
+
+    A0[nSel] += X0*data_y[new_cut[i]];    
+  }
+
+  /* compute new_a'*new_a and insert new_a to the last column of full_A */
+  sq_norm_a = A0[nSel]*A0[nSel];
+  for(j=0; j < nDim; j++ ) {
+    sq_norm_a += new_a[j]*new_a[j];
+    full_A[LIBOCAS_INDEX(j,nSel,nDim)] = new_a[j];
+  }
+
+  new_col_H[nSel] = sq_norm_a;
+  for(i=0; i < nSel; i++) {
+    double tmp = A0[nSel]*A0[i];
+
+    for(j=0; j < nDim; j++ ) {
+      tmp += new_a[j]*full_A[LIBOCAS_INDEX(j,i,nDim)];
+    }
+    new_col_H[i] = tmp;
+  }
+
+/*  mxFree( new_a );*/
+
+  return 0;
+}
+
+
+/*----------------------------------------------------------------------
+  full_compute_output( output ) does the follwing:
+
+  output = data_X'*W;
+  ----------------------------------------------------------------------*/
+int full_single_compute_output( double *output, void* user_data )
+{
+  uint32_t i, j;
+  float *ptr;
+  double tmp;
+
+  ptr = (float*)mxGetPr( data_X );
+
+  for(i=0; i < nData; i++) { 
+    tmp = data_y[i]*X0*W0;
+
+    for(j=0; j < nDim; j++ ) {
+      tmp += W[j] * (double)ptr[LIBOCAS_INDEX(j,i,nDim)];
+    }
+    output[i] = tmp;
+  }
+  
+  return 0;
+}
\ No newline at end of file
diff --git a/features_single.h b/features_single.h
new file mode 100644
index 0000000..c7e06d2
--- /dev/null
+++ b/features_single.h
@@ -0,0 +1,20 @@
+/*-----------------------------------------------------------------------
+ * features_single.h: Helper functions for the OCAS solver working with 
+ *                   features in double precision.
+ *-------------------------------------------------------------------- */
+
+#ifndef _features_single_h
+#define _features_single_h
+
+#include <stdint.h>
+
+/* dense double features */
+extern int full_single_compute_output( double *output, void* user_data );
+extern int full_single_add_new_cut( double *new_col_H, 
+                       uint32_t *new_cut, 
+                       uint32_t cut_length, 
+                       uint32_t nSel,
+                       void* user_data);
+
+
+#endif
diff --git a/html/ChangeLog b/html/ChangeLog
index 5e762e3..cd5b4d2 100644
--- a/html/ChangeLog
+++ b/html/ChangeLog
@@ -1,3 +1,5 @@
+2011-12-22 Vojtech Fracn
+	* Added "svmocas_int8" supporting features represented as int8.
 2010-06-11  Vojtech Franc
         * Added functions which implement the COFFIN framework for training 
         * translation invariant image classifier from virtual example.
diff --git a/html/index.html b/html/index.html
index 13ee3c8..4d8814c 100644
--- a/html/index.html
+++ b/html/index.html
@@ -13,7 +13,7 @@ classifiers from large-scale data</H2>
 <A href="http://ida.first.fraunhofer.de/homepages/sonne/first/">Soeren
 Sonnenburg</a>
 <p>
-Last Modified: 11-Jun-2010
+Last Modified: 06-Feb-2012
 
 </div>
 
@@ -47,18 +47,15 @@ notebook with just 4GB of memory.
 <h4>Features</h4>
 
 <ul>
-   <li>SVM solvers for training linear classifiers from large scale-data.</li>
-   <li>Binary (two-class) and genuine multi-class SVM formulations.</li>
-   <li>Optimized code written in C.</li>
-   <li>A stand alone application and MEX interface for Matlab.</li>
-   <li>Reads examples from SVM^light format.</li>
-   <li>Optimized for both sparse and dense features.</li>  
-   <li>Parallelized version of the binary solver.</li>
-   <li>Allows using different C for each training example (Matlab's interace to binary solver).</li>
-   <li>Tools for classification.</li>
-   <li><img align="top" border="0" src="new.gif"> Training translation invariant image classifiers from virtual examples.</li>
-   <li><img align="top" border="0" src="new.gif"> Functions for computing image features based on Local Binary Patterns (LBP).</li>
-
+  <li>SVM solvers for training linear classifiers from large scale-data.</li>
+  <li>Two-class and genuine multi-class SVM formulations.</li>
+  <li>A stand alone application and MEX interface for Matlab.</li>
+  <li>Optimized for features represented by different data types: sparse/dense, double/single precision, int8.</li>
+  <li>Reads examples from SVM^light format.</li>
+  <li>Parallelized version of the two-class SVM solver.</li>
+  <li>Allows using different C for each training example (only for Matlab).</li>
+  <li>Training translation invariant image classifier from virtual examples using LBP features.</li>
+  <li>Functions for computing image features based on Local Binary Patterns (LBP).</li>
 </ul>
 
 <h4>Problem formulation</h4>
@@ -93,7 +90,11 @@ from <img align="top" border="0" src="set_y_sc.png">.
 
 LIBOCAS can be downloaded from here: 
 <ul>
-  <li><img align="top" border="0" src="new.gif"> Version 0.93, 2010-06-11, <a
+  <li><img align="top" border="0" src="new.gif"> Version 0.95, 2012-02-06, <a
+  href="http://cmp.felk.cvut.cz/~xfrancv/ocas/libocas_v095.zip">libocas_v095.zip</a>: Support for features in single precision floats. Code polished. </li>
+  <li>Version 0.94, 2011-12-22, <a
+  href="http://cmp.felk.cvut.cz/~xfrancv/ocas/libocas_v094.zip">libocas_v094.zip</a>: Support for features represented as int8. </li>
+  <li>Version 0.93, 2010-06-11, <a
   href="http://cmp.felk.cvut.cz/~xfrancv/ocas/libocas_v093.zip">libocas_v093.zip</a> </li>
   <li>Version 0.92, 2008-08-03, <a
   href="http://cmp.felk.cvut.cz/~xfrancv/ocas/libocas_v092.zip">libocas_v092.zip</a> </li>
diff --git a/lbpfilter_mex.c b/lbpfilter_mex.c
deleted file mode 100644
index 5681682..0000000
--- a/lbpfilter_mex.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/*=================================================================
- * LBPFILTER computes LBP for each 3x3 subwindow in input image.
- *
- * Synopsis:
- *  F = lbpfilter(I)
- * where
- *  I [h x w (double)] is input image.
- *  F [h x w (double)] is image of LBP responses;
- *   the border colums and rows, for which LBP is not defined, are set 0.
- *
- *=================================================================*/
-
-#include <stdio.h>
-#include <string.h>
-#include <stdint.h>
-#include <mex.h>
-#include <time.h>
-#include <errno.h>
-
-#define MIN(A,B) ((A) > (B) ? (B) : (A))
-#define MAX(A,B) ((A) < (B) ? (B) : (A))
-#define ABS(A) ((A) < 0 ? -(A) : (A))
-#define INDEX(ROW,COL,NUM_ROWS) ((COL)*(NUM_ROWS)+(ROW))
-
-
-/*======================================================================
-  Main code plus interface to Matlab.
-========================================================================*/
-
-void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
-{
-
-  double *I, *P;
-  int w,h, x,y;
-  double center;
-  unsigned char pattern;
-
-  if( nrhs != 1 )
-    mexErrMsgTxt("One input argument required.\n\n"
-                 "LBPFILTER computes LBP for each 3x3 subwindow in input image.\n"
-                 "\n"
-                 "Synopsis:\n"
-                 "  F = lbpfilter(I)\n"
-                 "where\n"
-                 "  I [h x w (double)] is input image.\n"
-                 "  F [h x w (double)] is image of LBP responses; \n"
-                 "    the border colums and rows, for which LBP is not defined, are set 0.\n"
-                 );
-
-  I = (double*)mxGetPr(prhs[0]);
-  h = mxGetM(prhs[0]);
-  w = mxGetN(prhs[0]);
-
-  plhs[0] = mxCreateDoubleMatrix(h,w,mxREAL);
-  P = (double*)mxGetPr(plhs[0]);
-
-  for(x=1; x < w-1; x++)
-  {
-    for(y=1; y< h-1; y++)
-    {
-      pattern = 0;
-      center = I[INDEX(y,x,h)];
-      if(I[INDEX(y-1,x-1,h)] < center) pattern = pattern | 0x01;
-      if(I[INDEX(y-1,x,h)] < center)   pattern = pattern | 0x02;
-      if(I[INDEX(y-1,x+1,h)] < center) pattern = pattern | 0x04;
-      if(I[INDEX(y,x-1,h)] < center)   pattern = pattern | 0x08;
-      if(I[INDEX(y,x+1,h)] < center)   pattern = pattern | 0x10;
-      if(I[INDEX(y+1,x-1,h)] < center) pattern = pattern | 0x20;
-      if(I[INDEX(y+1,x,h)] < center)   pattern = pattern | 0x40;
-      if(I[INDEX(y+1,x+1,h)] < center) pattern = pattern | 0x80;
-
-      P[INDEX(y,x,h)] = (double)pattern; 
-    }
-  }
-  
-  return;
-}
-
diff --git a/lbppyr.m b/lbppyr.m
deleted file mode 100644
index cfcba4b..0000000
--- a/lbppyr.m
+++ /dev/null
@@ -1,59 +0,0 @@
-function F = lbppyr(I, P)
-% LBPPYR computes LBP features on scale-pyramid of input image.
-%
-% Synopsis:
-%  F = lbppyr(I, P)
-%
-% Description:
-%  Local Binary Pattern (LBP) is 1 Byte number which encodes grey-scale
-%  intensities of a given 3x3 window.
-% 
-%  For P = 1, LBPPYR computes LBP features for all 3x3 windows
-%  in the input image I. The LBP features are stucked to a column 
-%  vector F.
-%
-%  For P > 1, the input image I is down-scaled (P-1)-times to create 
-%  a scale-pyramid of height P. Each subsequent level of the pyramid is
-%  obtained by downscaling the original image by 2. Having the pyramid,
-%  the LBP features are computed on each leavel of the pyramid and 
-%  they are stucked to a column vector F.
-%
-%  For more details on LBP see:
-%   Ojala, et. al: Multiresolution gray-scale and rotation invariant 
-%   texture classification with local binary patterns. IEEE PAMI, 
-%   24(7):971-987,2002.
-%
-% Input:
-%  I [H x W (uint8)] Input image.
-%  lbp_pyramid [1 x 1] Height of the LBP pyramids.
-%  
-% Output:
-%  F [nDim x 1] LBP features stucked to a column vector.
-%
-% Example:
-%  I = imread('./data/lena.jpg');
-%  F = lbppyr(I,4);
-%
-% Matlab code equivalent to LBPPYR_MEX.C:
-% 
-%  [h,w] = size(I);
-%  I = uint32(I);
-%  F = [];
-%  k = 1; 
-%  while k <= P & min(w,h) >= 3
-%     k = k + 1;
-%     tmp = lbpfilter(double(I));
-%     tmp = tmp(2:end-1,2:end-1);
-%     F = [F; tmp(:)];    
-%     if mod(w,2) == 1
-%        I = I(:,1:w-1);
-%        w= w - 1;
-%     end
-%     if mod(h,2) == 1
-%        I = I(1:h-1,:);
-%        h = h - 1;
-%     end
-%     I = I(1:2:h,1:2:w)+I(1:2:h,2:2:w)+I(2:2:h,1:2:w)+I(2:2:h,2:2:w);
-%     [h,w] = size(I);
-%  end
-%
\ No newline at end of file
diff --git a/lbppyr_features.mexa64 b/lbppyr_features.mexa64
new file mode 100755
index 0000000..65c4668
Binary files /dev/null and b/lbppyr_features.mexa64 differ
diff --git a/lbppyr_features_mex.c b/lbppyr_features_mex.c
index e31ab8b..bc173f2 100644
--- a/lbppyr_features_mex.c
+++ b/lbppyr_features_mex.c
@@ -29,9 +29,10 @@
 
 void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
 {
-  uint32_t i, j;
+/*  uint32_t i, j;*/
+  mwSize i, j;
   double *tmp;
-  char *Features ;
+  char *Features;
   uint8_t *CroppedWin;
   int verb;
 
@@ -58,7 +59,8 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
     verb = 1;
 
   uint8_t * Images = (uint8_t*)mxGetPr(prhs[0]);
-  uint32_t nImages = mxGetN(prhs[0]);
+/*  uint32_t nImages = mxGetN(prhs[0]);*/
+  mwSize nImages = mxGetN(prhs[0]);
 
   tmp = (double*)mxGetPr(prhs[1]);
   uint32_t im_H = (uint32_t)tmp[0];
@@ -74,9 +76,11 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
   uint16_t win_W = (uint16_t)tmp[1];
 
   uint16_t nPyramids = (uint32_t)mxGetScalar(prhs[4]);
-  uint32_t nDim =  liblbp_pyr_get_dim(win_H,win_W,nPyramids);
+/*  uint32_t nDim =  liblbp_pyr_get_dim(win_H,win_W,nPyramids);*/
+  mwSize nDim =  liblbp_pyr_get_dim(win_H,win_W,nPyramids);
 
-  uint32_t nData = mxGetN(prhs[2]);
+/*  uint32_t nData = mxGetN(prhs[2]);*/
+  mwSize nData = mxGetN(prhs[2]);
 
   if(verb)
   {
@@ -105,7 +109,8 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
   CroppedWin = (uint8_t*)mxGetPr(plhs[1]);
 
 
-  uint32_t cnt, cnt0, mirror,x,x1,y,y1,idx;
+/*  uint32_t cnt, cnt0, mirror,x,x1,y,y1,idx;*/
+  mwSize cnt, cnt0, mirror,x,x1,y,y1,idx;
   uint32_t *win;
   uint8_t *img_ptr;
   
diff --git a/lbppyr_mex.c b/lbppyr_mex.c
deleted file mode 100644
index a005149..0000000
--- a/lbppyr_mex.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/*=================================================================
- * LBPPYR computes LBP features on scale-pyramid of input image.
- * 
- * Synopsis:
- *  F = lbppyr_mat(I, P)
- * where
- *  I [H x W (uint8)] is input image.
- *  P [1 x 1 (double)] is height of the scale-pyramid.
- *  F [N x 1 (uint8)] LBP features stucked to a column vector. 
- *
- *=================================================================*/
-
-#include <stdio.h>
-#include <string.h>
-#include <stdint.h>
-#include <mex.h>
-#include <time.h>
-#include <errno.h>
-
-#define MIN(A,B) ((A) > (B) ? (B) : (A))
-#define MAX(A,B) ((A) < (B) ? (B) : (A))
-#define ABS(A) ((A) < 0 ? -(A) : (A))
-#define INDEX(ROW,COL,NUM_ROWS) ((COL)*(NUM_ROWS)+(ROW))
-
-
-/*======================================================================
-  Main code plus interface to Matlab.
-========================================================================*/
-
-void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
-{
-
-  uint8_t *I, K;
-  uint32_t *P;
-  uint32_t *J;
-  int w,h,x,y,i,j,N;
-  int ww,hh; 
-  uint32_t center;
-  uint32_t offset;
-  uint8_t pattern;
-
-  if( nrhs != 2 )
-    mexErrMsgTxt("Two input arguments required.\n\n"
-                 "LBPPYR computes LBP features on scale-pyramid of input image.\n"
-                 "Synopsis:\n"
-                 "  F = lbppyr(I, P)\n"
-                 "where\n"
-                 "  I [H x W (uint8)] is input image.\n"
-                 "  P [1 x 1 (double)] is height of the scale-pyramid.\n"
-                 "  F [N x 1 (uint8)] LBP features stucked to a column vector. \n");
-
-  I = (uint8_t*)mxGetPr(prhs[0]);
-  K = (uint8_t)mxGetScalar(prhs[1]);
-
-  h = mxGetM(prhs[0]);
-  w = mxGetN(prhs[0]);
-
-  /*  printf("h: %d\n", h);
-  printf("w: %d\n", w);
-  printf("K: %d\n", K);
-  */
-
-  /* count number of LBPs */
-  for(ww=w, hh=h, N=0, i=0; i < K && MIN(ww,hh) >= 3; i++)
-  {
-    N += (ww-2)*(hh-2);
-
-    if(ww % 2) ww--;
-    if(hh % 2) hh--;
-    ww = ww/2;
-    hh = hh/2;
-  }
-  K = i;
-  N = 256*N;
-  
-/*  printf("N: %d (=256*%d)\n", N,N/256);*/
-/*  printf("K: %d\n",K);*/
-  /*  printf("%d/%d = %d*%d + %d \n", b,a, a, b/a, b % a);*/
-  
-  plhs[0] = mxCreateNumericMatrix(N, 1, mxUINT32_CLASS, mxREAL);
-  P = (uint32_t*)mxGetPr(plhs[0]);
-
-  J = mxCalloc(h*w, sizeof(uint32_t));
-  if(J ==NULL)
-    mexErrMsgTxt("Not enough memory.");
-
-  for(x=0; x < w; x++)
-    for(y=0; y < h; y++)
-      J[INDEX(y,x,h)] = I[INDEX(y,x,h)];
-  
-  for(ww=w, hh=h, i=0, offset = 0; i < K; i++)
-  {
-    for(x=1; x < ww-1; x++)
-    {
-      for(y=1; y< hh-1; y++)
-      {
-        pattern = 0;
-        center = J[INDEX(y,x,h)];
-        if(J[INDEX(y-1,x-1,h)] < center) pattern = pattern | 0x01;
-        if(J[INDEX(y-1,x,h)] < center)   pattern = pattern | 0x02;
-        if(J[INDEX(y-1,x+1,h)] < center) pattern = pattern | 0x04;
-        if(J[INDEX(y,x-1,h)] < center)   pattern = pattern | 0x08;
-        if(J[INDEX(y,x+1,h)] < center)   pattern = pattern | 0x10;
-        if(J[INDEX(y+1,x-1,h)] < center) pattern = pattern | 0x20;
-        if(J[INDEX(y+1,x,h)] < center)   pattern = pattern | 0x40;
-        if(J[INDEX(y+1,x+1,h)] < center) pattern = pattern | 0x80;
-
-        /*        P[cnt++] = pattern; */
-        P[offset+pattern] = 1;
-        offset += 256;
-      }
-    }
-
-    if( i < K-1 )
-    {
-      if(ww % 2 == 1) ww--;
-      if(hh % 2 == 1) hh--;
-
-      ww = ww/2;
-      for(x=0; x < ww; x++)
-        for(j=0; j < hh; j++)
-          J[INDEX(j,x,h)] = J[INDEX(j,2*x,h)] + J[INDEX(j,2*x+1,h)];
-
-      hh = hh/2;
-      for(y=0; y < hh; y++)
-        for(j=0; j < ww; j++)
-          J[INDEX(y,j,h)] = J[INDEX(2*y,j,h)] + J[INDEX(2*y+1,j,h)];
-    }
-    
-  }
-  
-  return;
-}
-
diff --git a/libocas.so b/libocas.so
new file mode 100755
index 0000000..41a9953
Binary files /dev/null and b/libocas.so differ
diff --git a/libocas_test.m b/libocas_test.m
index 4e0847e..d2b1aef 100644
--- a/libocas_test.m
+++ b/libocas_test.m
@@ -1,171 +1,287 @@
-% This script tests functionality of SVMOCAS and MSVMOCAS solvers.
+% This script tests functionality of SVM solvers implemneted in the LIBOCAS.
 %
-% It runs the solvers on example data and compares results to solutions
-% stored in reference files. 
-%  
+% The script runs SVM solvers on example data (in ./data/) and compares
+% the obtained results with the solutions stored in reference files. 
+% 
+% This script is useful to check potential bugs e.g. introduced when 
+% changing the library code.
+%
+
+% jump to root dir of libocas
+cd(fileparts(which('svmocas')));
 
 % two-class problem 
-BinaryTrnFile = './data/riply_trn.light';
+TWO_CLASS_PROBLEM = './data/riply_trn.mat';
+
+% two-class problem in SVM^light format
+TWO_CLASS_PROBLEM_SVMLIGHT = './data/riply_trn.light';
 
 % multi-class problem
-MulticlassTrnFile = './data/example4_train.light';
+MULTI_CLASS_PROBLEM = './data/example4_train.mat';
+
+% multi-class problem in SVM^light format
+MULTI_CLASS_PROBLEM_SVMLIGHT = './data/example4_train.light';
+
+% gender classification (male vs. female) from face images 
+GENDER_IMAGE_DATABASE = './data/gender_images.mat';
 
 % file to store/load reference solution
-ReferenceFile = './data/refernce_solution';
+ReferenceFile = './data/reference_solution';
 
 % if 1 save results to reference files else compares the results to the
-% reference solutions
+% reference solutions; 
 CREATE_REFERNCE_FILES = 0;
 
-% Solver options
+%% Solver settings
 opt.C = 1;
 opt.Method = 1;
 opt.TolRel = 0.01;
 opt.TolAbs = 0;
 opt.QPBound = 0;
-opt.BufSize = 2000;
+opt.BufSize = 500;
 opt.MaxTime = inf;
 opt.X0 = 1;
 opt.verb = 0;
 
-fprintf('Training binary SVM classifier by SVMOCAS...');
-[bin.W,bin.W0,bin.stat] = svmocas(BinaryTrnFile,opt.X0,opt.C,opt.Method,opt.TolRel,...
-                             opt.TolAbs,opt.QPBound,opt.BufSize,inf,opt.MaxTime,opt.verb);
+%% run all solvers for different inputs
+
+% SVMOCAS for dense double features
+fprintf('SVMOCAS: training two-class SVM classifier from dense features in double precision ...');
+data = load( TWO_CLASS_PROBLEM );
+[svmocasResults.W,svmocasResults.W0,svmocasResults.stat] = ...
+    svmocas(data.X,opt.X0,data.y, opt.C,opt.Method,opt.TolRel,...
+            opt.TolAbs,opt.QPBound,opt.BufSize,inf,opt.MaxTime,opt.verb);
 fprintf('done.\n');
 
-fprintf('Training multi-class SVM classifier by MSVMOCAS...');
-[multi.W,multi.stat] = msvmocas(MulticlassTrnFile,opt.C,opt.Method,opt.TolRel,...
-                             opt.TolAbs,opt.QPBound,opt.BufSize,inf,opt.MaxTime,opt.verb);
+% SVMOCAS for dense single prec.  features
+fprintf('SVMOCAS: training two-class SVM classifier from dense features in single precision ...');
+data = load( TWO_CLASS_PROBLEM );
+data.X = single(data.X);
+[svmocasSingleResults.W,svmocasSingleResults.W0,svmocasSingleResults.stat] = ...
+    svmocas(data.X,opt.X0,data.y, opt.C,opt.Method,opt.TolRel,...
+            opt.TolAbs,opt.QPBound,opt.BufSize,inf,opt.MaxTime,opt.verb);
 fprintf('done.\n');
 
+% SVMOCAS for sparse double features
+fprintf('SVMOCAS: training two-class SVM classifier from sparse features in double precision ...');
+data = load( TWO_CLASS_PROBLEM );
+data.X = sparse(data.X);
+[svmocasSparseResults.W,svmocasSparseResults.W0,svmocasSparseResults.stat] = ...
+    svmocas(data.X,opt.X0,data.y, opt.C,opt.Method,opt.TolRel,...
+            opt.TolAbs,opt.QPBound,opt.BufSize,inf,opt.MaxTime,opt.verb);
+fprintf('done.\n');
+
+% SVMOCAS for INT8 features
+fprintf('SVMOCAS: training two-class SVM classifier from dense int8 features ...');
+data = load( TWO_CLASS_PROBLEM );
+data.X = int8(100*data.X);
+[svmocasInt8Results.W,svmocasInt8Results.W0,svmocasInt8Results.stat] = ...
+    svmocas(data.X,opt.X0,data.y, opt.C,opt.Method,opt.TolRel,...
+            opt.TolAbs,opt.QPBound,opt.BufSize,inf,opt.MaxTime,opt.verb);
+fprintf('done.\n');
 
-if CREATE_REFERNCE_FILES == 1,    
+% SVMOCAS_LIGHT
+fprintf('SVMOCAS_LIGHT: training two-class SVM classifier from examples stored in SVM^light file ...');
+[svmocasLightResults.W,svmocasLightResults.W0,svmocasLightResults.stat] = ...
+    svmocas_light(TWO_CLASS_PROBLEM_SVMLIGHT,opt.X0, opt.C,opt.Method,opt.TolRel,...
+            opt.TolAbs,opt.QPBound,opt.BufSize,inf,opt.MaxTime,opt.verb);
+fprintf('done.\n');
+
+% SVMOCAS_LBP
+fprintf('SVMOCAS_LBP: training two-class SVM classifier from LBP features computed on images ...');
+data = load( GENDER_IMAGE_DATABASE );
+HEIGHT_OF_LBP_PYRAMID = 4;
+BASE_WINDOW_SIZE = [60 40];    
+numMaleImages = size(data.trn_male_images,2);
+numFemaleImages = size(data.trn_male_images,2);
+wins = [ [1:numMaleImages numMaleImages+[1:numFemaleImages]]; ...
+          repmat([20;15;0],1,numFemaleImages+numMaleImages)];
+labels = [ones(1,numMaleImages) -ones(1,numFemaleImages)];    
+[svmocasLBPResults.W,svmocasLBPResults.W0,svmocasLBPResults.stat] = ...
+    svmocas_lbp([data.trn_male_images data.trn_female_images], data.IMAGE_SIZE,...
+                 uint32(wins), BASE_WINDOW_SIZE, HEIGHT_OF_LBP_PYRAMID, opt.X0, labels, 0.001*opt.C, ...
+                 opt.Method, opt.TolRel,opt.TolAbs,opt.QPBound,opt.BufSize,inf,opt.MaxTime,opt.verb);
+fprintf('done.\n');
+
+% MSVMOCAS
+fprintf('MSVMOCAS: training multi-class SVM classifier from dense features in double precision ...');
+data = load( MULTI_CLASS_PROBLEM );
+[msvmocasResults.W,msvmocasResults.stat] = ...
+    msvmocas(data.X,data.y,opt.C,opt.Method,opt.TolRel,...
+            opt.TolAbs,opt.QPBound,opt.BufSize,inf,opt.MaxTime,opt.verb);
+fprintf('done.\n');
+
+% MSVMOCAS_LIGHT
+fprintf('MSVMOCAS_LIGHT: training multi-class SVM classifier from examples stored in SVM^light file ...');
+[msvmocasLightResults.W,msvmocasLightResults.stat] = ...
+    msvmocas_light(MULTI_CLASS_PROBLEM_SVMLIGHT,opt.C,opt.Method,opt.TolRel,...
+            opt.TolAbs,opt.QPBound,opt.BufSize,inf,opt.MaxTime,opt.verb);
+fprintf('done.\n');
+
+if CREATE_REFERNCE_FILES == 1,       
+    %% save reference solutions to file
     fprintf('Saving reference solutions to %s\n', ReferenceFile);
-    save(ReferenceFile,'bin','multi');    
+    save(ReferenceFile,'svmocasResults','svmocasSparseResults','msvmocasResults',...
+                       'svmocasInt8Results','svmocasLBPResults','svmocasSingleResults', ...
+                       'svmocasLightResults','msvmocasLightResults');
+    
 else
+    %% compare obtained solutions to those stored in the reference file
     ref = load(ReferenceFile);    
-        
-    test(1).dif = sum(abs(bin.W - ref.bin.W)+abs(bin.W0-ref.bin.W0));
+    
+    test = [];
+     
+    % SVMOCAS for dense double features
+    test(1).dif = sum(abs(svmocasResults.W - ref.svmocasResults.W) + ...
+                      abs(svmocasResults.W0-ref.svmocasResults.W0));
     test(1).name = 'sum(|W-ref.W| + |W0-ref.W0])';
-    test(2).dif = abs(bin.stat.Q_P - ref.bin.stat.Q_P);
+    test(2).dif = abs(svmocasResults.stat.Q_P - ref.svmocasResults.stat.Q_P);
     test(2).name = 'PrimalVal - ref.PrimalVal   ';
-    test(3).dif = abs(bin.stat.Q_D - ref.bin.stat.Q_D);
+    test(3).dif = abs(svmocasResults.stat.Q_D - ref.svmocasResults.stat.Q_D);
     test(3).name = 'DualVal - ref.DualVal       ';
     
-    fprintf('\nSVMOCAS (solver for binary classifiation problems):\n');
+    fprintf('\nSVMOCAS for dense features in double precision:\n');
     for i=1:length(test)
         fprintf('   %s = %.20f ... ',test(i).name,test(i).dif);
         if test(i).dif == 0
             fprintf('SOLUTIONS EQUAL - OK\n');
         else
-            fprintf('SOLUTION DIFFERS\n');
+            fprintf('SOLUTION IS DIFFERENT!!!\n');
+        end
+    end
+    
+    % SVMOCAS for dense single precision features
+    test(1).dif = sum(abs(svmocasSingleResults.W - ref.svmocasSingleResults.W) + ...
+                      abs(svmocasSingleResults.W0-ref.svmocasSingleResults.W0));
+    test(1).name = 'sum(|W-ref.W| + |W0-ref.W0])';
+    test(2).dif = abs(svmocasSingleResults.stat.Q_P - ref.svmocasSingleResults.stat.Q_P);
+    test(2).name = 'PrimalVal - ref.PrimalVal   ';
+    test(3).dif = abs(svmocasSingleResults.stat.Q_D - ref.svmocasSingleResults.stat.Q_D);
+    test(3).name = 'DualVal - ref.DualVal       ';
+    
+    fprintf('\nSVMOCAS for dense features in single precision:\n');
+    for i=1:length(test)
+        fprintf('   %s = %.20f ... ',test(i).name,test(i).dif);
+        if test(i).dif == 0
+            fprintf('SOLUTIONS EQUAL - OK\n');
+        else
+            fprintf('SOLUTION IS DIFFERENT!!!\n');
+        end
+    end
+    
+    % SVMOCAS for sparse double features
+    test(1).dif = sum(abs(svmocasSparseResults.W - ref.svmocasSparseResults.W) + ...
+                      abs(svmocasSparseResults.W0-ref.svmocasSparseResults.W0));
+    test(1).name = 'sum(|W-ref.W| + |W0-ref.W0])';
+    test(2).dif = abs(svmocasSparseResults.stat.Q_P - ref.svmocasSparseResults.stat.Q_P);
+    test(2).name = 'PrimalVal - ref.PrimalVal   ';
+    test(3).dif = abs(svmocasSparseResults.stat.Q_D - ref.svmocasSparseResults.stat.Q_D);
+    test(3).name = 'DualVal - ref.DualVal       ';
+    
+    fprintf('\nSVMOCAS for sparse features in double precision:\n');
+    for i=1:length(test)
+        fprintf('   %s = %.20f ... ',test(i).name,test(i).dif);
+        if test(i).dif == 0
+            fprintf('SOLUTIONS EQUAL - OK\n');
+        else
+            fprintf('SOLUTION IS DIFFERENT!!!\n');
+        end
+    end
+    
+    % SVMOCAS for dense INT8 features
+    test(1).dif = sum(abs(svmocasInt8Results.W - ref.svmocasInt8Results.W) + ...
+                      abs(svmocasInt8Results.W0-ref.svmocasInt8Results.W0));
+    test(1).name = 'sum(|W-ref.W| + |W0-ref.W0])';
+    test(2).dif = abs(svmocasInt8Results.stat.Q_P - ref.svmocasInt8Results.stat.Q_P);
+    test(2).name = 'PrimalVal - ref.PrimalVal   ';
+    test(3).dif = abs(svmocasInt8Results.stat.Q_D - ref.svmocasInt8Results.stat.Q_D);
+    test(3).name = 'DualVal - ref.DualVal       ';
+    
+    fprintf('\nSVMOCAS for dense int8 features:\n');
+    for i=1:length(test)
+        fprintf('   %s = %.20f ... ',test(i).name,test(i).dif);
+        if test(i).dif == 0
+            fprintf('SOLUTIONS EQUAL - OK\n');
+        else
+            fprintf('SOLUTION IS DIFFERENT!!!\n');
+        end
+    end
+    
+    % SVMOCAS_LIGHT
+    test(1).dif = sum(abs(svmocasLightResults.W - ref.svmocasLightResults.W) + ...
+                      abs(svmocasLightResults.W0-ref.svmocasLightResults.W0));
+    test(1).name = 'sum(|W-ref.W| + |W0-ref.W0])';
+    test(2).dif = abs(svmocasLightResults.stat.Q_P - ref.svmocasLightResults.stat.Q_P);
+    test(2).name = 'PrimalVal - ref.PrimalVal   ';
+    test(3).dif = abs(svmocasLightResults.stat.Q_D - ref.svmocasLightResults.stat.Q_D);
+    test(3).name = 'DualVal - ref.DualVal       ';
+    
+    fprintf('\nSVMOCAS_LIGHT:\n');
+    for i=1:length(test)
+        fprintf('   %s = %.20f ... ',test(i).name,test(i).dif);
+        if test(i).dif == 0
+            fprintf('SOLUTIONS EQUAL - OK\n');
+        else
+            fprintf('SOLUTION IS DIFFERENT!!!\n');
         end
     end        
-
-    test(1).dif = sum(sum(abs(multi.W - ref.multi.W)));
+    
+    % SVMOCAS_LBP
+    test(1).dif = sum(abs(svmocasLBPResults.W - ref.svmocasLBPResults.W) + ...
+                      abs(svmocasLBPResults.W0-ref.svmocasLBPResults.W0));
+    test(1).name = 'sum(|W-ref.W| + |W0-ref.W0])';
+    test(2).dif = abs(svmocasLBPResults.stat.Q_P - ref.svmocasLBPResults.stat.Q_P);
+    test(2).name = 'PrimalVal - ref.PrimalVal   ';
+    test(3).dif = abs(svmocasLBPResults.stat.Q_D - ref.svmocasLBPResults.stat.Q_D);
+    test(3).name = 'DualVal - ref.DualVal       ';
+    
+    fprintf('\nSVMOCAS_LBP:\n');
+    for i=1:length(test)
+        fprintf('   %s = %.20f ... ',test(i).name,test(i).dif);
+        if test(i).dif == 0
+            fprintf('SOLUTIONS EQUAL - OK\n');
+        else
+            fprintf('SOLUTION IS DIFFERENT!!!\n');
+        end
+    end
+    
+    % MSVMOCAS
+    test(1).dif = sum(sum(abs(msvmocasResults.W - ref.msvmocasResults.W)));
     test(1).name = 'sum(|W-ref.W|)           ';
-    test(2).dif = abs(multi.stat.Q_P - ref.multi.stat.Q_P);
+    test(2).dif = abs(msvmocasResults.stat.Q_P - ref.msvmocasResults.stat.Q_P);
     test(2).name = 'PrimalVal - ref.PrimalVal';
-    test(3).dif = abs(multi.stat.Q_D - ref.multi.stat.Q_D);
+    test(3).dif = abs(msvmocasResults.stat.Q_D - ref.msvmocasResults.stat.Q_D);
     test(3).name = 'DualVal - ref.DualVal    ';
     
-    fprintf('\nMSVMOCAS: (solver for multi-class problems\n');
+    fprintf('\nMSVMOCAS:\n');
     for i=1:length(test)
         fprintf('   %s = %.20f ... ',test(i).name, test(i).dif);
         if test(i).dif == 0
             fprintf('SOLUTIONS EQUAL - OK\n');
         else
-            fprintf('SOLUTION DIFFERS\n');
+            fprintf('SOLUTION IS DIFFERENT!!!\n');
         end
-    end        
+    end
     
+    % MSVMOCAS_LIGHT
+    test(1).dif = sum(sum(abs(msvmocasLightResults.W - ref.msvmocasLightResults.W)));
+    test(1).name = 'sum(|W-ref.W|)           ';
+    test(2).dif = abs(msvmocasLightResults.stat.Q_P - ref.msvmocasLightResults.stat.Q_P);
+    test(2).name = 'PrimalVal - ref.PrimalVal';
+    test(3).dif = abs(msvmocasLightResults.stat.Q_D - ref.msvmocasLightResults.stat.Q_D);
+    test(3).name = 'DualVal - ref.DualVal    ';
     
+    fprintf('\nMSVMOCAS_LIGHT:\n');
+    for i=1:length(test)
+        fprintf('   %s = %.20f ... ',test(i).name, test(i).dif);
+        if test(i).dif == 0
+            fprintf('SOLUTIONS EQUAL - OK\n');
+        else
+            fprintf('SOLUTION IS DIFFERENT!!!\n');
+        end
+    end               
 end
 
+% EOF
 
-break;
 
-for i=1:length(DataSets)  
-   fprintf('\nDataset: %s\n', DataSets{i});
-   
-   [exp{i}.W,exp{i}.W0,exp{i}.stat] = svmocas(DataSets{i},opt.X0,opt.C,opt.Method,...
-                opt.TolRel,opt.TolAbs,opt.QPBound,opt.BufSize,inf,opt.MaxTime);  
-end
-
-fprintf('\n\nRESULTS SUMMARY\n================================\n\n');
-for i=1:length(DataSets)
-   fprintf('\nDataset: %s\n--------------------------------\n', DataSets{i});
-   
-   % remove suffix
-   sol_fname = DataSets{i};
-   idx = findstr(sol_fname,'.');
-   sol_fname = sol_fname(1:idx(end)-1);
-         
-   sol_fname = [sol_fname '_ocas_C' num2str(opt.C) '_solution.mat'];
-   if SAVE_AS_REFERENCE,
-      if exist(sol_fname)
-         fprintf('Solution file %s already exists.\n', sol_fname);
-         error('Erase the file or set SAVE_AS_REFERENCE = 0 and run the test again.');
-      else
-          fprintf('Saving solution to %s ...', sol_fname);
-          ref_sol = exp{i};
-          ref_opt = opt;
-          save(sol_fname,'ref_sol','ref_opt');
-          fprintf('done.\n');      
-          ref_sol = [];
-      end
-   else
-      if exist(sol_fname)
-          load(sol_fname,'ref_sol','ref_opt');          
-
-          fprintf('\nReference solution\n');
-          fprintf('file: %s\n', sol_fname);
-          fprintf(['settings: C: %f, Method: %d, TolRel: %f, TolAbs: %f, ' ...
-                   'QPBound: %f, BufSize: %d, MaxTime: %f, X0: %f \n'], ...
-                  ref_opt.C, ref_opt.Method, ref_opt.TolRel, ref_opt.TolAbs, ...
-                  ref_opt.QPBound, ref_opt.BufSize, ref_opt.MaxTime, ref_opt.X0);
-          fprintf(['solution: QP: %.10f, QD: %.10f, nIter: %d, nCutPlanes: %d, '...
-                'exitflag: %d, ocas_time: %f, total_time: %f\n'],...
-                  ref_sol.stat.Q_P, ref_sol.stat.Q_D, ref_sol.stat.nIter, ref_sol.stat.nCutPlanes, ...
-                  ref_sol.stat.exitflag, ref_sol.stat.ocas_time, ref_sol.stat.total_time);
-      end       
-   end
-   
-   fprintf('\nCurrent solution \n');
-   fprintf(['settings: C: %f, Method: %d, TolRel: %f, TolAbs: %f, ' ...
-                   'QPBound: %f, BufSize: %d, MaxTime: %f, X0: %f \n'], ...
-                  opt.C, opt.Method, opt.TolRel, opt.TolAbs, ...
-                  opt.QPBound, opt.BufSize, opt.MaxTime, opt.X0);
-   fprintf(['solution: QP: %.10f, QD: %.10f, nIter: %d, nCutPlanes: %d, '...
-            'exitflag: %d, ocas_time: %f, total_time: %f\n'],...
-           exp{i}.stat.Q_P, exp{i}.stat.Q_D, exp{i}.stat.nIter, exp{i}.stat.nCutPlanes, ...
-           exp{i}.stat.exitflag, exp{i}.stat.ocas_time, exp{i}.stat.total_time);
-   
-   if ~isempty(ref_sol)
-       opt_dif = any([opt.Method~=ref_opt.Method opt.C~=ref_opt.C opt.TolRel ~= ref_opt.TolRel ...
-                      opt.TolAbs~=ref_opt.TolAbs opt.QPBound~=ref_opt.QPBound ...
-                      opt.BufSize~=ref_opt.BufSize opt.MaxTime~=ref_opt.MaxTime opt.X0~=ref_opt.X0]);
-       sol_dif = max(max(abs(exp{i}.W-ref_sol.W)),abs(exp{i}.W0-ref_sol.W0));
-       fprintf('\nSolution difference: max(abs(ref.W-W)) = %f. Solutions are ', sol_dif); 
-       if ~sol_dif 
-           fprintf('EQUAL.\n'); 
-       else
-           fprintf('DIFFERENT.\n');
-       end
-       fprintf('Current and refrence settings are ');
-       if ~opt_dif 
-           fprintf('EQUAL.\n'); 
-       else
-           fprintf('DIFFERENT.\n');
-       end
-       fprintf('Comparison result: ');
-       if sol_dif && ~opt_dif ,
-           fprintf('THIS IS NOT GOOD ... BUT DON''T PANIC.\n');
-       elseif ~sol_dif && ~opt_dif
-           fprintf('OK.\n');
-       elseif opt_dif
-           fprintf('UNDECIDED since options are different.\n');
-       end
-       
-   end
-end
diff --git a/linclassif b/linclassif
new file mode 100755
index 0000000..b5c20eb
Binary files /dev/null and b/linclassif differ
diff --git a/linclass.c b/linclassif.c
similarity index 96%
rename from linclass.c
rename to linclassif.c
index 7cb99d5..b62211d 100644
--- a/linclass.c
+++ b/linclassif.c
@@ -1,9 +1,9 @@
 /*-----------------------------------------------------------------------
- * linclass.c: Implementation of linear classification rule classifying 
+ * linclassif.c: Implementation of linear classification rule classifying 
  *  examples from the SVM^light format.
  *   
- * Copyright (C) 2008, 2009 Vojtech Franc, xfrancv at cmp.felk.cvut.cz
- *                    Soeren Sonnenburg, soeren.sonnenburg at first.fraunhofer.de
+ * Copyright (C) 2008-2012 Vojtech Franc, xfrancv at cmp.felk.cvut.cz
+ *              Soeren Sonnenburg, soeren.sonnenburg at first.fraunhofer.de
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public 
@@ -26,7 +26,7 @@
 
 void print_usage(void)
 {
-  printf("LINCLASS: Predict labels by linear classication rule\n" 
+  printf("LINCLASSIF: Predict labels by linear classication rule\n" 
          "          " OCAS_VERSION "\n"
          "\n"
          "   usage: linclass [options] example_file model_file\n"
@@ -48,11 +48,11 @@ void print_usage(void)
          "Examples\n"
          "  Train SVM classifier from riply_trn.light with regularization constant C = 10,\n"
          "  bias switched on, verbosity switched off and model saved to svmocas.model\n"
-         "    ./svmocas -c 10 -b 1 -v 0 riply_trn.light svmocas.model \n"
+         "    ./svmocas -c 10 -b 1 -v 0 ./data/riply_trn.light ./data/svmocas.model \n"
          "\n"
          "  Compute testing error of the classifier stored in svmocas.model using testing\n"
          "  examples from riply_tst.light and save predicted labels to riply_tst.pred\n"
-         "    ./linclass -e -o riply_tst.pred riply_tst.light svmocas.model\n"
+         "    ./linclassif -e -o ./data/riply_tst.pred ./data/riply_tst.light ./data/svmocas.model\n"
          "\n"
          );
 }
diff --git a/svmlight_linclass.m b/linclassif_light.m
similarity index 53%
rename from svmlight_linclass.m
rename to linclassif_light.m
index 1b8f84c..ff7e601 100644
--- a/svmlight_linclass.m
+++ b/linclassif_light.m
@@ -1,17 +1,20 @@
 % SVMLIGHT_LINCLASS classifies examples in SVM^light file by linear rule.
 %
 % Synopsis:
-%  [score,true_lab] = svmlight_linclass(data_file,W,[])
-%  [score,true_lab] = svmlight_linclass(data_file,W,W0)
-%  [score,true_lab] = svmlight_linclass(data_file,W,W0,verb)
+%  [score,trueLabels] = linclassif_light(dataFile,W,[])
+%  [score,trueLabels] = linclassif_light(dataFile,W,W0)
+%  [score,trueLabels] = linclassif_light(dataFile,W,W0,verb)
 % 
 % Input:
-%  data_file [string] Path to file with examples stored in SVM^light format.
+%  dataFile [string] File with examples stored in the SVM^light format.
 %  W [nDims x nModels] Parameter vectors of nModels linear classifiers.
 %  W0 [nModels x 1] Bias of decision rule. If W0 is empty then W0 = 0 is used.
 %  verb [1x1] If ~= 0 then prints info (default 0).
 %
 % Output:
 %  score [nModels x nExamples] score(i,j) = W(:,i)'*X_j + W0(i)
-%  true_labels [nExamples x 1] labels from the data_file
+%  trueLabels [nExamples x 1] labels from the dataFile
+%
+% Example:
+%  help svmocas_light
 %
diff --git a/linclassif_light.mexa64 b/linclassif_light.mexa64
new file mode 100755
index 0000000..a13e38f
Binary files /dev/null and b/linclassif_light.mexa64 differ
diff --git a/svmlight_linclass_mex.c b/linclassif_light_mex.c
similarity index 74%
rename from svmlight_linclass_mex.c
rename to linclassif_light_mex.c
index cfedb55..1378f40 100644
--- a/svmlight_linclass_mex.c
+++ b/linclassif_light_mex.c
@@ -1,23 +1,22 @@
-/*=================================================================
- * SVMLIGHT_LINCLASS classifies examples in SVM^light file by linear rule.
- *
- *  Synopsis:
- *    [score,true_lab] = svmlight_linclass(data_file,W,[])
- *    [score,true_lab] = svmlight_linclass(data_file,W,W0)
- *    [score,true_lab] = svmlight_linclass(data_file,W,W0,verb)
- *
- * 
- *  Input:
- *   data_file [string] Path to file with examples stored in SVM^light format.
- *   W [nDims x nModels] Parameter vectors of nModels linear classifiers.
- *   W0 [nModels x 1] Bias of decision rule. If W0 is empty then W0 = 0 is used. 
- *   verb [1x1] If ~= 0 then prints info (default 0).
- *
- *  Output:
- *   score [nModels x nExamples] score(i,j) = W(:,i)'*X_j + W0(i)
- *   true_labels [nExamples x 1] labels from the data_file
- *
- *=================================================================*/
+/*==============================================================================
+*  SVMLIGHT_LINCLASS classifies examples in SVM^light file by linear rule.      *
+*                                                                               *
+* Synopsis:                                                                     *
+*   [score,trueLabels] = svmlight_linclass(dataFile,W,[])                       *
+*   [score,trueLabels] = svmlight_linclass(dataFile,W,W0)                       *
+*   [score,trueLabels] = svmlight_linclass(dataFile,W,W0,verb)                  *
+*                                                                               *
+* Input:                                                                        *
+*   dataFile [string] Path to file with examples stored in SVM^light format.    *
+*   W [nDims x nModels] Parameter vectors of nModels linear classifiers.        *
+*   W0 [nModels x 1] Bias of decision rule. If W0 is empty then W0 = 0 is used. *
+*   verb [1x1] If ~= 0 then prints info (default 0).                            *
+*                                                                               *
+* Output:                                                                       *
+*   score [nModels x nExamples] score(i,j) = W(:,i)'*X_j + W0(i)                *
+*   trueLabels [nExamples x 1] labels from the dataFile                         *
+*                                                                               *
+*===============================================================================*/
 
 #define _FILE_OFFSET_BITS  64
 
@@ -131,11 +130,22 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
   int verb = 0;
   double *auc;
 
-  if( nrhs < 3 )
-    mexErrMsgTxt("At least three input arguments must be passed.");
-
-  if( nrhs > 4)
-    mexErrMsgTxt("At most four input arguments must be passed.");
+  if( nrhs <3 || nrhs > 4)
+    mexErrMsgTxt("SVMLIGHT_LINCLASS classifies examples in SVM^light file by linear rule.\n"
+		 "\n"
+		 "  [score,trueLabels] = svmlight_linclass(dataFile,W,[])\n"
+		 "  [score,trueLabels] = svmlight_linclass(dataFile,W,W0)\n"
+		 "  [score,trueLabels] = svmlight_linclass(dataFile,W,W0,verb)\n"
+		 "\n" 
+		 "Input:\n"
+		 "  dataFile [string] Path to file with examples stored in SVM^light format.\n"
+		 "  W [nDims x nModels] Parameter vectors of nModels linear classifiers.\n"
+		 "  W0 [nModels x 1] Bias of decision rule. If W0 is empty then W0 = 0 is used.\n"
+		 "  verb [1x1] If ~= 0 then prints info (default 0).\n"
+		 "\n"
+		 "Output:\n"
+		 "  score [nModels x nExamples] score(i,j) = W(:,i)'*X_j + W0(i)\n"
+		 "  trueLabels [nExamples x 1] labels from the dataFile\n");
 
   if( nrhs == 4)
     verb = (int)mxGetScalar(prhs[3]);
@@ -258,7 +268,7 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
     mexErrMsgTxt("Not enought memory to allocate buffer for score.");
   score = (double*)mxGetPr(plhs[0]);
 
-  plhs[1] = (mxArray*)mxCreateDoubleMatrix(line_cnt,1,mxREAL);
+  plhs[1] = (mxArray*)mxCreateDoubleMatrix(1,line_cnt,mxREAL);
   if(plhs[1] == NULL)
     mexErrMsgTxt("Not enought memory to allocate buffer for true_labels.");
   true_lab = (double*)mxGetPr(plhs[1]);
diff --git a/msvmocas b/msvmocas
new file mode 100755
index 0000000..0d7e283
Binary files /dev/null and b/msvmocas differ
diff --git a/msvmocas.c b/msvmocas.c
index 59c1d4a..f8067f5 100644
--- a/msvmocas.c
+++ b/msvmocas.c
@@ -21,6 +21,7 @@
 #include "libocas.h"
 #include "sparse_mat.h"
 #include "ocas_helper.h"
+#include "features_double.h"
 
 #include "version.h"
 
@@ -62,7 +63,7 @@ void print_usage(void)
          "\n"  
          "  Compute testing error of the classifier stored in ./data/msvmocas.model using testing\n"
          "  examples from ./data/example4_test.light and save predicted labels to ./data/example4_test.pred\n"
-         "    ./linclass -e -o ./data/exaple4_test.pred ./data/example4_test.light ./data/msvmocas.model\n"
+         "    ./linclassif -e -o ./data/exaple4_test.pred ./data/example4_test.light ./data/msvmocas.model\n"
          "\n"
          );
 }
@@ -412,13 +413,13 @@ int main(int argc, char *argv[])
       printf("Starting optimization:\n");
 
       ocas = msvm_ocas_solver( C, data_y, nY, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
-                               &msvm_sparse_compute_W, &msvm_full_update_W, &msvm_sparse_add_new_cut,
+                               &msvm_sparse_compute_W, &msvm_update_W, &msvm_sparse_add_new_cut,
                                &msvm_sparse_compute_output, &qsort_data, &ocas_print, 0);
     }
     else
     {
       ocas = msvm_ocas_solver( C, data_y, nY, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
-                               &msvm_sparse_compute_W, &msvm_full_update_W, &msvm_sparse_add_new_cut,
+                               &msvm_sparse_compute_W, &msvm_update_W, &msvm_sparse_add_new_cut,
                                &msvm_sparse_compute_output, &qsort_data, &ocas_print_null, 0);
     }
   }
@@ -437,13 +438,13 @@ int main(int argc, char *argv[])
       printf("Starting optimization:\n");
     
       ocas = msvm_ocas_solver( C, data_y, nY, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
-                               &msvm_full_compute_W, &msvm_full_update_W, &msvm_full_add_new_cut,
+                               &msvm_full_compute_W, &msvm_update_W, &msvm_full_add_new_cut,
                                &msvm_full_compute_output, &qsort_data, &ocas_print, 0); 
     }
     else
     {
       ocas = msvm_ocas_solver( C, data_y, nY, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
-                               &msvm_full_compute_W, &msvm_full_update_W, &msvm_full_add_new_cut,
+                               &msvm_full_compute_W, &msvm_update_W, &msvm_full_add_new_cut,
                                &msvm_full_compute_output, &qsort_data, &ocas_print_null, 0); 
 
     }
diff --git a/msvmocas.m b/msvmocas.m
index 6a48dd0..a2a5b4f 100644
--- a/msvmocas.m
+++ b/msvmocas.m
@@ -1,8 +1,7 @@
-% MSVMOCAS Train multi-class linear SVM classifier using OCAS solver.
+% MSVMOCAS OCAS solver for training multi-class linear SVM classifiers.
 %
 % Synopsis:
 %  [W,stat] = msvmocas(X,y,C,Method,TolRel,TolAbs,QPBound,BufSize,nExamples,MaxTime,verb)
-%  [W,stat] = msvmocas(svmlight_data_file,C,Method,TolRel,TolAbs,QPBound,BufSize,nExamples,MaxTime,verb)
 %
 % Desription:
 %  This function trains multi-class linear SVM classifier by solving
@@ -10,16 +9,16 @@
 %      W^* = argmin 0.5*sum_y (W(:,y)'*W(:,y)) + C*  sum     max( (y~=y(i)) + (W(:,y) - W(:,y(i))'*X(:,i))
 %              W                                   i=1:nData   y
 %
-%  The function accepts examples either in Matlab matrix X (both sparse and dense) and 
-%  a dense vector y or as path to a file in SVM^light format.
+%  The function accepts examples either in Matlab matrix X both sparse and
+%  dense matrix.
 %
 % Reference:
-%  V. Franc, S. Sonnenburg. To be published. 2009
+%  V. Franc, S. Sonnenburg. Optimized Cutting Plane Algorithm for Large-scale Risk
+%  Minimization. Journal of Machine Learning Research. 2009
+%    http://jmlr.csail.mit.edu/papers/volume10/franc09a/franc09a.pdf
 %
 % Input:
-%   data_file [string] Training examples stored in SVM^light format.
-%
-%   X [nDim x nExamples] training inputs (sparse or dense matrix).
+%   X [nDim x nExamples] training inputs (sparse or dense matrix of doubles).
 %   y [nExamples x 1] labels; intgers 1,2,...nY
 %   C [1x1] regularization constant
 %   Method [1x1] 0..cutting plane; 1..OCAS  (default 1)
@@ -38,19 +37,16 @@
 %   stat [struct] Optimizer statistics (field names are self-explaining).
 %
 % Example:
-%  C = 1; 
-%
-%  % case 1: loading data directly from file in SVM^light format
-%  [W,stat] = msvmocas('example4_train.light',C);
-%
-%  % case 2: using data loaded in Matlab
-%  load('example4_train','X','y');
-%  [W,stat] = msvmocas(X,y,C);
-%
-%  % classification
-%  load('example4_test.mat','X','y');
-%  [dummy,ypred] = max(W'*X);
-%  sum(ypred(:) ~= y(:))/length(y)
+%  % training
+%  libocasPath = fileparts(which('svmocas'));
+%  trn = load([libocasPath '/data/example4_train.mat'],'X','y'); 
+%  svmC = 1; 
+%  [W,stat] = msvmocas(trn.X,trn.y,svmC);
+%
+%  % classifying test examples
+%  tst = load([libocasPath '/data/example4_test.mat'],'X','y'); 
+%  [dummy,ypred] = max(W'*tst.X);
+%  sum(ypred(:) ~= tst.y(:))/length(tst.y)
 % 
 
 %
diff --git a/msvmocas.mexa64 b/msvmocas.mexa64
new file mode 100755
index 0000000..f905495
Binary files /dev/null and b/msvmocas.mexa64 differ
diff --git a/msvmocas.m b/msvmocas_light.m
similarity index 62%
copy from msvmocas.m
copy to msvmocas_light.m
index 6a48dd0..f81219c 100644
--- a/msvmocas.m
+++ b/msvmocas_light.m
@@ -1,8 +1,8 @@
-% MSVMOCAS Train multi-class linear SVM classifier using OCAS solver.
+% MSVMOCAS_LIGHT OCAS solver for training multi-class linear SVM classifier from SVM^light file.
+% 
 %
 % Synopsis:
-%  [W,stat] = msvmocas(X,y,C,Method,TolRel,TolAbs,QPBound,BufSize,nExamples,MaxTime,verb)
-%  [W,stat] = msvmocas(svmlight_data_file,C,Method,TolRel,TolAbs,QPBound,BufSize,nExamples,MaxTime,verb)
+%  [W,stat] = msvmocas_light(dataFile,C,Method,TolRel,TolAbs,QPBound,BufSize,nExamples,MaxTime,verb)
 %
 % Desription:
 %  This function trains multi-class linear SVM classifier by solving
@@ -10,16 +10,15 @@
 %      W^* = argmin 0.5*sum_y (W(:,y)'*W(:,y)) + C*  sum     max( (y~=y(i)) + (W(:,y) - W(:,y(i))'*X(:,i))
 %              W                                   i=1:nData   y
 %
-%  The function accepts examples either in Matlab matrix X (both sparse and dense) and 
-%  a dense vector y or as path to a file in SVM^light format.
+%  The function loads examples from dataFile in SVM^light format.
 %
 % Reference:
-%  V. Franc, S. Sonnenburg. To be published. 2009
+%  V. Franc, S. Sonnenburg. Optimized Cutting Plane Algorithm for Large-scale Risk
+%  Minimization. Journal of Machine Learning Research. 2009
+%    http://jmlr.csail.mit.edu/papers/volume10/franc09a/franc09a.pdf
 %
 % Input:
-%   data_file [string] Training examples stored in SVM^light format.
-%
-%   X [nDim x nExamples] training inputs (sparse or dense matrix).
+%   dataFile [string] path to file with training examples in SVM^light format.
 %   y [nExamples x 1] labels; intgers 1,2,...nY
 %   C [1x1] regularization constant
 %   Method [1x1] 0..cutting plane; 1..OCAS  (default 1)
@@ -38,19 +37,15 @@
 %   stat [struct] Optimizer statistics (field names are self-explaining).
 %
 % Example:
-%  C = 1; 
-%
-%  % case 1: loading data directly from file in SVM^light format
-%  [W,stat] = msvmocas('example4_train.light',C);
-%
-%  % case 2: using data loaded in Matlab
-%  load('example4_train','X','y');
-%  [W,stat] = msvmocas(X,y,C);
-%
-%  % classification
-%  load('example4_test.mat','X','y');
-%  [dummy,ypred] = max(W'*X);
-%  sum(ypred(:) ~= y(:))/length(y)
+%  % training
+%  libocasPath = fileparts(which('svmocas'));
+%  svmC = 1; 
+%  [W,stat] = msvmocas_light([libocasPath '/data/example4_train.light'],svmC);
+%
+%  % classifying test examples
+%  [score,trueLabels] = linclassif_light([libocasPath '/data/example4_test.light'],W,[]);
+%  [dummy,ypred] = max(score);
+%  sum(ypred~=trueLabels)/length(trueLabels)
 % 
 
 %
diff --git a/msvmocas_light.mexa64 b/msvmocas_light.mexa64
new file mode 100755
index 0000000..f7a1d4b
Binary files /dev/null and b/msvmocas_light.mexa64 differ
diff --git a/msvmocas_test.m b/msvmocas_light_example.m
similarity index 72%
rename from msvmocas_test.m
rename to msvmocas_light_example.m
index 55d8e5c..4bda560 100644
--- a/msvmocas_test.m
+++ b/msvmocas_light_example.m
@@ -1,5 +1,5 @@
-trn_file = 'example4_train.light';
-tst_file = 'example4_test.light';
+trn_file = './data/example4_train.light';
+tst_file = './data/example4_test.light';
 
 C = 1;
 TolRel = 0.01;
@@ -10,13 +10,13 @@ nData = inf;
 MaxTime = inf;
 verb = 0;
 
-Method = 0; % Cutting Plane Algorithm
+Method = 0; % standard BMRM alias Cutting Plane Algorithm
 fprintf('Training SVM by Cutting Plane Algorithm...');
-[cp_W,cp_stat] = msvmocas(trn_file,C,Method,TolRel,TolAbs,QPBound,BufSize,nData,MaxTime,verb);
+[cp_W,cp_stat] = msvmocas_light(trn_file,C,Method,TolRel,TolAbs,QPBound,BufSize,nData,MaxTime,verb);
 fprintf('done\n');
 
 fprintf('Evaluating classifier on testing data...');
-[score,true_labels] = svmlight_linclass(tst_file,cp_W,[]);
+[score,true_labels] = linclassif_light(tst_file,cp_W,[]);
 [dummy,pred_labels] = max(score);
 cp_tst_err = sum(pred_labels(:) ~= true_labels(:))/length(true_labels);
 fprintf('done\n');
@@ -31,11 +31,11 @@ fprintf('Testing error: %f %%\n',cp_tst_err*100);
 
 Method = 1; % OCAS 
 fprintf('\nTraining SVM by OCAS...');
-[ocas_W,ocas_stat] = msvmocas(trn_file,C,Method,TolRel,TolAbs,QPBound,BufSize,nData,MaxTime,verb);
+[ocas_W,ocas_stat] = msvmocas_light(trn_file,C,Method,TolRel,TolAbs,QPBound,BufSize,nData,MaxTime,verb);
 fprintf('done\n');
 
 fprintf('Evaluating classifier on testing data...');
-[score,true_labels] = svmlight_linclass(tst_file,ocas_W,[]);
+[score,true_labels] = linclassif_light(tst_file,ocas_W,[]);
 [dummy,pred_labels] = max(score);
 ocas_tst_err = sum(pred_labels(:) ~= true_labels(:))/length(true_labels);
 fprintf('done\n');
diff --git a/msvmocas_mex.c b/msvmocas_light_mex.c
similarity index 53%
copy from msvmocas_mex.c
copy to msvmocas_light_mex.c
index 330972e..43b4373 100644
--- a/msvmocas_mex.c
+++ b/msvmocas_light_mex.c
@@ -1,12 +1,30 @@
 /*=================================================================================
- * svmocas_mex.c: Matlab MEX interface for OCAS solver training the linear SVM classifiers.
+ * msvmocas_light_mex.c: OCAS solver for training multi-class linear SVM classifiers
+ *                       loading examples from SVM^light file.
  * 
  * Synopsis:
- *  [W,stat] = msvmocas(X,y,C,Method,TolRel,TolAbs,QPBound,BufSize,nData,MaxTime,verb)
- *  [W,stat] = msvmocas(svmlight_data_file,C,Method,TolRel,TolAbs,QPBound,BufSize,nData,MaxTime,verb)
+ *   [W,stat] = msvmocas_light(dataFile,C,Method,TolRel,TolAbs,QPBound,BufSize,nExamples,MaxTime,verb)
+ * 
+ * Input:
+ *  dataFile [string] path to file with training examples in SVM^light format
+ *  X [nDim x nExamples] training feature inputs (sparse or dense matrix of doubles).
+ *  y [nExamples x 1] labels; intgers 1,2,...nY
+ *  C [1x1] regularization constant
+ *  Method [1x1] 0..cutting plane; 1..OCAS  (default 1)
+ *  TolRel [1x1] halts if Q_P-Q_D <= abs(Q_P)*TolRel  (default 0.01)
+ *  TolAbs [1x1] halts if Q_P-Q_D <= TolAbs  (default 0)
+ *  QPValue [1x1] halts if Q_P <= QPBpound  (default 0)
+ *  BufSize [1x1] Initial size of active constrains buffer (default 2000)
+ *  nExamples [1x1] Number of training examplesused for training; must be >0 and <= size(X,2).
+ *     If nExamples = inf then nExamples is set to size(X,2).
+ *  MaxTime [1x1] halts if time used by solver (data loading time is not counted) exceeds
+ *    MaxTime given in seconds. Use MaxTime=inf (default) to switch off this stopping condition. 
+ *  verb [1x1] if non-zero then prints some info; (default 1)
  *
- * Synopsis:
- *  [W,stat] = msvmocas(X,y,C,Method,TolRel,TolAbs,QPBound,BufSize,nData,MaxTime)
+ * Output:
+ *  W [nDim x nY] Paramater vectors of decision rule; [dummy,ypred] = max(W'*x)
+ *  stat [struct] Optimizer statistics (field names are self-explaining).
+ * 
  * Copyright (C) 2008 Vojtech Franc, xfrancv at cmp.felk.cvut.cz
  *
  * This program is free software; you can redistribute it and/or
@@ -23,6 +41,7 @@
 
 #include "libocas.h"
 #include "ocas_helper.h"
+#include "features_double.h"
 
 #define DEFAULT_METHOD 1
 #define DEFAULT_TOLREL 0.01
@@ -54,152 +73,101 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
   total_time = get_time();
   init_time = total_time;
 
-  if(nrhs < 1)
-    mexErrMsgTxt("Improper number of input arguments.");
-
-  /* get input arguments */ 
-  if(mxIsChar(prhs[0]) == false) 
-  {
-
-    if(nrhs < 3 || nrhs > 11)
-      mexErrMsgTxt("Improper number of input arguments.");
-
-    /*  [W,stat] = msvmocas(X,y,C,Method,TolRel,TolAbs,QPBound,BufSize,nData,MaxTime)*/
-
-    data_X = (mxArray*)prhs[0];
-    if (!(mxIsDouble(data_X)))
-      mexErrMsgTxt("Input argument X must be of type double.");
-
-    if (mxGetNumberOfDimensions(data_X) != 2)
-      mexErrMsgTxt("Input argument X must be two dimensional.");
-
-    data_y = (double*)mxGetPr(prhs[1]);
-
-    if(LIBOCAS_MAX(mxGetM(prhs[1]),mxGetN(prhs[1])) != mxGetN(prhs[0]))
-      mexErrMsgTxt("Length of vector y must equal to the number of columns of matrix X.");
-
-    C = (double)mxGetScalar(prhs[2]);
-
-    if(nrhs >= 4)
-      Method = (uint32_t)mxGetScalar(prhs[3]);
-    else
-      Method = DEFAULT_METHOD;
-
-    if(nrhs >= 5)
-      TolRel = (double)mxGetScalar(prhs[4]);
-    else
-      TolRel = DEFAULT_TOLREL;
-
-    if(nrhs >= 6)    
-      TolAbs = (double)mxGetScalar(prhs[5]);
-    else
-      TolAbs = DEFAULT_TOLABS;
-
-    if(nrhs >= 7)
-      QPBound = (double)mxGetScalar(prhs[6]);
-    else
-      QPBound = DEFAULT_QPVALUE;
-    
-    if(nrhs >= 8)
-      BufSize = (uint32_t)mxGetScalar(prhs[7]);
-    else
-      BufSize = DEFAULT_BUFSIZE;
-
-    if(nrhs >= 9 && mxIsInf(mxGetScalar(prhs[8])) == false)
-      nData = (uint32_t)mxGetScalar(prhs[8]);
-    else
-      nData = mxGetN(data_X);
-      
-    if(nData < 1 || nData > mxGetN(prhs[0])) 
-      mexErrMsgTxt("Improper value of argument nData.");
-
-    if(nrhs >= 10)
-      MaxTime = (double)mxGetScalar(prhs[9]);
-    else
-      MaxTime = DEFAULT_MAXTIME;
-
-    if(nrhs >= 11)
-      verb = (int)mxGetScalar(prhs[10]);
-    else
-      verb = DEFAULT_VERB;
-
-
-  }
+  if(nrhs < 2 || nrhs > 10)
+    mexErrMsgTxt("Improper number of input arguments.\n"
+		 "\n"
+		 "OCAS solver for training multi-class linear SVM classifiers.\n"
+		 "\n"
+                 "Synopsis:\n"
+		 "  [W,stat] = msvmocas(dataFile,C,Method,TolRel,TolAbs,QPBound,BufSize,nExamples,MaxTime,verb)\n"
+		 "\n"
+		 "Input:\n"
+		 "  dataFile [string] path to file with training examples in SVM^light format\n"
+		 "  y [nExamples x 1] labels must be integers 1,2,...nY\n"
+		 "  C [1x1] regularization constant\n"
+		 "  Method [1x1] 0..cutting plane; 1..OCAS  (default 1)\n"
+		 "  TolRel [1x1] halts if Q_P-Q_D <= abs(Q_P)*TolRel  (default 0.01)\n"
+		 "  TolAbs [1x1] halts if Q_P-Q_D <= TolAbs  (default 0)\n"
+		 "  QPValue [1x1] halts if Q_P <= QPBpound  (default 0)\n"
+		 "  BufSize [1x1] Initial size of active constrains buffer (default 2000)\n"
+		 "  nExamples [1x1] Number of training examples used for training; must be >0 and <= size(X,2).\n"
+		 "    If nExamples = inf then nExamples is set to size(X,2).\n"
+		 "  MaxTime [1x1] halts if time used by solver (data loading time is not counted) exceeds\n"
+		 "    MaxTime given in seconds. Use MaxTime=inf (default) to switch off this stopping condition.\n"
+		 "  verb [1x1] if non-zero then prints some info; (default 1)\n"
+		 "\n"
+		 "Output:\n"
+		 "  W [nDim x nY] Paramater vectors of decision rule; [dummy,ypred] = max(W'*x)\n"
+		 "  stat [struct] Optimizer statistics (field names are self-explaining).\n");
+
+  char *fname;
+  int fname_len;
+
+  if(!mxIsChar(prhs[0]))
+    mexErrMsgTxt("First input argument must be of type string.");
+
+  fname_len = mxGetNumberOfElements(prhs[0]) + 1;   
+  fname = mxCalloc(fname_len, sizeof(char));    
+
+  if (mxGetString(prhs[0], fname, fname_len) != 0)     
+    mexErrMsgTxt("Could not convert first input argument to string.");
+
+  if(nrhs >= 10)
+    verb = (int)mxGetScalar(prhs[9]);
   else
-  {
-    /*  [W,stat] = msvmocas(svmlight_data_file,C,Method,TolRel,TolAbs,QPBound,BufSize,nData,MaxTime)*/
-    char *fname;
-    int fname_len;
-
-    if(nrhs < 2 || nrhs > 10)
-      mexErrMsgTxt("Improper number of input arguments.");
-
-    if(!mxIsChar(prhs[0]))
-      mexErrMsgTxt("First input argument must be of type string.");
-
-    fname_len = mxGetNumberOfElements(prhs[0]) + 1;   
-    fname = mxCalloc(fname_len, sizeof(char));    
-
-    if (mxGetString(prhs[0], fname, fname_len) != 0)     
-      mexErrMsgTxt("Could not convert first input argument to string.");
-
-    if(nrhs >= 10)
-      verb = (int)mxGetScalar(prhs[9]);
-    else
-      verb = DEFAULT_VERB;
+    verb = DEFAULT_VERB;
 
-    /* load data */
-    if( load_svmlight_file(fname,verb) == -1 || data_X == NULL || data_y == NULL)
-      mexErrMsgTxt("Cannot load input file.");
+  /* load data */
+  if( load_svmlight_file(fname,verb) == -1 || data_X == NULL || data_y == NULL)
+    mexErrMsgTxt("Cannot load input file.");
 
-    C = (double)mxGetScalar(prhs[1]);
+  C = (double)mxGetScalar(prhs[1]);
 
-    if(nrhs >= 3)
-      Method = (uint32_t)mxGetScalar(prhs[2]);
-    else
-      Method = DEFAULT_METHOD;
+  if(nrhs >= 3)
+    Method = (uint32_t)mxGetScalar(prhs[2]);
+  else
+    Method = DEFAULT_METHOD;
 
-    if(nrhs >= 4)
-      TolRel = (double)mxGetScalar(prhs[3]);
-    else
-      TolRel = DEFAULT_TOLREL;
+  if(nrhs >= 4)
+    TolRel = (double)mxGetScalar(prhs[3]);
+  else
+    TolRel = DEFAULT_TOLREL;
 
-    if(nrhs >= 5)    
-      TolAbs = (double)mxGetScalar(prhs[4]);
-    else
-      TolAbs = DEFAULT_TOLABS;
+  if(nrhs >= 5)    
+    TolAbs = (double)mxGetScalar(prhs[4]);
+  else
+    TolAbs = DEFAULT_TOLABS;
 
-    if(nrhs >= 6)
-      QPBound = (double)mxGetScalar(prhs[5]);
-    else
-      QPBound = DEFAULT_QPVALUE;
+  if(nrhs >= 6)
+    QPBound = (double)mxGetScalar(prhs[5]);
+  else
+    QPBound = DEFAULT_QPVALUE;
     
-    if(nrhs >= 7)
-      BufSize = (uint32_t)mxGetScalar(prhs[6]);
-    else
-      BufSize = DEFAULT_BUFSIZE;
-
-    if(nrhs >= 8 && mxIsInf(mxGetScalar(prhs[7])) == false)
-      nData = (uint32_t)mxGetScalar(prhs[7]);
-    else
-      nData = mxGetN(data_X);
+  if(nrhs >= 7)
+    BufSize = (uint32_t)mxGetScalar(prhs[6]);
+  else
+    BufSize = DEFAULT_BUFSIZE;
 
-    if(nData < 1 || nData > mxGetN(data_X)) 
-      mexErrMsgTxt("Improper value of argument nData.");
+  if(nrhs >= 8 && mxIsInf(mxGetScalar(prhs[7])) == false)
+    nData = (uint32_t)mxGetScalar(prhs[7]);
+  else
+    nData = mxGetN(data_X);
 
-    if(nrhs >= 9)
-      MaxTime = (double)mxGetScalar(prhs[8]);
-    else
-      MaxTime = DEFAULT_MAXTIME;
+  if(nData < 1 || nData > mxGetN(data_X)) 
+    mexErrMsgTxt("Improper value of argument nData.");
 
+  if(nrhs >= 9)
+    MaxTime = (double)mxGetScalar(prhs[8]);
+  else
+    MaxTime = DEFAULT_MAXTIME;
 
-  }
 
 /*  nDim = mxGetM(prhs[0]);*/
   nDim = mxGetM(data_X);
-  for(i=0, nY = 0; i < nData; i++)
-    nY = LIBOCAS_MAX(nY, (uint32_t)data_y[i]);
-
+  for(i=0, nY = 0; i < nData; i++) 
+  {
+      nY = LIBOCAS_MAX(nY, (uint32_t)data_y[i]);
+  }
 
   /*----------------------------------------------------------------
     Print setting
@@ -243,6 +211,17 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
   if(new_a == NULL) 
     mexErrMsgTxt("Not enough memory for auxciliary cutting plane buffer new_a.");  
 
+  /* select function to print progress info */
+  void (*print_function)(ocas_return_value_T);
+  if(verb) 
+  {
+    mexPrintf("Starting optimization:\n");
+    print_function = &ocas_print;
+  }
+  else 
+  {
+    print_function = &ocas_print_null;
+  }
 
   if( mxIsSparse(data_X)== true ) 
   {
@@ -253,19 +232,11 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
     if(sparse_A.nz_dims == NULL || sparse_A.index == NULL || sparse_A.value == NULL) 
       mexErrMsgTxt("Not enough memory for cutting plane buffer sparse_A.");  
 
-    if(verb)
-      mexPrintf("Starting optimization:\n");
-
     init_time=get_time()-init_time;
 
-    if(verb)
-      ocas = msvm_ocas_solver( C, data_y, nY, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
-                             &msvm_sparse_compute_W, &msvm_full_update_W, &msvm_sparse_add_new_cut,
-                             &msvm_sparse_compute_output, &qsort_data, &ocas_print, 0);
-    else
-      ocas = msvm_ocas_solver( C, data_y, nY, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
-                             &msvm_sparse_compute_W, &msvm_full_update_W, &msvm_sparse_add_new_cut,
-                             &msvm_sparse_compute_output, &qsort_data, &ocas_print_null, 0);
+    ocas = msvm_ocas_solver( C, data_y, nY, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
+                             &msvm_sparse_compute_W, &msvm_update_W, &msvm_sparse_add_new_cut,
+                             &msvm_sparse_compute_output, &qsort_data, print_function, 0);
   }
   else
   {
@@ -274,21 +245,15 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
     if( full_A == NULL )
       mexErrMsgTxt("Not enough memory for cutting plane buffer full_A.");    
 
-    if(verb)
-      mexPrintf("Starting optimization:\n");
-
     init_time=get_time()-init_time;
 
-    if(verb)
-      ocas = msvm_ocas_solver( C, data_y, nY, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
-                             &msvm_full_compute_W, &msvm_full_update_W, &msvm_full_add_new_cut,
-                             &msvm_full_compute_output, &qsort_data, &ocas_print, 0); 
-    else
-      ocas = msvm_ocas_solver( C, data_y, nY, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
-                             &msvm_full_compute_W, &msvm_full_update_W, &msvm_full_add_new_cut,
-                             &msvm_full_compute_output, &qsort_data, &ocas_print_null, 0); 
+    ocas = msvm_ocas_solver( C, data_y, nY, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
+                             &msvm_full_compute_W, &msvm_update_W, &msvm_full_add_new_cut,
+                             &msvm_full_compute_output, &qsort_data, print_function, 0); 
 
   }
+
+  total_time=get_time()-total_time;
  
   if(verb)
   {
@@ -302,11 +267,7 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
        case -1: mexPrintf("Has not converged!\n" ); break;
        case -2: mexPrintf("Not enough memory for the solver.\n" ); break;
     }
-  }
-
-  total_time=get_time()-total_time;
-  if(verb)
-  {
+  
     mexPrintf("Timing statistics:\n"
 			"   init_time      : %f[s]\n"
 			"   qp_solver_time : %f[s]\n"
@@ -323,20 +284,6 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
     mexPrintf("Training error: %.4f%%\n", 100*(double)ocas.trn_err/(double)nData);
   }
 
-  
-  /* return ocas optimizer statistics */
-  /* typedef struct {
-     uint32_t nIter;    
-     uint32_t nCutPlanes;
-     double trn_err;      
-     double Q_P;          
-     double Q_D;
-     double output_time;
-     double sort_time;
-     double solver_time;
-     int8_t exitflag;       
-     } ocas_return_value_T; */
-
   const char *field_names[] = {"nTrnErrors","Q_P","Q_D","nIter","nCutPlanes","exitflag",
                                "init_time","output_time","sort_time","qp_solver_time","add_time",
                                "w_time","ocas_time","total_time"}; 
diff --git a/msvmocas_mex.c b/msvmocas_mex.c
index 330972e..99d01a2 100644
--- a/msvmocas_mex.c
+++ b/msvmocas_mex.c
@@ -1,13 +1,29 @@
 /*=================================================================================
- * svmocas_mex.c: Matlab MEX interface for OCAS solver training the linear SVM classifiers.
+ * msvmocas_mex.c: OCAS solver for training multi-class linear SVM classifiers.
  * 
  * Synopsis:
- *  [W,stat] = msvmocas(X,y,C,Method,TolRel,TolAbs,QPBound,BufSize,nData,MaxTime,verb)
- *  [W,stat] = msvmocas(svmlight_data_file,C,Method,TolRel,TolAbs,QPBound,BufSize,nData,MaxTime,verb)
+ *   [W,stat] = msvmocas(X,y,C,Method,TolRel,TolAbs,QPBound,BufSize,nExamples,MaxTime,verb)
+ * 
+ * Input:
+ *  X [nDim x nExamples] training feature inputs (sparse or dense matrix of doubles).
+ *  y [nExamples x 1] labels; intgers 1,2,...nY
+ *  C [1x1] regularization constant
+ *  Method [1x1] 0..cutting plane; 1..OCAS  (default 1)
+ *  TolRel [1x1] halts if Q_P-Q_D <= abs(Q_P)*TolRel  (default 0.01)
+ *  TolAbs [1x1] halts if Q_P-Q_D <= TolAbs  (default 0)
+ *  QPValue [1x1] halts if Q_P <= QPBpound  (default 0)
+ *  BufSize [1x1] Initial size of active constrains buffer (default 2000)
+ *  nExamples [1x1] Number of training examplesused for training; must be >0 and <= size(X,2).
+ *     If nExamples = inf then nExamples is set to size(X,2).
+ *  MaxTime [1x1] halts if time used by solver (data loading time is not counted) exceeds
+ *    MaxTime given in seconds. Use MaxTime=inf (default) to switch off this stopping condition. 
+ *  verb [1x1] if non-zero then prints some info; (default 1)
  *
- * Synopsis:
- *  [W,stat] = msvmocas(X,y,C,Method,TolRel,TolAbs,QPBound,BufSize,nData,MaxTime)
- * Copyright (C) 2008 Vojtech Franc, xfrancv at cmp.felk.cvut.cz
+ * Output:
+ *  W [nDim x nY] Paramater vectors of decision rule; [dummy,ypred] = max(W'*x)
+ *  stat [struct] Optimizer statistics (field names are self-explaining).
+ *
+ * Copyright (C) 2008, 2012 Vojtech Franc, xfrancv at cmp.felk.cvut.cz
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public 
@@ -19,10 +35,9 @@
 #include <stdint.h>
 #include <mex.h>
 
-/*#define LIBOCAS_MATLAB*/
-
 #include "libocas.h"
 #include "ocas_helper.h"
+#include "features_double.h"
 
 #define DEFAULT_METHOD 1
 #define DEFAULT_TOLREL 0.01
@@ -54,153 +69,97 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
   total_time = get_time();
   init_time = total_time;
 
-  if(nrhs < 1)
-    mexErrMsgTxt("Improper number of input arguments.");
-
-  /* get input arguments */ 
-  if(mxIsChar(prhs[0]) == false) 
+  if(nrhs < 3 || nrhs > 11)
+    mexErrMsgTxt("Improper number of input arguments.\n"
+		 "\n"
+		 "OCAS solver for training multi-class linear SVM classifiers.\n"
+		 "\n"
+                 "Synopsis:\n"
+		 "  [W,stat] = msvmocas(X,y,C,Method,TolRel,TolAbs,QPBound,BufSize,nExamples,MaxTime,verb)\n"
+		 "\n"
+		 "Input:\n"
+		 "  X [nDim x nExamples] training inputs (sparse or dense matrix of doubles).\n"
+		 "  y [nExamples x 1] labels must be integers 1,2,...nY\n"
+		 "  C [1x1] regularization constant\n"
+		 "  Method [1x1] 0..cutting plane; 1..OCAS  (default 1)\n"
+		 "  TolRel [1x1] halts if Q_P-Q_D <= abs(Q_P)*TolRel  (default 0.01)\n"
+		 "  TolAbs [1x1] halts if Q_P-Q_D <= TolAbs  (default 0)\n"
+		 "  QPValue [1x1] halts if Q_P <= QPBpound  (default 0)\n"
+		 "  BufSize [1x1] Initial size of active constrains buffer (default 2000)\n"
+		 "  nExamples [1x1] Number of training examples used for training; must be >0 and <= size(X,2).\n"
+		 "    If nExamples = inf then nExamples is set to size(X,2).\n"
+		 "  MaxTime [1x1] halts if time used by solver (data loading time is not counted) exceeds\n"
+		 "    MaxTime given in seconds. Use MaxTime=inf (default) to switch off this stopping condition.\n"
+		 "  verb [1x1] if non-zero then prints some info; (default 1)\n"
+		 "\n"
+		 "Output:\n"
+		 "  W [nDim x nY] Paramater vectors of decision rule; [dummy,ypred] = max(W'*x)\n"
+		 "  stat [struct] Optimizer statistics (field names are self-explaining).\n");
+     
+  data_X = (mxArray*)prhs[0];
+  if( (mxGetNumberOfDimensions(data_X) != 2) ||
+      !( ( mxIsDouble(data_X) && mxIsSparse(data_X)  ) ||
+         ( mxIsDouble(data_X) && !mxIsSparse(data_X) ) ))
   {
-
-    if(nrhs < 3 || nrhs > 11)
-      mexErrMsgTxt("Improper number of input arguments.");
-
-    /*  [W,stat] = msvmocas(X,y,C,Method,TolRel,TolAbs,QPBound,BufSize,nData,MaxTime)*/
-
-    data_X = (mxArray*)prhs[0];
-    if (!(mxIsDouble(data_X)))
-      mexErrMsgTxt("Input argument X must be of type double.");
-
-    if (mxGetNumberOfDimensions(data_X) != 2)
-      mexErrMsgTxt("Input argument X must be two dimensional.");
-
-    data_y = (double*)mxGetPr(prhs[1]);
-
-    if(LIBOCAS_MAX(mxGetM(prhs[1]),mxGetN(prhs[1])) != mxGetN(prhs[0]))
-      mexErrMsgTxt("Length of vector y must equal to the number of columns of matrix X.");
-
-    C = (double)mxGetScalar(prhs[2]);
-
-    if(nrhs >= 4)
-      Method = (uint32_t)mxGetScalar(prhs[3]);
-    else
-      Method = DEFAULT_METHOD;
-
-    if(nrhs >= 5)
-      TolRel = (double)mxGetScalar(prhs[4]);
-    else
-      TolRel = DEFAULT_TOLREL;
-
-    if(nrhs >= 6)    
-      TolAbs = (double)mxGetScalar(prhs[5]);
-    else
-      TolAbs = DEFAULT_TOLABS;
-
-    if(nrhs >= 7)
-      QPBound = (double)mxGetScalar(prhs[6]);
-    else
-      QPBound = DEFAULT_QPVALUE;
+    mexErrMsgTxt("The first input argument must be two dimensional matrix of the following type:\n"
+		 "dense double matrix or sparse double matrix.\n");
+  }
     
-    if(nrhs >= 8)
-      BufSize = (uint32_t)mxGetScalar(prhs[7]);
-    else
-      BufSize = DEFAULT_BUFSIZE;
-
-    if(nrhs >= 9 && mxIsInf(mxGetScalar(prhs[8])) == false)
-      nData = (uint32_t)mxGetScalar(prhs[8]);
-    else
-      nData = mxGetN(data_X);
-      
-    if(nData < 1 || nData > mxGetN(prhs[0])) 
-      mexErrMsgTxt("Improper value of argument nData.");
+  data_y = (double*)mxGetPr(prhs[1]);
 
-    if(nrhs >= 10)
-      MaxTime = (double)mxGetScalar(prhs[9]);
-    else
-      MaxTime = DEFAULT_MAXTIME;
+  if(LIBOCAS_MAX(mxGetM(prhs[1]),mxGetN(prhs[1])) != mxGetN(prhs[0]))
+    mexErrMsgTxt("Length of vector y must equal to the number of columns of matrix X.");
 
-    if(nrhs >= 11)
-      verb = (int)mxGetScalar(prhs[10]);
-    else
-      verb = DEFAULT_VERB;
+  C = (double)mxGetScalar(prhs[2]);
 
-
-  }
+  if(nrhs >= 4)
+    Method = (uint32_t)mxGetScalar(prhs[3]);
   else
-  {
-    /*  [W,stat] = msvmocas(svmlight_data_file,C,Method,TolRel,TolAbs,QPBound,BufSize,nData,MaxTime)*/
-    char *fname;
-    int fname_len;
-
-    if(nrhs < 2 || nrhs > 10)
-      mexErrMsgTxt("Improper number of input arguments.");
-
-    if(!mxIsChar(prhs[0]))
-      mexErrMsgTxt("First input argument must be of type string.");
-
-    fname_len = mxGetNumberOfElements(prhs[0]) + 1;   
-    fname = mxCalloc(fname_len, sizeof(char));    
-
-    if (mxGetString(prhs[0], fname, fname_len) != 0)     
-      mexErrMsgTxt("Could not convert first input argument to string.");
-
-    if(nrhs >= 10)
-      verb = (int)mxGetScalar(prhs[9]);
-    else
-      verb = DEFAULT_VERB;
-
-    /* load data */
-    if( load_svmlight_file(fname,verb) == -1 || data_X == NULL || data_y == NULL)
-      mexErrMsgTxt("Cannot load input file.");
-
-    C = (double)mxGetScalar(prhs[1]);
+    Method = DEFAULT_METHOD;
 
-    if(nrhs >= 3)
-      Method = (uint32_t)mxGetScalar(prhs[2]);
-    else
-      Method = DEFAULT_METHOD;
-
-    if(nrhs >= 4)
-      TolRel = (double)mxGetScalar(prhs[3]);
-    else
-      TolRel = DEFAULT_TOLREL;
+  if(nrhs >= 5)
+    TolRel = (double)mxGetScalar(prhs[4]);
+  else
+    TolRel = DEFAULT_TOLREL;
 
-    if(nrhs >= 5)    
-      TolAbs = (double)mxGetScalar(prhs[4]);
-    else
-      TolAbs = DEFAULT_TOLABS;
+  if(nrhs >= 6)    
+    TolAbs = (double)mxGetScalar(prhs[5]);
+  else
+    TolAbs = DEFAULT_TOLABS;
 
-    if(nrhs >= 6)
-      QPBound = (double)mxGetScalar(prhs[5]);
-    else
-      QPBound = DEFAULT_QPVALUE;
+  if(nrhs >= 7)
+    QPBound = (double)mxGetScalar(prhs[6]);
+  else
+    QPBound = DEFAULT_QPVALUE;
     
-    if(nrhs >= 7)
-      BufSize = (uint32_t)mxGetScalar(prhs[6]);
-    else
-      BufSize = DEFAULT_BUFSIZE;
-
-    if(nrhs >= 8 && mxIsInf(mxGetScalar(prhs[7])) == false)
-      nData = (uint32_t)mxGetScalar(prhs[7]);
-    else
-      nData = mxGetN(data_X);
+  if(nrhs >= 8)
+    BufSize = (uint32_t)mxGetScalar(prhs[7]);
+  else
+    BufSize = DEFAULT_BUFSIZE;
 
-    if(nData < 1 || nData > mxGetN(data_X)) 
-      mexErrMsgTxt("Improper value of argument nData.");
+  if(nrhs >= 9 && mxIsInf(mxGetScalar(prhs[8])) == false)
+    nData = (uint32_t)mxGetScalar(prhs[8]);
+  else
+    nData = mxGetN(data_X);
+      
+  if(nData < 1 || nData > mxGetN(prhs[0])) 
+    mexErrMsgTxt("Improper value of argument nData.");
 
-    if(nrhs >= 9)
-      MaxTime = (double)mxGetScalar(prhs[8]);
-    else
-      MaxTime = DEFAULT_MAXTIME;
+  if(nrhs >= 10)
+    MaxTime = (double)mxGetScalar(prhs[9]);
+  else
+    MaxTime = DEFAULT_MAXTIME;
 
+  if(nrhs >= 11)
+    verb = (int)mxGetScalar(prhs[10]);
+  else
+    verb = DEFAULT_VERB;
 
-  }
 
-/*  nDim = mxGetM(prhs[0]);*/
   nDim = mxGetM(data_X);
   for(i=0, nY = 0; i < nData; i++)
     nY = LIBOCAS_MAX(nY, (uint32_t)data_y[i]);
 
-
   /*----------------------------------------------------------------
     Print setting
   -------------------------------------------------------------------*/
@@ -243,7 +202,19 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
   if(new_a == NULL) 
     mexErrMsgTxt("Not enough memory for auxciliary cutting plane buffer new_a.");  
 
+  /* select function to print progress info */
+  void (*print_function)(ocas_return_value_T);
+  if(verb) 
+  {
+    mexPrintf("Starting optimization:\n");
+    print_function = &ocas_print;
+  }
+  else 
+  {
+    print_function = &ocas_print_null;
+  }
 
+  
   if( mxIsSparse(data_X)== true ) 
   {
     /* init cutting plane buffer */
@@ -253,19 +224,11 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
     if(sparse_A.nz_dims == NULL || sparse_A.index == NULL || sparse_A.value == NULL) 
       mexErrMsgTxt("Not enough memory for cutting plane buffer sparse_A.");  
 
-    if(verb)
-      mexPrintf("Starting optimization:\n");
-
     init_time=get_time()-init_time;
 
-    if(verb)
-      ocas = msvm_ocas_solver( C, data_y, nY, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
-                             &msvm_sparse_compute_W, &msvm_full_update_W, &msvm_sparse_add_new_cut,
-                             &msvm_sparse_compute_output, &qsort_data, &ocas_print, 0);
-    else
-      ocas = msvm_ocas_solver( C, data_y, nY, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
-                             &msvm_sparse_compute_W, &msvm_full_update_W, &msvm_sparse_add_new_cut,
-                             &msvm_sparse_compute_output, &qsort_data, &ocas_print_null, 0);
+    ocas = msvm_ocas_solver( C, data_y, nY, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
+                             &msvm_sparse_compute_W, &msvm_update_W, &msvm_sparse_add_new_cut,
+                             &msvm_sparse_compute_output, &qsort_data, print_function, 0);
   }
   else
   {
@@ -274,21 +237,14 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
     if( full_A == NULL )
       mexErrMsgTxt("Not enough memory for cutting plane buffer full_A.");    
 
-    if(verb)
-      mexPrintf("Starting optimization:\n");
-
     init_time=get_time()-init_time;
 
-    if(verb)
-      ocas = msvm_ocas_solver( C, data_y, nY, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
-                             &msvm_full_compute_W, &msvm_full_update_W, &msvm_full_add_new_cut,
-                             &msvm_full_compute_output, &qsort_data, &ocas_print, 0); 
-    else
-      ocas = msvm_ocas_solver( C, data_y, nY, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
-                             &msvm_full_compute_W, &msvm_full_update_W, &msvm_full_add_new_cut,
-                             &msvm_full_compute_output, &qsort_data, &ocas_print_null, 0); 
-
+    ocas = msvm_ocas_solver( C, data_y, nY, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
+                             &msvm_full_compute_W, &msvm_update_W, &msvm_full_add_new_cut,
+                             &msvm_full_compute_output, &qsort_data, print_function, 0); 
   }
+
+  total_time=get_time()-total_time;
  
   if(verb)
   {
@@ -302,41 +258,23 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
        case -1: mexPrintf("Has not converged!\n" ); break;
        case -2: mexPrintf("Not enough memory for the solver.\n" ); break;
     }
-  }
 
-  total_time=get_time()-total_time;
-  if(verb)
-  {
     mexPrintf("Timing statistics:\n"
-			"   init_time      : %f[s]\n"
-			"   qp_solver_time : %f[s]\n"
-			"   sort_time      : %f[s]\n"
-			"   output_time    : %f[s]\n"
-			"   add_time       : %f[s]\n"
-			"   w_time         : %f[s]\n"
-			"   print_time     : %f[s]\n"
-			"   ocas_time      : %f[s]\n"
-			"   total_time     : %f[s]\n",
-			init_time, ocas.qp_solver_time, ocas.sort_time, ocas.output_time, 
+	      " init_time      : %f[s]\n"
+	      "   qp_solver_time : %f[s]\n"
+	      "   sort_time      : %f[s]\n"
+	      "   output_time    : %f[s]\n"
+	      "   add_time       : %f[s]\n"
+	      "   w_time         : %f[s]\n"
+	      "   print_time     : %f[s]\n"
+	      "   ocas_time      : %f[s]\n"
+	      "   total_time     : %f[s]\n",
+	    init_time, ocas.qp_solver_time, ocas.sort_time, ocas.output_time, 
             ocas.add_time, ocas.w_time, ocas.print_time, ocas.ocas_time, total_time);
 
     mexPrintf("Training error: %.4f%%\n", 100*(double)ocas.trn_err/(double)nData);
   }
 
-  
-  /* return ocas optimizer statistics */
-  /* typedef struct {
-     uint32_t nIter;    
-     uint32_t nCutPlanes;
-     double trn_err;      
-     double Q_P;          
-     double Q_D;
-     double output_time;
-     double sort_time;
-     double solver_time;
-     int8_t exitflag;       
-     } ocas_return_value_T; */
-
   const char *field_names[] = {"nTrnErrors","Q_P","Q_D","nIter","nCutPlanes","exitflag",
                                "init_time","output_time","sort_time","qp_solver_time","add_time",
                                "w_time","ocas_time","total_time"}; 
diff --git a/ocas_helper.c b/ocas_helper.c
index 7372086..bf38e65 100644
--- a/ocas_helper.c
+++ b/ocas_helper.c
@@ -1,8 +1,6 @@
 /*-----------------------------------------------------------------------
  * ocas_helper.c: Implementation of helper functions for the OCAS solver.
  *
- * It supports both sparse and dense matrices and loading data from
- * the SVM^light format.
  *-------------------------------------------------------------------- */
 
 #define _FILE_OFFSET_BITS  64
@@ -78,9 +76,50 @@ static struct thread_params_add* params_add;
 /* use multi-threads only if minimal number of examples to add is higher than the constant*/
 static const uint32_t MinimalParallelCutLenght = 100;  
 
-/***********************************************************************
-   Multiclass SVM helper functions.                                   
- **********************************************************************/
+
+/*----------------------------------------------------------------------
+  sq_norm_W = sparse_compute_W( alpha, nSel ) does the following:
+
+  oldW = W;
+  W = sparse_A(:,1:nSel)'*alpha;
+  sq_norm_W = W'*W;
+  dp_WoldW = W'*oldW';
+
+  ----------------------------------------------------------------------*/
+void sparse_compute_W( double *sq_norm_W, 
+                       double *dp_WoldW, 
+                       double *alpha, 
+                       uint32_t nSel, 
+                       void* user_data )
+{
+  uint32_t i,j, nz_dims;
+
+  memcpy(oldW, W, sizeof(double)*nDim ); 
+  memset(W, 0, sizeof(double)*nDim);
+
+  oldW0 = W0;
+  W0 = 0;
+
+  for(i=0; i < nSel; i++) {
+    nz_dims = sparse_A.nz_dims[i];
+    if(nz_dims > 0 && alpha[i] > 0) {
+      for(j=0; j < nz_dims; j++) {
+        W[sparse_A.index[i][j]] += alpha[i]*sparse_A.value[i][j];
+      }
+    }
+    W0 += A0[i]*alpha[i];
+  }
+
+  *sq_norm_W = W0*W0;
+  *dp_WoldW = W0*oldW0;
+  for(j=0; j < nDim; j++) {
+    *sq_norm_W += W[j]*W[j];
+    *dp_WoldW += W[j]*oldW[j];
+  }
+  
+  return;
+}
+
 
 /*----------------------------------------------------------------------
   sq_norm_W = sparse_compute_W( alpha, nSel ) does the following:
@@ -130,7 +169,7 @@ void msvm_sparse_compute_W( double *sq_norm_W,
   sq_norm_W = W'*W;
 
   ---------------------------------------------------------------------------------*/
-double msvm_full_update_W( double t, void* user_data )
+double msvm_update_W( double t, void* user_data )
 {
   uint32_t j;
   double sq_norm_W;         
@@ -146,202 +185,29 @@ double msvm_full_update_W( double t, void* user_data )
 }
 
 
-/*----------------------------------------------------------------------------------
-  sparse_add_new_cut( new_col_H, new_cut, cut_length, nSel ) does the following:
-
-    new_a = zeros(nDim,nY);
-    for i=1:nData
-       if new_cut(i) ~= data_y(i)
-          new_a(:,data_y(i)) = new_a(:,data_y(i)) + X(;,i);
-          new_a(:,new_cut(i)) = new_a(:,new_cut(i)) - X(;,i);
-       end
-    end
-
-    new_col_H = [sparse_A(:,1:nSel)'*new_a ; new_a'*new_a];
-    sparse_A(:,nSel+1) = new_a;
-
-    Warning: data_y is 1-based while new_cut is 0-based
-
-  ---------------------------------------------------------------------------------*/
-int msvm_sparse_add_new_cut( double *new_col_H, 
-                         uint32_t *new_cut, 
-                         uint32_t nSel, 
-                         void* user_data )
-{
-/*  double *new_a, */
-  double sq_norm_a;
-  uint32_t i, j, nz_dims, ptr, y;
-
-  memset(new_a, 0, sizeof(double)*nY*nDim);
-  
-  for(i=0; i < nData; i++)
-  {
-    y = (uint32_t)(data_y[i]-1);
-    if(new_cut[i] != y)
-    {
-      add_sparse_col(&new_a[nDim*y], data_X, i);
-      subtract_sparse_col(&new_a[nDim*(uint32_t)new_cut[i]], data_X, i);
-    }
-  }
- 
-  /* compute new_a'*new_a and count number of non-zero dimensions */
-  nz_dims = 0; 
-  sq_norm_a = 0;
-  for(j=0; j < nY*nDim; j++ ) {
-    if(new_a[j] != 0) {
-      nz_dims++;
-      sq_norm_a += new_a[j]*new_a[j];
-    }
-  }
-
-  /* sparsify new_a and insert it to the last column  of sparse_A */
-  sparse_A.nz_dims[nSel] = nz_dims;
-  if(nz_dims > 0) {
-    sparse_A.index[nSel] = NULL;
-    sparse_A.value[nSel] = NULL;
-    sparse_A.index[nSel] = mxCalloc(nz_dims,sizeof(uint32_t));
-    sparse_A.value[nSel] = mxCalloc(nz_dims,sizeof(double));
-    if(sparse_A.index[nSel]==NULL || sparse_A.value[nSel]==NULL)
-    {
-/*      mexErrMsgTxt("Not enough memory for vector sparse_A.index[nSel], sparse_A.value[nSel].");*/
-      mxFree(sparse_A.index[nSel]);
-      mxFree(sparse_A.value[nSel]);
-      return(-1);
-    }
-
-    ptr = 0;
-    for(j=0; j < nY*nDim; j++ ) {
-      if(new_a[j] != 0) {
-        sparse_A.index[nSel][ptr] = j;
-        sparse_A.value[nSel][ptr++] = new_a[j];
-      }
-    }
-  }
-   
-  new_col_H[nSel] = sq_norm_a;
-  for(i=0; i < nSel; i++) {
-    double tmp = 0;
-
-    for(j=0; j < sparse_A.nz_dims[i]; j++) {
-      tmp += new_a[sparse_A.index[i][j]]*sparse_A.value[i][j];
-    }
-      
-    new_col_H[i] = tmp;
-  }
-
-  return 0;
-}
-
-
-/*----------------------------------------------------------------------
-  sparse_compute_output( output ) does the follwing:
-
-  output = W'*data_X;
-  ----------------------------------------------------------------------*/
-int msvm_sparse_compute_output( double *output, void* user_data )
-{
-  uint32_t i,y;
-
-  for(i=0; i < nData; i++) 
-  {
-    for(y=0; y < nY; y++)
-    {
-      output[LIBOCAS_INDEX(y,i,nY)] = dp_sparse_col(&W[y*nDim], data_X, i);
-    }
-  }
-  
-  return 0;
-}
-
-
-/*-----------------------------------------------------------
-  Functions working with full data.
-  -------------------------------------------------------------*/
-
-/*----------------------------------------------------------------------------------
-  full_add_new_cut( new_col_H, new_cut, cut_length, nSel ) does the following:
-
-    new_a = sum(data_X(:,find(new_cut ~=0 )),2);
-    new_col_H = [full_A(:,1:nSel)'*new_a ; new_a'*new_a];
-    full_A(:,nSel+1) = new_a;
-
-  ---------------------------------------------------------------------------------*/
-int msvm_full_add_new_cut( double *new_col_H, uint32_t *new_cut, uint32_t nSel, void* user_data)
-{
-  double sq_norm_a, *ptr;
-  uint32_t i, j, y, y2;
-
-  ptr = mxGetPr(data_X);
-
-  memset(new_a, 0, sizeof(double)*nDim*nY);
-
-  for(i=0; i < nData; i++)
-  {
-    y = (uint32_t)(data_y[i]-1);
-    y2 = (uint32_t)new_cut[i];
-    if(y2 != y)
-    {
-      for(j=0; j < nDim; j++ ) 
-      {
-        new_a[LIBOCAS_INDEX(j,y,nDim)] += ptr[LIBOCAS_INDEX(j,i,nDim)];
-        new_a[LIBOCAS_INDEX(j,y2,nDim)] -= ptr[LIBOCAS_INDEX(j,i,nDim)];
-      }
-    }
-  }
-
-  /* compute new_a'*new_a and insert new_a to the last column of full_A */
-  sq_norm_a = 0;
-  for(j=0; j < nDim*nY; j++ ) {
-    sq_norm_a += new_a[j]*new_a[j];
-    full_A[LIBOCAS_INDEX(j,nSel,nDim*nY)] = new_a[j];
-  }
-
-  new_col_H[nSel] = sq_norm_a;
-  for(i=0; i < nSel; i++) {
-    double tmp = 0;
-
-    for(j=0; j < nDim*nY; j++ ) {
-      tmp += new_a[j]*full_A[LIBOCAS_INDEX(j,i,nDim*nY)];
-    }
-    new_col_H[i] = tmp;
-  }
-
-  return 0;
-}
-
-
-/*----------------------------------------------------------------------
-  full_compute_output( output ) does the follwing:
+/*-------------------------------------------------------------------------
+  sq_norm_W = full_update_W( t ) does the following:
 
-  output = data_X'*W;
-  ----------------------------------------------------------------------*/
-int msvm_full_compute_output( double *output, void* user_data )
+  W = oldW*(1-t) + t*W;
+  sq_norm_W = W'*W;
+---------------------------------------------------------------------------*/
+double update_W( double t, void* user_data )
 {
-  uint32_t i, j, y;
-  double *ptr, tmp;
+  uint32_t j;
+  double sq_norm_W;         
 
-  ptr = mxGetPr( data_X );
+  W0 = oldW0*(1-t) + t*W0;
+  sq_norm_W = W0*W0;
 
-  for(i=0; i < nData; i++) 
-  { 
-    for(y=0; y < nY; y++)
-    {
-      tmp = 0;
+  for(j=0; j <nDim; j++) {
+    W[j] = oldW[j]*(1-t) + t*W[j];
+    sq_norm_W += W[j]*W[j];
+  }          
 
-      for(j=0; j < nDim; j++ ) 
-      {
-        tmp += W[LIBOCAS_INDEX(j,y,nDim)]*ptr[LIBOCAS_INDEX(j,i,nDim)];
-      }
-      
-      output[LIBOCAS_INDEX(y,i,nY)] = tmp;
-    }
-  }
-  
-  return 0;
+  return( sq_norm_W );
 }
 
 
-
 /*----------------------------------------------------------------------
   sq_norm_W = full_compute_W( alpha, nSel ) does the following:
 
@@ -378,12 +244,6 @@ void msvm_full_compute_W( double *sq_norm_W, double *dp_WoldW, double *alpha, ui
 }
 
 
-
-/***********************************************************************
-  Generic functions.
- **********************************************************************/
-
-
 /*-----------------------------------------------------------------------
   Print statistics.
   -----------------------------------------------------------------------*/
@@ -413,13 +273,6 @@ double get_time()
 }
 
 
-/*=========================================================================
- *
- * Ocas helper functions implemented for input data represented as 
- * Matlab sparse matrix.
- *
- *=========================================================================*/
-
 /*----------------------------------------------------------------------
   in-place computes sparse_mat(:,col)= alpha * sparse_mat(:,col)
   where alpha is a scalar and sparse_mat is Matlab sparse matrix.
@@ -427,10 +280,9 @@ double get_time()
 void mul_sparse_col(double alpha, mxArray *sparse_mat, uint32_t col)
 {
 	uint32_t nItems, ptr, i;
-	INDEX_TYPE_T *Ir, *Jc;
+	INDEX_TYPE_T *Jc;
 	double *Pr;
 
-	Ir = mxGetIr(sparse_mat);
 	Jc = mxGetJc(sparse_mat);
 	Pr = mxGetPr(sparse_mat);
 
@@ -468,6 +320,7 @@ void add_sparse_col(double *full_vec, mxArray *sparse_mat, uint32_t col)
   }
 }
 
+
 /*----------------------------------------------------------------------
  It computes full_vec = full_vec - sparse_mat(:,col)
  where full_vec is a double array and sparse_mat is Matlab 
@@ -494,6 +347,7 @@ void subtract_sparse_col(double *full_vec, mxArray *sparse_mat, uint32_t col)
   }
 }
 
+
 /*----------------------------------------------------------------------
  It computes dp = full_vec'*sparse_mat(:,col)
  where full_vec is a double array and sparse_mat is Matlab 
@@ -524,269 +378,6 @@ double dp_sparse_col(double *full_vec, mxArray *sparse_mat, uint32_t col)
 }
 
 
-/*----------------------------------------------------------------------------------
-  sq_norm_W = sparse_update_W( t ) does the following:
-
-  W = oldW*(1-t) + t*W;
-  sq_norm_W = W'*W;
-
-  ---------------------------------------------------------------------------------*/
-double sparse_update_W( double t, void* user_data )
-{
-  uint32_t j;
-  double sq_norm_W;         
-
-  W0 = oldW0*(1-t) + t*W0;
-  sq_norm_W = W0*W0;
-
-  for(j=0; j <nDim; j++) {
-    W[j] = oldW[j]*(1-t) + t*W[j];
-    sq_norm_W += W[j]*W[j];
-  }          
-
-  return( sq_norm_W );
-}
-
-/*-------------------------------------------------------------------------
-  sq_norm_W = full_update_W( t ) does the following:
-
-  W = oldW*(1-t) + t*W;
-  sq_norm_W = W'*W;
----------------------------------------------------------------------------*/
-double full_update_W( double t, void* user_data )
-{
-  uint32_t j;
-  double sq_norm_W;         
-
-  W0 = oldW0*(1-t) + t*W0;
-  sq_norm_W = W0*W0;
-
-  for(j=0; j <nDim; j++) {
-    W[j] = oldW[j]*(1-t) + t*W[j];
-    sq_norm_W += W[j]*W[j];
-  }          
-
-  return( sq_norm_W );
-}
-
-
-/*----------------------------------------------------------------------------------
-  sparse_add_new_cut( new_col_H, new_cut, cut_length, nSel ) does the following:
-
-    new_a = sum(data_X(:,find(new_cut ~=0 )),2);
-    new_col_H = [sparse_A(:,1:nSel)'*new_a ; new_a'*new_a];
-    sparse_A(:,nSel+1) = new_a;
-
-  ---------------------------------------------------------------------------------*/
-int sparse_add_new_cut( double *new_col_H, 
-                         uint32_t *new_cut, 
-                         uint32_t cut_length, 
-                         uint32_t nSel, 
-                         void* user_data )
-{
-/*  double *new_a, */
-  double sq_norm_a;
-  uint32_t i, j, nz_dims, ptr;
-
-  memset(new_a, 0, sizeof(double)*nDim);
-  
-  for(i=0; i < cut_length; i++) {
-    add_sparse_col(new_a, data_X, new_cut[i]);
-
-    A0[nSel] += X0*data_y[new_cut[i]];    
-  }
- 
-  /* compute new_a'*new_a and count number of non-zero dimensions */
-  nz_dims = 0; 
-  sq_norm_a = A0[nSel]*A0[nSel];
-  for(j=0; j < nDim; j++ ) {
-    if(new_a[j] != 0) {
-      nz_dims++;
-      sq_norm_a += new_a[j]*new_a[j];
-    }
-  }
-
-  /* sparsify new_a and insert it to the last column  of sparse_A */
-  sparse_A.nz_dims[nSel] = nz_dims;
-  if(nz_dims > 0) {
-    sparse_A.index[nSel] = NULL;
-    sparse_A.value[nSel] = NULL;
-    sparse_A.index[nSel] = mxCalloc(nz_dims,sizeof(uint32_t));
-    sparse_A.value[nSel] = mxCalloc(nz_dims,sizeof(double));
-    if(sparse_A.index[nSel]==NULL || sparse_A.value[nSel]==NULL)
-    {
-/*      mexErrMsgTxt("Not enough memory for vector sparse_A.index[nSel], sparse_A.value[nSel].");*/
-      mxFree(sparse_A.index[nSel]);
-      mxFree(sparse_A.value[nSel]);
-      return(-1);
-    }
-
-    ptr = 0;
-    for(j=0; j < nDim; j++ ) {
-      if(new_a[j] != 0) {
-        sparse_A.index[nSel][ptr] = j;
-        sparse_A.value[nSel][ptr++] = new_a[j];
-      }
-    }
-  }
-   
-  new_col_H[nSel] = sq_norm_a;
-  for(i=0; i < nSel; i++) {
-    double tmp = A0[nSel]*A0[i];
-
-    for(j=0; j < sparse_A.nz_dims[i]; j++) {
-      tmp += new_a[sparse_A.index[i][j]]*sparse_A.value[i][j];
-    }
-      
-    new_col_H[i] = tmp;
-  }
-
-/*  mxFree( new_a );*/
-
-  return 0;
-}
-
-
-/*----------------------------------------------------------------------------------
-  full_add_new_cut( new_col_H, new_cut, cut_length, nSel ) does the following:
-
-    new_a = sum(data_X(:,find(new_cut ~=0 )),2);
-    new_col_H = [full_A(:,1:nSel)'*new_a ; new_a'*new_a];
-    full_A(:,nSel+1) = new_a;
-
-  ---------------------------------------------------------------------------------*/
-int full_add_new_cut( double *new_col_H, 
-                       uint32_t *new_cut, 
-                       uint32_t cut_length, 
-                       uint32_t nSel,
-                       void* user_data)
-{
-/*  double *new_a, */
-  double sq_norm_a, *ptr;
-  uint32_t i, j;
-
-  ptr = mxGetPr(data_X);
-
-  memset(new_a, 0, sizeof(double)*nDim);
-
-
-  for(i=0; i < cut_length; i++) {
-    for(j=0; j < nDim; j++ ) {
-      new_a[j] += ptr[LIBOCAS_INDEX(j,new_cut[i],nDim)];
-    }
-
-    A0[nSel] += X0*data_y[new_cut[i]];    
-  }
-
-  /* compute new_a'*new_a and insert new_a to the last column of full_A */
-  sq_norm_a = A0[nSel]*A0[nSel];
-  for(j=0; j < nDim; j++ ) {
-    sq_norm_a += new_a[j]*new_a[j];
-    full_A[LIBOCAS_INDEX(j,nSel,nDim)] = new_a[j];
-  }
-
-  new_col_H[nSel] = sq_norm_a;
-  for(i=0; i < nSel; i++) {
-    double tmp = A0[nSel]*A0[i];
-
-    for(j=0; j < nDim; j++ ) {
-      tmp += new_a[j]*full_A[LIBOCAS_INDEX(j,i,nDim)];
-    }
-    new_col_H[i] = tmp;
-  }
-
-/*  mxFree( new_a );*/
-
-  return 0;
-}
-
-
-/*----------------------------------------------------------------------
-  sparse_compute_output( output ) does the follwing:
-
-  output = data_X'*W;
-  ----------------------------------------------------------------------*/
-int sparse_compute_output( double *output, void* user_data )
-{
-  uint32_t i;
-
-  for(i=0; i < nData; i++) { 
-    output[i] = data_y[i]*X0*W0 + dp_sparse_col(W, data_X, i);
-  }
-  
-  return 0;
-}
-
-/*----------------------------------------------------------------------
-  full_compute_output( output ) does the follwing:
-
-  output = data_X'*W;
-  ----------------------------------------------------------------------*/
-int full_compute_output( double *output, void* user_data )
-{
-  uint32_t i, j;
-  double *ptr, tmp;
-
-  ptr = mxGetPr( data_X );
-
-  for(i=0; i < nData; i++) { 
-    tmp = data_y[i]*X0*W0;
-
-    for(j=0; j < nDim; j++ ) {
-      tmp += W[j]*ptr[LIBOCAS_INDEX(j,i,nDim)];
-    }
-    output[i] = tmp;
-  }
-  
-  return 0;
-}
-
-
-
-/*----------------------------------------------------------------------
-  sq_norm_W = sparse_compute_W( alpha, nSel ) does the following:
-
-  oldW = W;
-  W = sparse_A(:,1:nSel)'*alpha;
-  sq_norm_W = W'*W;
-  dp_WoldW = W'*oldW';
-
-  ----------------------------------------------------------------------*/
-void sparse_compute_W( double *sq_norm_W, 
-                       double *dp_WoldW, 
-                       double *alpha, 
-                       uint32_t nSel, 
-                       void* user_data )
-{
-  uint32_t i,j, nz_dims;
-
-  memcpy(oldW, W, sizeof(double)*nDim ); 
-  memset(W, 0, sizeof(double)*nDim);
-
-  oldW0 = W0;
-  W0 = 0;
-
-  for(i=0; i < nSel; i++) {
-    nz_dims = sparse_A.nz_dims[i];
-    if(nz_dims > 0 && alpha[i] > 0) {
-      for(j=0; j < nz_dims; j++) {
-        W[sparse_A.index[i][j]] += alpha[i]*sparse_A.value[i][j];
-      }
-    }
-    W0 += A0[i]*alpha[i];
-  }
-
-  *sq_norm_W = W0*W0;
-  *dp_WoldW = W0*oldW0;
-  for(j=0; j < nDim; j++) {
-    *sq_norm_W += W[j]*W[j];
-    *dp_WoldW += W[j]*oldW[j];
-  }
-  
-  return;
-}
-
-
 /*----------------------------------------------------------------------
   sq_norm_W = full_compute_W( alpha, nSel ) does the following:
 
@@ -827,17 +418,6 @@ void full_compute_W( double *sq_norm_W, double *dp_WoldW, double *alpha, uint32_
 }
 
 
-/* ==========================================================================
- Multi-thread version of the OCAS helper functions.
-
- int parallel_sparse_compute_output( double *output, void* user_data )
-
- void destroy_parallel_ocas(void)
- int init_parallel_ocas(int number_of_threads)
-
-============================================================================*/
-
-
 /*----------------------------------------------------------------------
   parallel_sparse_compute_output( output, user_data ) does the following
 
@@ -1153,15 +733,6 @@ int parallel_sparse_add_new_cut( double *new_col_H,
 }
 
 
-/*=========================================================================
- *
- * Ocas helper functions implemented for input data represented as
- * an array of doubles.
- *
- *=========================================================================*/
-
-
-
 /*=======================================================================
  OCAS helper functions for sorting numbers.
 =======================================================================*/
@@ -1172,12 +743,6 @@ static void swapf(double* a, double* b)
 	*a=dummy;
 }
 
-/*static void swapi(uint32_t* a, uint32_t* b)*/
-/*{*/
-/*	int dummy=*b;*/
-/*	*b=*a;*/
-/*	*a=dummy;*/
-/*}*/
 
 /* sort arrays value and data according to value in ascending order */
 int qsort_data(double* value, double* data, uint32_t size)
@@ -1346,9 +911,8 @@ int parallel_qsort_data(double* value, double* data, uint32_t size)
   return(0);
 }
 
-/* =================================================================================
- Other auxiliary functions.
-   =================================================================================*/
+
+
 
 /* ---------------------------------------------------------------------------------
 This function loads regularization constants from a text file. Each line contains
diff --git a/ocas_helper.h b/ocas_helper.h
index f6aece6..8eb14bb 100644
--- a/ocas_helper.h
+++ b/ocas_helper.h
@@ -1,14 +1,13 @@
 /*-----------------------------------------------------------------------
  * ocas_helper.h: Implementation of helper functions for the OCAS solver.
  *
- * It supports both sparse and dense matrices and loading data from
- * the SVM^light format.
  *-------------------------------------------------------------------- */
 
 #ifndef _ocas_helper_h
 #define _ocas_helper_h
 
 #include <stdint.h>
+#include "libocas.h"
 
 #ifdef LIBOCAS_MATLAB
 
@@ -52,53 +51,47 @@ extern double W0;
 extern double oldW0;
 extern double X0;
 
-double get_time(void);
-void ocas_print(ocas_return_value_T value);
-void ocas_print_null(ocas_return_value_T value);
-
-void mul_sparse_col(double alpha, mxArray *sparse_mat, uint32_t col);
-void add_sparse_col(double *full_vec, mxArray *sparse_mat, uint32_t col);
-void subtract_sparse_col(double *full_vec, mxArray *sparse_mat, uint32_t col);
-double dp_sparse_col(double *full_vec, mxArray *sparse_mat, uint32_t col);
-double sparse_update_W( double t, void* user_data );
-int sparse_add_new_cut( double *new_col_H, 
-                         uint32_t *new_cut, 
-                         uint32_t cut_length, 
-                         uint32_t nSel, 
-                         void* user_data );
-int sparse_compute_output( double *output, void* user_data );
-void sparse_compute_W( double *sq_norm_W, double *dp_WoldW, double *alpha, uint32_t nSel, void* user_data );
-
-void msvm_sparse_compute_W( double *sq_norm_W, double *dp_WoldW, double *alpha, uint32_t nSel, void* user_data );
-int msvm_sparse_add_new_cut( double *new_col_H, uint32_t *new_cut, uint32_t nSel, void* user_data );
-int msvm_sparse_compute_output( double *output, void* user_data );
-
-double msvm_full_update_W( double t, void* user_data );
-int msvm_full_add_new_cut( double *new_col_H, uint32_t *new_cut, uint32_t nSel, void* user_data);
-int msvm_full_compute_output( double *output, void* user_data );
-void msvm_full_compute_W( double *sq_norm_W, double *dp_WoldW, double *alpha, uint32_t nSel, void* user_data );
-
-
-double full_update_W( double t, void* user_data );
-int full_compute_output( double *output, void* user_data );
-void full_compute_W( double *sq_norm_W, double *dp_WoldW, double *alpha, uint32_t nSel, void* user_data );
-int full_add_new_cut( double *new_col_H, 
-                       uint32_t *new_cut, 
-                       uint32_t cut_length, 
-                       uint32_t nSel,
-                       void* user_data);
-
-int load_svmlight_file(char *fname, int verb);
-double compute_auc(double *score, int *label, uint32_t nData);
-int load_regconsts(char *fname, double **vec_C, uint32_t *len_vec_C, int verb);
-
-int qsort_data(double* value, double* data, uint32_t size);
-
-void destroy_parallel_ocas(void);
-int init_parallel_ocas(int number_of_threads);
-int parallel_sparse_compute_output( double *output, void* user_data );
-int parallel_qsort_data(double* value, double* data, uint32_t size);
-int parallel_sparse_add_new_cut( double *new_col_H,uint32_t *new_cut, uint32_t cut_length,uint32_t nSel,void* user_data );
+
+/** helper functions for OCAS solver **/
+extern void ocas_print(ocas_return_value_T value);
+extern void ocas_print_null(ocas_return_value_T value);
+extern int qsort_data(double* value, double* data, uint32_t size);
+
+/* helper functions for two-class SVM  solver */
+extern double update_W( double t, void* user_data );
+/* dense cutting plane buffer*/
+extern void full_compute_W( double *sq_norm_W, double *dp_WoldW, double *alpha, uint32_t nSel, void* user_data );
+/* sparse cutting plane bugger */
+extern void sparse_compute_W( double *sq_norm_W, double *dp_WoldW, double *alpha, uint32_t nSel, void* user_data );
+
+/* helper functions for multi-class SVM  solver */
+extern double msvm_update_W( double t, void* user_data );
+/* dense cutting plane buffer*/
+extern void msvm_full_compute_W( double *sq_norm_W, double *dp_WoldW, double *alpha, uint32_t nSel, void* user_data );
+/* sparse cutting plane bugger */
+extern void msvm_sparse_compute_W( double *sq_norm_W, double *dp_WoldW, double *alpha, uint32_t nSel, void* user_data );
+
+
+/** parallelized implementation of helper functions for two-class OCAS solver **/
+extern void destroy_parallel_ocas(void);
+extern int init_parallel_ocas(int number_of_threads);
+extern int parallel_sparse_compute_output( double *output, void* user_data );
+extern int parallel_qsort_data(double* value, double* data, uint32_t size);
+extern int parallel_sparse_add_new_cut( double *new_col_H,uint32_t *new_cut, uint32_t cut_length,uint32_t nSel,void* user_data );
+
+
+/** functions for working with sparse vectors **/
+extern void mul_sparse_col(double alpha, mxArray *sparse_mat, uint32_t col);
+extern void add_sparse_col(double *full_vec, mxArray *sparse_mat, uint32_t col);
+extern void subtract_sparse_col(double *full_vec, mxArray *sparse_mat, uint32_t col);
+extern double dp_sparse_col(double *full_vec, mxArray *sparse_mat, uint32_t col);
+
+
+/** auxcilirary functions **/
+extern int load_svmlight_file(char *fname, int verb);
+extern double compute_auc(double *score, int *label, uint32_t nData);
+extern int load_regconsts(char *fname, double **vec_C, uint32_t *len_vec_C, int verb);
+extern double get_time(void);
 
 
 #endif
diff --git a/ocas_lbp_helper.c b/ocas_lbp_helper.c
index aa6da0a..463b2e1 100644
--- a/ocas_lbp_helper.c
+++ b/ocas_lbp_helper.c
@@ -150,7 +150,7 @@ int full_add_new_cut( double *new_col_H,
           croped_window[cnt++] = img_ptr[LIBOCAS_INDEX(y,x,im_H)];
     }
     
-    if(data_y[new_cut[i]] == +1) {
+    if(data_y[new_cut[i]] > 0) {
 /*      lbppyr_addvec(new_a,croped_window);*/
       liblbp_pyr_addvec(new_a,nDim,croped_window,win_H,win_W);
     }
@@ -237,7 +237,10 @@ int full_compute_output( double *output, void* user_data )
     }
     
 /*    output[i] = data_y[i]*(X0*W0 + lbppyr_dotprod(W,croped_window));*/
-    output[i] = data_y[i]*(X0*W0 + liblbp_pyr_dotprod(W,nDim,croped_window,win_H,win_W));
+    if( data_y[i] > 0)
+      output[i] = (X0*W0 + liblbp_pyr_dotprod(W,nDim,croped_window,win_H,win_W));
+    else
+      output[i] = -(X0*W0 + liblbp_pyr_dotprod(W,nDim,croped_window,win_H,win_W));
 
     /*
     for(j=0; j < nDim; j++ ) {
diff --git a/svmocas b/svmocas
new file mode 100755
index 0000000..df8c752
Binary files /dev/null and b/svmocas differ
diff --git a/svmocas.c b/svmocas.c
index 3b74dfb..b0944ba 100644
--- a/svmocas.c
+++ b/svmocas.c
@@ -2,7 +2,7 @@
  * svmocas.c: Standalone application implementing the OCAS solver for 
  *   training linear SVM classifiers.
  *   
- * Copyright (C) 2008, 2009 Vojtech Franc, xfrancv at cmp.felk.cvut.cz
+ * Copyright (C) 2008, 2009, 2012 Vojtech Franc, xfrancv at cmp.felk.cvut.cz
  *                    Soeren Sonnenburg, soeren.sonnenburg at first.fraunhofer.de
  *
  * This program is free software; you can redistribute it and/or
@@ -22,6 +22,7 @@
 #include "libocas.h"
 #include "sparse_mat.h"
 #include "ocas_helper.h"
+#include "features_double.h"
 
 #include "version.h"
 
@@ -67,7 +68,7 @@ void print_usage(void)
          "\n"
          "  Compute testing error of the classifier stored in ./data/svmocas.model using testing\n"
          "  examples from ./data/riply_tst.light and save predicted labels to ./data/riply_tst.pred\n"
-         "    ./linclass -e -o ./data/riply_tst.pred ./data/riply_tst.light ./data/svmocas.model\n"
+         "    ./linclassif -e -o ./data/riply_tst.pred ./data/riply_tst.light ./data/svmocas.model\n"
          "\n"
          );
 }
@@ -520,11 +521,11 @@ int main(int argc, char *argv[])
         printf("Starting optimization:\n");
         if( vec_C == NULL)
           ocas = svm_ocas_solver( C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method, 
-                                  &sparse_compute_W, &sparse_update_W, &sparse_add_new_cut, 
+                                  &sparse_compute_W, &update_W, &sparse_add_new_cut, 
                                   &sparse_compute_output, &qsort_data, &ocas_print, 0);
         else
           ocas = svm_ocas_solver_difC( vec_C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method, 
-                                       &sparse_compute_W, &sparse_update_W, &sparse_add_new_cut, 
+                                       &sparse_compute_W, &update_W, &sparse_add_new_cut, 
                                        &sparse_compute_output, &qsort_data, &ocas_print, 0);
 
       }
@@ -532,11 +533,11 @@ int main(int argc, char *argv[])
       {
         if( vec_C == NULL)          
           ocas = svm_ocas_solver( C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method, 
-                                  &sparse_compute_W, &sparse_update_W, &sparse_add_new_cut, 
+                                  &sparse_compute_W, &update_W, &sparse_add_new_cut, 
                                   &sparse_compute_output, &qsort_data, &ocas_print_null, 0);
         else
           ocas = svm_ocas_solver_difC( vec_C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method, 
-                                       &sparse_compute_W, &sparse_update_W, &sparse_add_new_cut, 
+                                       &sparse_compute_W, &update_W, &sparse_add_new_cut, 
                                        &sparse_compute_output, &qsort_data, &ocas_print_null, 0);
           
       }
@@ -555,11 +556,11 @@ int main(int argc, char *argv[])
     
         if( vec_C == NULL)          
           ocas = svm_ocas_solver( C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method, 
-                                  &sparse_compute_W, &sparse_update_W, &parallel_sparse_add_new_cut, 
+                                  &sparse_compute_W, &update_W, &parallel_sparse_add_new_cut, 
                                   &parallel_sparse_compute_output, &parallel_qsort_data, &ocas_print, 0);
         else
           ocas = svm_ocas_solver_difC( vec_C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method, 
-                                       &sparse_compute_W, &sparse_update_W, &parallel_sparse_add_new_cut, 
+                                       &sparse_compute_W, &update_W, &parallel_sparse_add_new_cut, 
                                        &parallel_sparse_compute_output, &parallel_qsort_data, &ocas_print, 0);
 
       }
@@ -567,11 +568,11 @@ int main(int argc, char *argv[])
       {
         if( vec_C == NULL)          
           ocas = svm_ocas_solver( C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method, 
-                                  &sparse_compute_W, &sparse_update_W, &parallel_sparse_add_new_cut, 
+                                  &sparse_compute_W, &update_W, &parallel_sparse_add_new_cut, 
                                   &parallel_sparse_compute_output, &parallel_qsort_data, &ocas_print_null, 0);
         else
           ocas = svm_ocas_solver_difC( vec_C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method, 
-                                  &sparse_compute_W, &sparse_update_W, &parallel_sparse_add_new_cut, 
+                                  &sparse_compute_W, &update_W, &parallel_sparse_add_new_cut, 
                                   &parallel_sparse_compute_output, &parallel_qsort_data, &ocas_print_null, 0);
           
       }
@@ -606,11 +607,11 @@ int main(int argc, char *argv[])
 
       if(vec_C == NULL)
          ocas = svm_ocas_solver( C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method, 
-                                 &full_compute_W, &full_update_W, &full_add_new_cut, 
+                                 &full_compute_W, &update_W, &full_add_new_cut, 
                                  &full_compute_output, &qsort_data, &ocas_print, 0);
       else
          ocas = svm_ocas_solver_difC( vec_C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method, 
-                                      &full_compute_W, &full_update_W, &full_add_new_cut, 
+                                      &full_compute_W, &update_W, &full_add_new_cut, 
                                       &full_compute_output, &qsort_data, &ocas_print, 0);
 
     }
@@ -618,11 +619,11 @@ int main(int argc, char *argv[])
     {
       if(vec_C == NULL)
         ocas = svm_ocas_solver( C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method, 
-                                &full_compute_W, &full_update_W, &full_add_new_cut, 
+                                &full_compute_W, &update_W, &full_add_new_cut, 
                                 &full_compute_output, &qsort_data, &ocas_print_null, 0);
       else
         ocas = svm_ocas_solver_difC( vec_C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method, 
-                                     &full_compute_W, &full_update_W, &full_add_new_cut, 
+                                     &full_compute_W, &update_W, &full_add_new_cut, 
                                      &full_compute_output, &qsort_data, &ocas_print_null, 0);
 
     }
diff --git a/svmocas.m b/svmocas.m
index 963c99d..ae86f2d 100644
--- a/svmocas.m
+++ b/svmocas.m
@@ -1,28 +1,31 @@
-% SVMOCAS Train linear SVM classifier using OCAS solver.
+% SVMOCAS solver for training linear two-class SVM classifiers
 %
 % Synopsis:
-%  [W,W0,stat] = svmocas(X,X0,y,C,Method,TolRel,TolAbs,QPBound,BufSize,nExamples,MaxTime); 
+%  [W,W0,stat] = svmocas(X,X0,y,C,Method,TolRel,TolAbs,QPBound,BufSize,nExamples,MaxTime)
 % 
-%  [W,W0,stat] = svmocas(data_file,X0,C,Method,TolRel,TolAbs,QPBound,BufSize,nExamples,MaxTime); 
-%
 % Desription:
 %  This function trains linear SVM classifier by solving
 %
 %      W,W0 = argmin 0.5*(w'*w+w0^2) + C*sum max( 0, 1-y(i)*(w'*X(:,i)+w0*X0) )
 %              w,w0                  i=1:nExamples
 %
-%  The function accepts examples either in Matlab matrix X (both sparse and dense) and 
-%  a dense vector y or as path to a file in SVM^light format.
+%  The training examples are passed in the matrix X where each column is a single
+%  feature vector. The matrix X can be one of the following types
+%     dense double (default in Matlab)
+%     sparse double
+%     dense single 
+%     dense int8
+%  The labels of the training examples must be given as dense vector y whose length
+%  equals to the number of columns of the matrix X.
 %
 % Reference:
-%  V. Franc, S. Sonnenburg. OCAS optimized cutting plane algorithm for Support Vector 
-%    Machines. In Proceedings of ICML. Omnipress, 2008.
-%    http://ida.first.fraunhofer.de/~franc/papers/Franc-OCAS-ICML08.pdf
+%  V. Franc, S. Sonnenburg. Optimized Cutting Plane Algorithm for Large-scale Risk
+%  Minimization. Journal of Machine Learning Research. 2009
+%    http://jmlr.csail.mit.edu/papers/volume10/franc09a/franc09a.pdf
 %
 % Input:
-%   data_file [string] Training examples stored in SVM^light format.
-%
-%   X [nDim x nExamples] training inputs (sparse or dense matrix).
+%   X [nDim x nExamples] training inputs (dense double, sparse double, dense single, 
+%     dense int8 matrix).
 %   X0 [1x1] constant coordinate (implicitly) added to all examples;
 %     this allows training biased decision rule.
 %   y [nExamples x 1] labels (+1/-1).
@@ -45,22 +48,24 @@
 %   stat [struct] Optimizer statistics (field names are self-explaining).
 %
 % Example:
-%  % loading data directly from file in SVM^light format
-%  [W,W0,stat] = svmocas('./data/riply_trn.light',1,1);
+%  % train linear SVM classifier 
+%  libocasPath = fileparts(which('svmocas'));
+%  trn = load([libocasPath '/data/riply_trn.mat'],'X','y'); 
+%  svmC = 1;
+%  [W,W0,stat] = svmocas(trn.X,1,trn.y,svmC);
 %
-%  % using data loaded to Matlab
-%  load('./data/riply_trn','X','y');
-%  [W,W0,stat] = svmocas(X,1,y,1);
+%  % classify test examples
+%  tst = load([libocasPath '/data/riply_tst.mat'],'X','y');
+%  ypred = sign(W'*tst.X + W0);
 %
-%  % classification
-%  load('riply_tst','X','y');
-%  ypred = sign(W'*X + W0);
-%  sum(ypred ~= y)/length(y)
+%  % compute test classification error and area under ROC
+%  sum(ypred ~= tst.y)/length(tst.y)
+%  compute_auc(W'*tst.X + W0, tst.y)
 %
 
 %
-% Copyright (C) 2008, 2009 Vojtech Franc, xfrancv at cmp.felk.cvut.cz
-%                          Soeren Sonnenburg, soeren.sonnenburg at first.fraunhofer.de
+% Copyright (C) 2008, 2009, 2012 Vojtech Franc, xfrancv at cmp.felk.cvut.cz
+%                                Soeren Sonnenburg, soeren.sonnenburg at first.fraunhofer.de
 %
 % This program is free software; you can redistribute it and/or
 % modify it under the terms of the GNU General Public 
diff --git a/svmocas.mexa64 b/svmocas.mexa64
new file mode 100755
index 0000000..d854b06
Binary files /dev/null and b/svmocas.mexa64 differ
diff --git a/svmocas_lbp.mexa64 b/svmocas_lbp.mexa64
new file mode 100755
index 0000000..e39e4ae
Binary files /dev/null and b/svmocas_lbp.mexa64 differ
diff --git a/svmocas_lbp_mex.c b/svmocas_lbp_mex.c
index 0a6806a..68102a5 100644
--- a/svmocas_lbp_mex.c
+++ b/svmocas_lbp_mex.c
@@ -12,7 +12,7 @@
  *   height_of_pyramid [1 x 1 (double)]
  *   X0 [1 x 1 (double)]
  *   y [nExamples x 1 (double)] +1/-1
- *   C [1 x 1 (double)] OR [nExamples x 1 (double)]
+ *   C [1 x 1 (double)] 
  *   Method [1x1 (double)] 0 (BMRM) or 1 (OCAS)
  *   TolRel [1x1 (double)]
  *   TolAbs [1x1 (double)]
@@ -72,26 +72,27 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
   total_time = get_time();
   init_time = total_time;
 
-  if(nrhs < 8 || nrhs > 15)
+  if(nrhs < 8 || nrhs > 16)
      mexErrMsgTxt("Improper number of input arguments.\n\n"
                   "SVMOCAS_LBP train linear SVM classifier for images prepresented by LBP features. \n\n"
                   "Synopsis:\n"
                   "  [W,W0,stat]= svmocas_lbp(Images,imSize,Wins,winSize,height_of_pyramid,\n"
-                  "              X0,y,C,Method,TolRel,TolAbs,QPBound,BufSize,MaxTime,verb) \n\n"
+                  "              X0,y,C,Method,TolRel,TolAbs,QPBound,BufSize,nExamples,MaxTime,verb) \n\n"
                   "Input:  \n"
                   "  Images [(im_H*im_W) x nImages (uint8)]\n"
-                  "  imSize [2 x 1 (uint32)] imSize = [im_H im_W]\n"
-                  "  Wins [4 x nExamples (uint32)] [img_idx; topleft_col; topleft_row; mirror]\n"
-                  "  winSize [2 x 1 (uint32)] [win_H win_W]\n"
+                  "  imSize [2 x 1 (double)] imSize = [im_H im_W]\n"
+                  "  Wins [4 x nExamples (uint32)] [img_idx; topleft_col; topleft_row; mirror] 1-based\n"
+                  "  winSize [2 x 1 (double)] [win_H win_W]\n"
                   "  height_of_pyramid [1 x 1 (double)]\n"
                   "  X0 [1 x 1 (double)]\n"
                   "  y [nExamples x 1 (double)] +1 or -1\n"
-                  "  C [1 x 1 (double)] OR [nExamples x 1 (double)]\n"
+                  "  C [1 x 1 (double)]\n"
                   "  Method [1x1 (double)] 0 for BMRM; 1 for OCAS \n"
                   "  TolRel [1x1 (double)]\n"
                   "  TolAbs [1x1 (double)]\n"
                   "  QPBound [1x1 (double)]\n"
                   "  BufSize [1x1 (double)]\n"
+                  "  nExamples [1x1 (double) number of examples to use; (inf mens use all available)\n"
                   "  MaxTime [1x1 (double)]\n"
                   "  verb [1x1 (bouble)]\n\n"
                   "Output:\n"
@@ -114,7 +115,7 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
   im_H = (uint32_t)tmp[0];
   im_W = (uint32_t)tmp[1];
 
-  mexPrintf("im_h=%d  im_W=%d \n", im_H, im_W);
+/*  mexPrintf("im_h=%d  im_W=%d \n", im_H, im_W);*/
   if(mxGetM(prhs[0]) != im_H*im_W)
     mexErrMsgTxt("Dimension of Images does not match to im_H*im_W.");
 
@@ -129,7 +130,7 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
   nDim = liblbp_pyr_get_dim(win_H,win_W,nPyramids);
 
   croped_window = (uint32_t*)mxCalloc(win_H*win_W,sizeof(uint32_t));
-  if(croped_window == NULL) 
+  if(croped_window == NULL)
     mexErrMsgTxt("Not enough memory for croped_window.");
   
   X0 = mxGetScalar(prhs[5]);
@@ -157,13 +158,18 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
   }
 
   num_of_Cs = LIBOCAS_MAX(mxGetN(prhs[7]),mxGetM(prhs[7]));
+
   if(num_of_Cs == 1)
   {
     C = (double)mxGetScalar(prhs[7]);
   }
   else
   {
-    vec_C = (double*)mxGetPr(prhs[7]);
+/*    if(nData != num_of_Cs) */
+/*      mexErrMsgTxt("The number of examples does not much the length of the vector C.");*/
+    
+    mexErrMsgTxt("The argument C must be a scalar of type double.");
+/*    vec_C = (double*)mxGetPr(prhs[7]);*/
   }
 
   if(nrhs >= 9)
@@ -215,12 +221,13 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
   {
     mexPrintf("SVM setting:\n");
 
-    if( num_of_Cs == 1)
-      mexPrintf("   C              : %f\n", C);
-    else
-      mexPrintf("   C              : different for each example\n");
+/*    if( num_of_Cs == 1)*/
+/*      mexPrintf("   C              : %f\n", C);*/
+/*    else*/
+/*      mexPrintf("   C              : different for each example\n");*/
 
-    mexPrintf("   bias           : %.0f\n"
+    mexPrintf("   C              : %f\n"
+              "   bias           : %.0f\n"
               "   # of examples  : %d\n"
               "   solver         : %d\n"
               "   cache size     : %d\n"
@@ -229,7 +236,7 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
               "   QPValue        : %f\n"
               "   MaxTime        : %f [s]\n"
               "   verb           : %d\n",
-              X0, nData, Method,BufSize,TolAbs,TolRel, QPBound, MaxTime, verb);
+              C, X0, nData, Method,BufSize,TolAbs,TolRel, QPBound, MaxTime, verb);
   }
   
   /* learned weight vector */
@@ -252,11 +259,11 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
   if(new_a == NULL) 
     mexErrMsgTxt("Not enough memory for auxciliary cutting plane buffer new_a.");  
 
-  if(num_of_Cs > 1)
-  {
-    for(i=0; i < nData; i++) 
-      data_y[i] = data_y[i]*vec_C[i];
-  }
+/*  if(num_of_Cs > 1)*/
+/*  {*/
+/*    for(i=0; i < nData; i++) */
+/*      data_y[i] = data_y[i]*vec_C[i];*/
+/*  }*/
 
   /* !!!!!!!!!!!!
   ptr = mxGetPr(data_X);
@@ -291,25 +298,25 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
   {
     mexPrintf("Starting optimization:\n");
     
-    if(num_of_Cs == 1)
+/*    if(num_of_Cs == 1)*/
       ocas = svm_ocas_solver( C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method, 
                               &full_compute_W, &full_update_W, &full_add_new_cut, 
                               &full_compute_output, &qsort_data, &ocas_print, 0);
-    else
-      ocas = svm_ocas_solver_difC( vec_C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method, 
-                                   &full_compute_W, &full_update_W, &full_add_new_cut, 
-                                   &full_compute_output, &qsort_data, &ocas_print, 0);
+/*    else*/
+/*      ocas = svm_ocas_solver_difC( vec_C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method, */
+/*                                   &full_compute_W, &full_update_W, &full_add_new_cut, */
+/*                                   &full_compute_output, &qsort_data, &ocas_print, 0);*/
   }
   else
   {
-    if(num_of_Cs == 1)
+/*    if(num_of_Cs == 1)*/
       ocas = svm_ocas_solver( C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method, 
                               &full_compute_W, &full_update_W, &full_add_new_cut, 
                               &full_compute_output, &qsort_data, &ocas_print_null, 0);
-    else
-      ocas = svm_ocas_solver_difC( vec_C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method, 
-                                   &full_compute_W, &full_update_W, &full_add_new_cut, 
-                                   &full_compute_output, &qsort_data, &ocas_print_null, 0);
+/*    else*/
+/*      ocas = svm_ocas_solver_difC( vec_C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method, */
+/*                                   &full_compute_W, &full_update_W, &full_add_new_cut, */
+/*                                   &full_compute_output, &qsort_data, &ocas_print_null, 0);*/
   }
 
 
@@ -346,11 +353,11 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
     mexPrintf("Training error: %.4f%%\n", 100*(double)ocas.trn_err/(double)nData);
   }
 
-  if(num_of_Cs > 1)
-  {
-    for(i=0; i < nData; i++) 
-      data_y[i] = data_y[i]/vec_C[i];
-  }
+/*  if(num_of_Cs > 1)*/
+/*  {*/
+/*    for(i=0; i < nData; i++) */
+/*      data_y[i] = data_y[i]/vec_C[i];*/
+/*  }*/
 
   plhs[1] = mxCreateDoubleScalar( W0 );
   
diff --git a/svmocas.m b/svmocas_light.m
similarity index 57%
copy from svmocas.m
copy to svmocas_light.m
index 963c99d..6848525 100644
--- a/svmocas.m
+++ b/svmocas_light.m
@@ -1,9 +1,7 @@
-% SVMOCAS Train linear SVM classifier using OCAS solver.
+% SVMOCAS OCAS solver for training linear SVM classifier from SVM^light file.
 %
 % Synopsis:
-%  [W,W0,stat] = svmocas(X,X0,y,C,Method,TolRel,TolAbs,QPBound,BufSize,nExamples,MaxTime); 
-% 
-%  [W,W0,stat] = svmocas(data_file,X0,C,Method,TolRel,TolAbs,QPBound,BufSize,nExamples,MaxTime); 
+%  [W,W0,stat] = svmocas(dataFile,X0,C,Method,TolRel,TolAbs,QPBound,BufSize,nExamples,MaxTime); 
 %
 % Desription:
 %  This function trains linear SVM classifier by solving
@@ -11,18 +9,15 @@
 %      W,W0 = argmin 0.5*(w'*w+w0^2) + C*sum max( 0, 1-y(i)*(w'*X(:,i)+w0*X0) )
 %              w,w0                  i=1:nExamples
 %
-%  The function accepts examples either in Matlab matrix X (both sparse and dense) and 
-%  a dense vector y or as path to a file in SVM^light format.
+%  The function loads examples from dataFile in SVM^light format.
 %
 % Reference:
-%  V. Franc, S. Sonnenburg. OCAS optimized cutting plane algorithm for Support Vector 
-%    Machines. In Proceedings of ICML. Omnipress, 2008.
-%    http://ida.first.fraunhofer.de/~franc/papers/Franc-OCAS-ICML08.pdf
+%  V. Franc, S. Sonnenburg. Optimized Cutting Plane Algorithm for Large-scale Risk
+%  Minimization. Journal of Machine Learning Research. 2009
+%    http://jmlr.csail.mit.edu/papers/volume10/franc09a/franc09a.pdf
 %
 % Input:
-%   data_file [string] Training examples stored in SVM^light format.
-%
-%   X [nDim x nExamples] training inputs (sparse or dense matrix).
+%   dataFile [string] Training examples stored in SVM^light format.
 %   X0 [1x1] constant coordinate (implicitly) added to all examples;
 %     this allows training biased decision rule.
 %   y [nExamples x 1] labels (+1/-1).
@@ -45,22 +40,20 @@
 %   stat [struct] Optimizer statistics (field names are self-explaining).
 %
 % Example:
-%  % loading data directly from file in SVM^light format
-%  [W,W0,stat] = svmocas('./data/riply_trn.light',1,1);
-%
-%  % using data loaded to Matlab
-%  load('./data/riply_trn','X','y');
-%  [W,W0,stat] = svmocas(X,1,y,1);
+%  % training   
+%  libocasPath = fileparts(which('svmocas'));
+%  svmC = 1;
+%  [W,W0,stat] = svmocas_light([libocasPath '/data/riply_trn.light'],1,svmC);
 %
-%  % classification
-%  load('riply_tst','X','y');
-%  ypred = sign(W'*X + W0);
-%  sum(ypred ~= y)/length(y)
+%  % classification 
+%  [score,trueLabels] = linclassif_light([libocasPath '/data/riply_tst.light'],W,W0);
+%  ypred = sign(score);
+%  sum(ypred~=trueLabels)/length(trueLabels)
 %
 
 %
-% Copyright (C) 2008, 2009 Vojtech Franc, xfrancv at cmp.felk.cvut.cz
-%                          Soeren Sonnenburg, soeren.sonnenburg at first.fraunhofer.de
+% Copyright (C) 2008, 2009, 2012 Vojtech Franc, xfrancv at cmp.felk.cvut.cz
+%               Soeren Sonnenburg, soeren.sonnenburg at first.fraunhofer.de
 %
 % This program is free software; you can redistribute it and/or
 % modify it under the terms of the GNU General Public 
diff --git a/svmocas_light.mexa64 b/svmocas_light.mexa64
new file mode 100755
index 0000000..f62cee8
Binary files /dev/null and b/svmocas_light.mexa64 differ
diff --git a/svmocas_lbp_mex.c b/svmocas_light_mex.c
similarity index 51%
copy from svmocas_lbp_mex.c
copy to svmocas_light_mex.c
index 0a6806a..f6760bb 100644
--- a/svmocas_lbp_mex.c
+++ b/svmocas_light_mex.c
@@ -1,37 +1,20 @@
 /*=================================================================================
- * SVMOCAS_LBP Train linear SVM classifier for images represented by LBP features. 
- * 
+ * svmocas_light_mex.c: Matlab MEX interface to OCAS solver training two-class 
+ *                      linear SVM classifier from examples in SVM^light file.
+ *
  * Synopsis:
- *  [W,W0,stat]= svmocas_lbp(Images,imSize,Wins,winSize,height_of_pyramid,X0,y,C,Method,TolRel,TolAbs,QPBound,BufSize,MaxTime,verb) 
+ *  [W,W0,stat] = svmocas_light(data_file,X0,C,Method,TolRel,TolAbs,QPBound,BufSize,
+ *                              nData,MaxTime,verb)
  *
- * Input:  
- *   Images [(im_H*im_W) x nImages (uint8)]
- *   imSize [2 x 1 (uint32)] imSize = [im_H im_W]
- *   Wins [4 x nExamples (uint32)]  [image_idx; top_left_col; top_left_row; mirror]
- *   winSize [2 x 1 (uint32)] [win_H win_W]
- *   height_of_pyramid [1 x 1 (double)]
- *   X0 [1 x 1 (double)]
- *   y [nExamples x 1 (double)] +1/-1
- *   C [1 x 1 (double)] OR [nExamples x 1 (double)]
- *   Method [1x1 (double)] 0 (BMRM) or 1 (OCAS)
- *   TolRel [1x1 (double)]
- *   TolAbs [1x1 (double)]
- *   QPBound [1x1 (double)]
- *   BufSize [1x1 (double)]
- *   MaxTime [1x1 (double)]
- *   verb [1x1 (bouble)]
- * Output:
- *   W [nDim x 1] Parameter vector
- *   W0 [1x1] Bias term
- *   stat [struct] 
+ * See svmocas_light.m for more help.
  *
- * Copyright (C) 2008, 2009, 2010 Vojtech Franc, xfrancv at cmp.felk.cvut.cz
- *                                Soeren Sonnenburg, soeren.sonnenburg at first.fraunhofer.de
+ * Copyright (C) 2008, 2009, 2012 Vojtech Franc, xfrancv at cmp.felk.cvut.cz
+ *                          Soeren Sonnenburg, soeren.sonnenburg at first.fraunhofer.de
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public 
  * License as published by the Free Software Foundation; 
- *======================================================================================*/ 
+ *===================================================================================*/ 
 
 #include <stdio.h>
 #include <string.h>
@@ -39,14 +22,14 @@
 #include <mex.h>
 
 #include "libocas.h"
-#include "ocas_lbp_helper.h"
-#include "liblbp.h"
+#include "ocas_helper.h"
+#include "features_double.h"
 
 #define DEFAULT_METHOD 1
 #define DEFAULT_TOLREL 0.01
 #define DEFAULT_TOLABS 0.0
 #define DEFAULT_QPVALUE 0.0
-#define DEFAULT_BUFSIZE 500
+#define DEFAULT_BUFSIZE 2000
 #define DEFAULT_MAXTIME mxGetInf()
 #define DEFAULT_VERB 1
 
@@ -58,12 +41,12 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
 {
   double C, TolRel, TolAbs, QPBound, trn_err, MaxTime;
   double *vec_C;   
+  double *ptr;
   uint32_t num_of_Cs;
   uint32_t i, j, BufSize;
   uint16_t Method;
   int verb;
   ocas_return_value_T ocas;
-  double *tmp;
 
   /* timing variables */
   double init_time;
@@ -72,26 +55,21 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
   total_time = get_time();
   init_time = total_time;
 
-  if(nrhs < 8 || nrhs > 15)
+  if(nrhs < 3 || nrhs > 11)
      mexErrMsgTxt("Improper number of input arguments.\n\n"
-                  "SVMOCAS_LBP train linear SVM classifier for images prepresented by LBP features. \n\n"
+                  "SVMOCAS_LIGHT train two-class linear SVM classifier from examples in SVM^light file\n\n"
                   "Synopsis:\n"
-                  "  [W,W0,stat]= svmocas_lbp(Images,imSize,Wins,winSize,height_of_pyramid,\n"
-                  "              X0,y,C,Method,TolRel,TolAbs,QPBound,BufSize,MaxTime,verb) \n\n"
+                  "  [W,W0,stat] = svmocas_light(dataFile,X0,C,Method,TolRel,TolAbs,QPBound,BufSize,nExamples,MaxTime) \n\n"
                   "Input:  \n"
-                  "  Images [(im_H*im_W) x nImages (uint8)]\n"
-                  "  imSize [2 x 1 (uint32)] imSize = [im_H im_W]\n"
-                  "  Wins [4 x nExamples (uint32)] [img_idx; topleft_col; topleft_row; mirror]\n"
-                  "  winSize [2 x 1 (uint32)] [win_H win_W]\n"
-                  "  height_of_pyramid [1 x 1 (double)]\n"
-                  "  X0 [1 x 1 (double)]\n"
-                  "  y [nExamples x 1 (double)] +1 or -1\n"
-                  "  C [1 x 1 (double)] OR [nExamples x 1 (double)]\n"
+                  "  dataFile [string] path to file with training examples in SVM^light format\n"
+                  "  X0 [1 x 1 (double)] constant feature added to all examples\n"
+                  "  C [1x1]  or [nExamples x 1] regularization constant(s) \n"
                   "  Method [1x1 (double)] 0 for BMRM; 1 for OCAS \n"
                   "  TolRel [1x1 (double)]\n"
                   "  TolAbs [1x1 (double)]\n"
                   "  QPBound [1x1 (double)]\n"
                   "  BufSize [1x1 (double)]\n"
+                  "  nExamples [1x1 (double) number of examples to use; (inf means use all examples)\n"
                   "  MaxTime [1x1 (double)]\n"
                   "  verb [1x1 (bouble)]\n\n"
                   "Output:\n"
@@ -99,112 +77,84 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
                   "  W0 [1x1] Bias term\n"
                   "  stat [struct] \n");
 
-  /*                             0      1     2     3         4     5  6 7   8      9      10      11     12     13       14     15*/
-  /*  [W,W0,stat]= svmocas_lbp(Images,imSize,Wins,winSize,nPyramids,X0,y,C,Method,TolRel,TolAbs,QPBound,BufSize,nExamples,MaxTime,verb) */
+  char *fname;
+  int fname_len;
 
-  if(nrhs >= 16)
-    verb = (int)mxGetScalar(prhs[15]);
+  if(nrhs >= 11)
+    verb = (int)mxGetScalar(prhs[10]);
   else
     verb = DEFAULT_VERB;
 
-  Images = (uint8_t*)mxGetPr(prhs[0]);
-  nImages = mxGetN(prhs[0]);
-
-  tmp = (double*)mxGetPr(prhs[1]);
-  im_H = (uint32_t)tmp[0];
-  im_W = (uint32_t)tmp[1];
+  if(!mxIsChar(prhs[0]))
+    mexErrMsgTxt("First input argument must be of type string.");
 
-  mexPrintf("im_h=%d  im_W=%d \n", im_H, im_W);
-  if(mxGetM(prhs[0]) != im_H*im_W)
-    mexErrMsgTxt("Dimension of Images does not match to im_H*im_W.");
+  fname_len = mxGetNumberOfElements(prhs[0]) + 1;   
+  fname = mxCalloc(fname_len, sizeof(char));    
 
-  Wins = (uint32_t*)mxGetPr(prhs[2]);
+  if (mxGetString(prhs[0], fname, fname_len) != 0)     
+    mexErrMsgTxt("Could not convert first input argument to string.");
 
-  tmp = (double*)mxGetPr(prhs[3]);
-  win_H = (uint32_t)tmp[0];
-  win_W = (uint32_t)tmp[1];
+  if( load_svmlight_file(fname,verb) == -1 || data_X == NULL || data_y == NULL)
+    mexErrMsgTxt("Cannot load input file.");
 
-  nPyramids = (uint32_t)mxGetScalar(prhs[4]);
-/*  nDim = lbppyr_get_dim(win_H,win_W,nPyramids);*/
-  nDim = liblbp_pyr_get_dim(win_H,win_W,nPyramids);
-
-  croped_window = (uint32_t*)mxCalloc(win_H*win_W,sizeof(uint32_t));
-  if(croped_window == NULL) 
-    mexErrMsgTxt("Not enough memory for croped_window.");
-  
-  X0 = mxGetScalar(prhs[5]);
-  data_y = (double*)mxGetPr(prhs[6]);
-
-  nData = LIBOCAS_MAX(mxGetM(prhs[6]),mxGetN(prhs[6]));
-  if(nData != mxGetN(prhs[2]))
-    mexErrMsgTxt("Dimension missmatch betwenn Wins and y.");
-
-  if(verb)
-  {
-    mexPrintf("Input data:\n"
-              "   # of images     : %d\n"
-              "   image height    : %d\n"
-              "   image width     : %d\n",
-              nImages, im_H, im_W);
-
-    mexPrintf("Feature represenation:\n"
-              "   base window height        : %d\n"
-              "   base window width         : %d\n"
-              "   nPyramids                 : %d\n"
-              "   # of virtual examples     : %d\n"
-              "   # of features per example : %d\n",
-              win_H, win_W, nPyramids, nData, nDim);
-  }
+  nDim = mxGetM(data_X);
+  X0 = mxGetScalar(prhs[1]);
 
-  num_of_Cs = LIBOCAS_MAX(mxGetN(prhs[7]),mxGetM(prhs[7]));
+  num_of_Cs = LIBOCAS_MAX(mxGetN(prhs[2]),mxGetM(prhs[2]));
   if(num_of_Cs == 1)
   {
-    C = (double)mxGetScalar(prhs[7]);
+    C = (double)mxGetScalar(prhs[2]);
   }
   else
   {
-    vec_C = (double*)mxGetPr(prhs[7]);
+    vec_C = (double*)mxGetPr(prhs[2]);
   }
 
-  if(nrhs >= 9)
-    Method = (uint32_t)mxGetScalar(prhs[8]);
+  if(verb)
+    mexPrintf("Input data statistics:\n"
+              "   # of examples  : %d\n"
+              "   dimensionality : %d\n"
+              "   density        : %.2f%%\n",
+              mxGetN(data_X), nDim, 100.0*(double)mxGetNzmax(data_X)/((double)nDim*(double)(mxGetN(data_X))));
+    
+  if(nrhs >= 4)
+    Method = (uint32_t)mxGetScalar(prhs[3]);
   else
     Method = DEFAULT_METHOD;
 
-  if(nrhs >= 10)
-    TolRel = (double)mxGetScalar(prhs[9]);
+  if(nrhs >= 5)
+    TolRel = (double)mxGetScalar(prhs[4]);
   else
     TolRel = DEFAULT_TOLREL;
-  
-  if(nrhs >= 11)    
-    TolAbs = (double)mxGetScalar(prhs[10]);
+
+  if(nrhs >= 6)
+    TolAbs = (double)mxGetScalar(prhs[5]);
   else
     TolAbs = DEFAULT_TOLABS;
 
-  if(nrhs >= 12)
-    QPBound = (double)mxGetScalar(prhs[11]);
+  if(nrhs >= 7)
+    QPBound = (double)mxGetScalar(prhs[6]);
   else
     QPBound = DEFAULT_QPVALUE;
 
-  if(nrhs >= 13)
-    BufSize = (uint32_t)mxGetScalar(prhs[12]);
+  if(nrhs >= 8)    
+    BufSize = (uint32_t)mxGetScalar(prhs[7]);
   else
     BufSize = DEFAULT_BUFSIZE;
 
-  if(num_of_Cs > 1 && num_of_Cs < nData)
-    mexErrMsgTxt("Length of the vector C less than the number of examples.");
+  if(nrhs >= 9 && mxIsInf(mxGetScalar(prhs[8])) == false) 
+    nData = (uint32_t)mxGetScalar(prhs[8]);
+  else
+    nData = mxGetN(data_X);
 
-  if(nrhs >= 14 && !mxIsInf(mxGetScalar(prhs[13])))
-  {
-    if((uint32_t)mxGetScalar(prhs[13]) < 0 || (uint32_t)mxGetScalar(prhs[13]) > nData)
-      mexErrMsgTxt("Improper number of examples; must be > 0 and < max number of virtual example.\n");
+  if(nData < 1 || nData > mxGetN(data_X)) 
+    mexErrMsgTxt("Improper value of argument nData.");
 
-    nData = (uint32_t)mxGetScalar(prhs[13]);
-    mexPrintf("   # of examples set to : %d\n",nData);
-  }
+  if(num_of_Cs > 1 && num_of_Cs < nData)
+    mexErrMsgTxt("Length of the vector C less than the number of examples.");
 
-  if(nrhs >= 15)
-    MaxTime = (double)mxGetScalar(prhs[14]);
+  if(nrhs >= 10)
+    MaxTime = (double)mxGetScalar(prhs[9]);
   else
     MaxTime = DEFAULT_MAXTIME;
 
@@ -213,7 +163,7 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
   -------------------------------------------------------------------*/
   if(verb)
   {
-    mexPrintf("SVM setting:\n");
+    mexPrintf("Setting:\n");
 
     if( num_of_Cs == 1)
       mexPrintf("   C              : %f\n", C);
@@ -232,6 +182,7 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
               X0, nData, Method,BufSize,TolAbs,TolRel, QPBound, MaxTime, verb);
   }
   
+  
   /* learned weight vector */
   plhs[0] = (mxArray*)mxCreateDoubleMatrix(nDim,1,mxREAL);
   W = (double*)mxGetPr(plhs[0]);
@@ -247,8 +198,7 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
   if(A0 == NULL) mexErrMsgTxt("Not enough memory for vector A0.");
 
   /* allocate buffer for computing cutting plane */
-/*  new_a = (double*)mxCalloc(nDim,sizeof(double));*/
-  new_a = mxCalloc(nDim,sizeof(new_a[0]));
+  new_a = (double*)mxCalloc(nDim,sizeof(double));
   if(new_a == NULL) 
     mexErrMsgTxt("Not enough memory for auxciliary cutting plane buffer new_a.");  
 
@@ -258,61 +208,87 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
       data_y[i] = data_y[i]*vec_C[i];
   }
 
-  /* !!!!!!!!!!!!
-  ptr = mxGetPr(data_X);
-  for(i=0; i < nData; i++) {
-    for(j=0; j < nDim; j++ ) {
-      ptr[LIBOCAS_INDEX(j,i,nDim)] = ptr[LIBOCAS_INDEX(j,i,nDim)]*data_y[i];
-    }
+
+  /* select function to print progress info */
+  void (*print_function)(ocas_return_value_T);
+  if(verb) 
+  {
+    mexPrintf("Starting optimization:\n");
+    print_function = &ocas_print;
+  }
+  else 
+  {
+    print_function = &ocas_print_null;
   }
-  */
 
-  /* init cutting plane buffer */
-/*  full_A = mxCalloc(BufSize*nDim,sizeof(double));*/
-  full_A = mxCalloc(BufSize*nDim,sizeof(full_A[0]));
-  if( full_A == NULL )
-    mexErrMsgTxt("Not enough memory for cutting plane buffer full_A."); 
 
+  if( mxIsSparse(data_X)== true ) {
 
-  if(verb)
-  {
-    mexPrintf("Memory occupancy:\n"
-             "   raw images         : %.2f MB\n" 
-             "   CP buffer          : %.2f MB\n"
-             "   parameter vector W : %.2f MB\n",
-              (double)nImages*im_H*im_W/(1024*1024),
-              (double)sizeof(full_A[0])*BufSize*nDim/(1024*1024), 
-              (double)sizeof(W[0])*nDim/(1024*1024));
-  }
+    /* for i=1:nData, X(:,i) = X(:,i)*y(i); end*/
+    for(i=0; i < nData; i++) 
+        mul_sparse_col(data_y[i], data_X, i);           
+  
 
-  init_time=get_time()-init_time;
+    /* init cutting plane buffer */
+    sparse_A.nz_dims = mxCalloc(BufSize,sizeof(uint32_t));
+    sparse_A.index = mxCalloc(BufSize,sizeof(sparse_A.index[0]));
+    sparse_A.value = mxCalloc(BufSize,sizeof(sparse_A.value[0]));
+    if(sparse_A.nz_dims == NULL || sparse_A.index == NULL || sparse_A.value == NULL) 
+      mexErrMsgTxt("Not enough memory for cutting plane buffer sparse_A.");  
 
-  if(verb)
-  {
-    mexPrintf("Starting optimization:\n");
+    init_time=get_time()-init_time;
     
     if(num_of_Cs == 1)
-      ocas = svm_ocas_solver( C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method, 
-                              &full_compute_W, &full_update_W, &full_add_new_cut, 
-                              &full_compute_output, &qsort_data, &ocas_print, 0);
+    {
+      ocas = svm_ocas_solver( C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, 
+                              Method, &sparse_compute_W, &update_W, 
+                              &sparse_add_new_cut, &sparse_compute_output, 
+                              &qsort_data, print_function, 0);
+    }  
     else
-      ocas = svm_ocas_solver_difC( vec_C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method, 
-                                   &full_compute_W, &full_update_W, &full_add_new_cut, 
-                                   &full_compute_output, &qsort_data, &ocas_print, 0);
+    {
+      ocas = svm_ocas_solver_difC( vec_C, nData, TolRel, TolAbs, QPBound, MaxTime,
+                                   BufSize, Method, &sparse_compute_W, 
+                                   &update_W, &sparse_add_new_cut, 
+                                   &sparse_compute_output, &qsort_data, 
+                                   print_function, 0);
+    }  
   }
   else
   {
+
+    ptr = mxGetPr(data_X);
+    for(i=0; i < nData; i++) {
+      for(j=0; j < nDim; j++ ) {
+        ptr[LIBOCAS_INDEX(j,i,nDim)] = ptr[LIBOCAS_INDEX(j,i,nDim)]*data_y[i];
+      }
+    }
+
+    /* init cutting plane buffer */
+    full_A = mxCalloc(BufSize*nDim,sizeof(double));
+    if( full_A == NULL )
+      mexErrMsgTxt("Not enough memory for cutting plane buffer full_A.");    
+
+    init_time=get_time()-init_time;
+   
     if(num_of_Cs == 1)
-      ocas = svm_ocas_solver( C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method, 
-                              &full_compute_W, &full_update_W, &full_add_new_cut, 
-                              &full_compute_output, &qsort_data, &ocas_print_null, 0);
+    {
+      ocas = svm_ocas_solver( C, nData, TolRel, TolAbs, QPBound, MaxTime, 
+                              BufSize, Method, 
+                              &full_compute_W, &update_W, &full_add_new_cut, 
+                              &full_compute_output, &qsort_data, 
+                              print_function, 0);
+    }
     else
-      ocas = svm_ocas_solver_difC( vec_C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method, 
-                                   &full_compute_W, &full_update_W, &full_add_new_cut, 
-                                   &full_compute_output, &qsort_data, &ocas_print_null, 0);
+    {
+      ocas = svm_ocas_solver_difC( vec_C, nData, TolRel, TolAbs, QPBound, MaxTime,
+                                   BufSize, Method, 
+                                   &full_compute_W, &update_W, &full_add_new_cut, 
+                                   &full_compute_output, &qsort_data, 
+                                   print_function, 0);
+    }
   }
 
-
   if(verb)
   {
     mexPrintf("Stopping condition: ");
@@ -321,7 +297,8 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
        case 1: mexPrintf("1-Q_D/Q_P <= TolRel(=%f) satisfied.\n", TolRel); break;
        case 2: mexPrintf("Q_P-Q_D <= TolAbs(=%f) satisfied.\n", TolAbs); break;
        case 3: mexPrintf("Q_P <= QPBound(=%f) satisfied.\n", QPBound); break;
-       case 4: mexPrintf("Optimization time (=%f) >= MaxTime(=%f).\n", ocas.ocas_time, MaxTime); break;
+       case 4: mexPrintf("Optimization time (=%f) >= MaxTime(=%f).\n", 
+                         ocas.ocas_time, MaxTime); break;
        case -1: mexPrintf("Has not converged!\n" ); break;
        case -2: mexPrintf("Not enough memory for the solver.\n" ); break;
     }
@@ -346,20 +323,18 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
     mexPrintf("Training error: %.4f%%\n", 100*(double)ocas.trn_err/(double)nData);
   }
 
-  if(num_of_Cs > 1)
-  {
-    for(i=0; i < nData; i++) 
-      data_y[i] = data_y[i]/vec_C[i];
-  }
+  mxDestroyArray( data_X );
 
   plhs[1] = mxCreateDoubleScalar( W0 );
   
+  /* return ocas optimizer statistics */
   const char *field_names[] = {"nTrnErrors","Q_P","Q_D","nIter","nCutPlanes","exitflag",
-                               "init_time","output_time","sort_time","qp_solver_time","add_time",
-                               "w_time","print_time","ocas_time","total_time"}; 
+                              "init_time","output_time","sort_time","qp_solver_time",
+                             "add_time","w_time","print_time","ocas_time","total_time"}; 
   mwSize dims[2] = {1,1};  
 
-  plhs[2] = mxCreateStructArray(2, dims, (sizeof(field_names)/sizeof(*field_names)), field_names);
+  plhs[2] = mxCreateStructArray(2, dims, (sizeof(field_names)/sizeof(*field_names)), 
+                                field_names);
   
   mxSetField(plhs[2],0,"nIter",mxCreateDoubleScalar((double)ocas.nIter));
   mxSetField(plhs[2],0,"nCutPlanes",mxCreateDoubleScalar((double)ocas.nCutPlanes));
diff --git a/svmocas_mex.c b/svmocas_mex.c
index 3e489b0..957d109 100644
--- a/svmocas_mex.c
+++ b/svmocas_mex.c
@@ -1,9 +1,10 @@
-/*=================================================================================
- * svmocas_mex.c: Matlab MEX interface for OCAS solver training the linear SVM classifiers.
+/*======================================================================================
+ * svmocas_mex.c: Matlab MEX interface to OCAS solver for training two-class 
+ *                linear SVM classifier
  *
  * Synopsis:
- *  [W,W0,stat] = svmocas(X,X0,y,C,Method,TolRel,TolAbs,QPBound,BufSize,nData,MaxTime,verb)
- *  [W,W0,stat] = svmocas(data_file,X0,C,Method,TolRel,TolAbs,QPBound,BufSize,nData,MaxTime,verb)
+ *  [W,W0,stat] = svmocas(X,X0,y,C,Method,TolRel,TolAbs,QPBound,BufSize,
+ *                        nData,MaxTime,verb)
  *
  * See svmocas.m for more help.
  *
@@ -13,7 +14,7 @@
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public 
  * License as published by the Free Software Foundation; 
- *======================================================================================*/ 
+ *=====================================================================================*/ 
 
 #include <stdio.h>
 #include <string.h>
@@ -22,6 +23,9 @@
 
 #include "libocas.h"
 #include "ocas_helper.h"
+#include "features_int8.h"
+#include "features_double.h"
+#include "features_single.h"
 
 #define DEFAULT_METHOD 1
 #define DEFAULT_TOLREL 0.01
@@ -39,11 +43,13 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
 {
   double C, TolRel, TolAbs, QPBound, trn_err, MaxTime;
   double *vec_C;   
-  double *ptr;
   uint32_t num_of_Cs;
   uint32_t i, j, BufSize;
   uint16_t Method;
   int verb;
+  double *ptr_double;
+  float *ptr_single;
+  int8_t *ptr_int8;
   ocas_return_value_T ocas;
 
   /* timing variables */
@@ -53,193 +59,132 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
   total_time = get_time();
   init_time = total_time;
 
-  if(nrhs < 1)
-    mexErrMsgTxt("Improper number of input arguments.");
-
-  /* get input arguments */ 
-  if(mxIsChar(prhs[0]) == false) 
+  if(nrhs < 4 || nrhs > 12)
+    mexErrMsgTxt("Improper number of input arguments.\n\n"
+                 "SVMOCAS solver for training two-class linear SVM classifiers\n\n"
+                 "Synopsis:\n"
+                 "  [W,W0,stat] = svmocas(X,X0,y,C,Method,TolRel,TolAbs,QPBound,"
+                 "BufSize,nExamples,MaxTime) \n\n"
+                 "Input:  \n"
+                 "  X [nDim x nExamples] training inputs (dense double or sparse double or dense single or dense int8)\n"
+                 "  X0 [1 x 1 (double)] constant feature added to all examples\n"
+                 "  y [nExamples x 1 (double)] labels of the examples (+1/-1)\n"
+                 "  C [1x1]  or [nExamples x 1] regularization constant(s) \n"
+                 "  Method [1x1 (double)] 0 for BMRM; 1 for OCAS \n"
+                 "  TolRel [1x1 (double)]\n"
+                 "  TolAbs [1x1 (double)]\n"
+                 "  QPBound [1x1 (double)]\n"
+                 "  BufSize [1x1 (double)]\n"
+                 "  nExamples [1x1 (double) number of examples to use; "
+                 "(inf means use all examples)\n"
+                 "  MaxTime [1x1 (double)]\n"
+                 "  verb [1x1 (bouble)]\n\n"
+                 "Output:\n"
+                 "  W [nDim x 1] Parameter vector\n"
+                 "  W0 [1x1] Bias term\n"
+                 "  stat [struct] \n");
+
+
+  if(nrhs >= 12)
+    verb = (int)mxGetScalar(prhs[11]);
+  else
+    verb = DEFAULT_VERB;
+
+  /* 1st input argument: training feature vectors */
+  data_X = (mxArray*)prhs[0];
+  if( (mxGetNumberOfDimensions(data_X) != 2) ||
+      !( ( mxIsDouble(data_X) && mxIsSparse(data_X)  ) ||
+         ( mxIsDouble(data_X) && !mxIsSparse(data_X) ) ||
+         ( mxIsSingle(data_X) && !mxIsSparse(data_X) ) ||
+         ( mxIsInt8(data_X)   && !mxIsSparse(data_X) ) ))
   {
-    /* [W,W0,stat] = svmocas_mex(X,X0,y,C,Method,TolRel,TolAbs,QPBound,BufSize,nData,MaxTime); */
-
-    if(nrhs < 4 || nrhs > 12)
-      mexErrMsgTxt("Improper number of input arguments.");
-
-    if(nrhs >= 12)
-      verb = (int)mxGetScalar(prhs[11]);
-    else
-      verb = DEFAULT_VERB;
-
-
-    data_X = (mxArray*)prhs[0];
-    if (!(mxIsDouble(data_X)))
-        mexErrMsgTxt("Input argument X must be of type double.");
-
-    if (mxGetNumberOfDimensions(data_X) != 2)
-        mexErrMsgTxt("Input argument X must be two dimensional");
+    mexErrMsgTxt("The first input argument must be two dimensional matrix of the following type:\n"
+		 "dense double or sparse double or dense single or dense int8 matrix.\n");
+  }
+  
+  /* 2nd  input argument: constant coordinate added to feature vectors */
+  X0 = (double)mxGetScalar(prhs[1]);
 
-    X0 = mxGetScalar(prhs[1]);
-    data_y = (double*)mxGetPr(prhs[2]);
+  /*3rd input argument: vector of labels */
+  if( !mxIsDouble(prhs[2]) || mxIsSparse(prhs[2]) )
+    mexErrMsgTxt("The third input argument must be dense vector of doubles.");
+  data_y = (double*)mxGetPr(prhs[2]);
 
-    if(LIBOCAS_MAX(mxGetM(prhs[2]),mxGetN(prhs[2])) != mxGetN(prhs[0]))
-      mexErrMsgTxt("Length of vector y must equl to the number of columns of matrix X.");
+  if(LIBOCAS_MAX(mxGetM(prhs[2]),mxGetN(prhs[2])) != mxGetN(prhs[0]))
+    mexErrMsgTxt("Length of vector y (3rd input argument) must equl to the number of columns of matrix X (1st input argument).");
 
-    nDim = mxGetM(prhs[0]);
+  nDim = mxGetM(prhs[0]);
 
-    if(verb)
-    {
-      mexPrintf("Input data statistics:\n"
-                "   # of examples  : %d\n"
-                "   dimensionality : %d\n",
-                mxGetN(data_X), nDim);
+  if(verb)
+  {
+    mexPrintf("Input data statistics:\n"
+              "   # of examples  : %d\n"
+              "   dimensionality : %d\n",
+              mxGetN(data_X), nDim);
     
-      if( mxIsSparse(data_X)== true ) 
-        mexPrintf("   density        : %.2f%%\n",
-                  100.0*(double)mxGetNzmax(data_X)/((double)nDim*(double)(mxGetN(data_X))));
-      else
-        mexPrintf("   density        : 100%% (full)\n");
-    }
-
-
-    num_of_Cs = LIBOCAS_MAX(mxGetN(prhs[3]),mxGetM(prhs[3]));
-    if(num_of_Cs == 1)
-    {
-       C = (double)mxGetScalar(prhs[3]);
-    }
-    else
-    {
-       vec_C = (double*)mxGetPr(prhs[3]);
-    }
-
-    if(nrhs >= 5)
-      Method = (uint32_t)mxGetScalar(prhs[4]);
-    else
-      Method = DEFAULT_METHOD;
-
-    if(nrhs >= 6)
-      TolRel = (double)mxGetScalar(prhs[5]);
-    else
-      TolRel = DEFAULT_TOLREL;
-
-    if(nrhs >= 7)    
-      TolAbs = (double)mxGetScalar(prhs[6]);
-    else
-      TolAbs = DEFAULT_TOLABS;
-
-    if(nrhs >= 8)
-      QPBound = (double)mxGetScalar(prhs[7]);
+    if( mxIsSparse(data_X)== true ) 
+      mexPrintf("   sparse features (density=%.2f%%) ",
+               100.0*(double)mxGetNzmax(data_X)/((double)nDim*(double)(mxGetN(data_X))));
     else
-      QPBound = DEFAULT_QPVALUE;
-
-    if(nrhs >= 9)
-      BufSize = (uint32_t)mxGetScalar(prhs[8]);
-    else
-      BufSize = DEFAULT_BUFSIZE;
-
-    if(nrhs >= 10 && mxIsInf(mxGetScalar(prhs[9])) == false)
-      nData = (uint32_t)mxGetScalar(prhs[9]);
-    else
-      nData = mxGetN(data_X);
-      
-    if(nData < 1 || nData > mxGetN(prhs[0])) 
-      mexErrMsgTxt("Improper value of argument nData.");
-
-    if(num_of_Cs > 1 && num_of_Cs < nData)
-      mexErrMsgTxt("Length of the vector C less than the number of examples.");
+      mexPrintf("   dense features ");
+    if( mxIsDouble(data_X) )
+      mexPrintf("in double precision\n");
+    if( mxIsSingle(data_X) )
+      mexPrintf("in single precision\n");
+    if( mxIsInt8(data_X) )
+      mexPrintf("represented as int8\n");
+  }
 
-    if(nrhs >= 11)
-      MaxTime = (double)mxGetScalar(prhs[10]);
-    else
-      MaxTime = DEFAULT_MAXTIME;
-  } 
+  num_of_Cs = LIBOCAS_MAX(mxGetN(prhs[3]),mxGetM(prhs[3]));
+  if(num_of_Cs == 1)
+  {
+     C = (double)mxGetScalar(prhs[3]);
+  }
   else
   {
-    /* [W,W0,stat] = svmocas_mex(svmlight_data_file,X0,C,Method,TolRel,TolAbs,QPBound,BufSize,nData,MaxTime); */
-    char *fname;
-    int fname_len;
-
-    if(nrhs < 3 || nrhs > 11)
-      mexErrMsgTxt("Improper number of input arguments.");
-
-    if(nrhs >= 11)
-      verb = (int)mxGetScalar(prhs[10]);
-    else
-      verb = DEFAULT_VERB;
-
-    if(!mxIsChar(prhs[0]))
-      mexErrMsgTxt("First input argument must be of type string.");
-
-    fname_len = mxGetNumberOfElements(prhs[0]) + 1;   
-    fname = mxCalloc(fname_len, sizeof(char));    
-
-    if (mxGetString(prhs[0], fname, fname_len) != 0)     
-      mexErrMsgTxt("Could not convert first input argument to string.");
-
-    if( load_svmlight_file(fname,verb) == -1 || data_X == NULL || data_y == NULL)
-      mexErrMsgTxt("Cannot load input file.");
-
-    nDim = mxGetM(data_X);
-    X0 = mxGetScalar(prhs[1]);
-
-/*    C = (double)mxGetScalar(prhs[2]);*/
-    num_of_Cs = LIBOCAS_MAX(mxGetN(prhs[2]),mxGetM(prhs[2]));
-    if(num_of_Cs == 1)
-    {
-       C = (double)mxGetScalar(prhs[2]);
-    }
-    else
-    {
-       vec_C = (double*)mxGetPr(prhs[2]);
-    }
-
-    if(verb)
-      mexPrintf("Input data statistics:\n"
-                "   # of examples  : %d\n"
-                "   dimensionality : %d\n"
-                "   density        : %.2f%%\n",
-                mxGetN(data_X), nDim, 100.0*(double)mxGetNzmax(data_X)/((double)nDim*(double)(mxGetN(data_X))));
-    
-    if(nrhs >= 4)
-      Method = (uint32_t)mxGetScalar(prhs[3]);
-    else
-      Method = DEFAULT_METHOD;
-
-    if(nrhs >= 5)
-      TolRel = (double)mxGetScalar(prhs[4]);
-    else
-      TolRel = DEFAULT_TOLREL;
+     vec_C = (double*)mxGetPr(prhs[3]);
+  }
 
-    if(nrhs >= 6)
-      TolAbs = (double)mxGetScalar(prhs[5]);
-    else
-      TolAbs = DEFAULT_TOLABS;
+  if(nrhs >= 5)
+    Method = (uint32_t)mxGetScalar(prhs[4]);
+  else
+    Method = DEFAULT_METHOD;
 
-    if(nrhs >= 7)
-      QPBound = (double)mxGetScalar(prhs[6]);
-    else
-      QPBound = DEFAULT_QPVALUE;
+  if(nrhs >= 6)
+    TolRel = (double)mxGetScalar(prhs[5]);
+  else
+    TolRel = DEFAULT_TOLREL;
 
-    if(nrhs >= 8)    
-      BufSize = (uint32_t)mxGetScalar(prhs[7]);
-    else
-      BufSize = DEFAULT_BUFSIZE;
+  if(nrhs >= 7)    
+    TolAbs = (double)mxGetScalar(prhs[6]);
+  else
+    TolAbs = DEFAULT_TOLABS;
 
-    if(nrhs >= 9 && mxIsInf(mxGetScalar(prhs[8])) == false) 
-      nData = (uint32_t)mxGetScalar(prhs[8]);
-    else
-      nData = mxGetN(data_X);
+  if(nrhs >= 8)
+    QPBound = (double)mxGetScalar(prhs[7]);
+  else
+    QPBound = DEFAULT_QPVALUE;
 
-    if(nData < 1 || nData > mxGetN(data_X)) 
-      mexErrMsgTxt("Improper value of argument nData.");
+  if(nrhs >= 9)
+    BufSize = (uint32_t)mxGetScalar(prhs[8]);
+  else
+    BufSize = DEFAULT_BUFSIZE;
 
-    if(num_of_Cs > 1 && num_of_Cs < nData)
-      mexErrMsgTxt("Length of the vector C less than the number of examples.");
+  if(nrhs >= 10 && mxIsInf(mxGetScalar(prhs[9])) == false)
+    nData = (uint32_t)mxGetScalar(prhs[9]);
+  else
+    nData = mxGetN(data_X);
+      
+  if(nData < 1 || nData > mxGetN(prhs[0])) 
+    mexErrMsgTxt("Improper value of argument nData.");
 
-    if(nrhs >= 10)
-      MaxTime = (double)mxGetScalar(prhs[9]);
-    else
-      MaxTime = DEFAULT_MAXTIME;
+  if(num_of_Cs > 1 && num_of_Cs < nData)
+    mexErrMsgTxt("Length of the vector C less than the number of examples.");
 
-  } 
+  if(nrhs >= 11)
+    MaxTime = (double)mxGetScalar(prhs[10]);
+  else
+    MaxTime = DEFAULT_MAXTIME;
 
 
   /*----------------------------------------------------------------
@@ -285,15 +230,26 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
   if(new_a == NULL) 
     mexErrMsgTxt("Not enough memory for auxciliary cutting plane buffer new_a.");  
 
-
   if(num_of_Cs > 1)
   {
     for(i=0; i < nData; i++) 
       data_y[i] = data_y[i]*vec_C[i];
   }
 
+  /* select function to print progress info */
+  void (*print_function)(ocas_return_value_T);
+  if(verb) 
+  {
+    mexPrintf("Starting optimization:\n");
+    print_function = &ocas_print;
+  }
+  else 
+  {
+    print_function = &ocas_print_null;
+  }
 
-  if( mxIsSparse(data_X)== true ) {
+  if( mxIsSparse(data_X)== true ) 
+  {
 
     /* for i=1:nData, X(:,i) = X(:,i)*y(i); end*/
     for(i=0; i < nData; i++) 
@@ -309,85 +265,96 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
 
     init_time=get_time()-init_time;
 
-    if(verb)
-    {
-      mexPrintf("Starting optimization:\n");
-
-      if(num_of_Cs == 1)
-      {
-        ocas = svm_ocas_solver( C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method, 
-                              &sparse_compute_W, &sparse_update_W, &sparse_add_new_cut, 
-                              &sparse_compute_output, &qsort_data, &ocas_print, 0);
-      }  
-      else
-      {
-        ocas = svm_ocas_solver_difC( vec_C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method, 
-                                     &sparse_compute_W, &sparse_update_W, &sparse_add_new_cut, 
-                                     &sparse_compute_output, &qsort_data, &ocas_print, 0);
-      }  
 
-    }
+    if(num_of_Cs == 1)
+    {
+      ocas = svm_ocas_solver( C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method, 
+                              &sparse_compute_W, &update_W, &sparse_add_new_cut, 
+                              &sparse_compute_output, &qsort_data, 
+                              print_function, 0);
+    }  
     else
     {
-      if(num_of_Cs == 1)
-      {
-        ocas = svm_ocas_solver( C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method, 
-                              &sparse_compute_W, &sparse_update_W, &sparse_add_new_cut, 
-                              &sparse_compute_output, &qsort_data, &ocas_print_null, 0);
-      }
-      else
-      {
-        ocas = svm_ocas_solver_difC( vec_C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method, 
-                              &sparse_compute_W, &sparse_update_W, &sparse_add_new_cut, 
-                              &sparse_compute_output, &qsort_data, &ocas_print_null, 0);
-      }
-    }
+      ocas = svm_ocas_solver_difC( vec_C, nData, TolRel, TolAbs, QPBound, 
+                                   MaxTime,BufSize, Method, 
+                                   &sparse_compute_W, &update_W, 
+                                   &sparse_add_new_cut, &sparse_compute_output, 
+                                   &qsort_data, print_function, 0);
+    }  
 
   }
   else
   {
 
-    ptr = mxGetPr(data_X);
-    for(i=0; i < nData; i++) {
-      for(j=0; j < nDim; j++ ) {
-        ptr[LIBOCAS_INDEX(j,i,nDim)] = ptr[LIBOCAS_INDEX(j,i,nDim)]*data_y[i];
+    int (*add_new_cut)(double*, uint32_t*, uint32_t, uint32_t, void*);
+    int (*compute_output)( double*, void* );    
+    
+    /* features in double precision */
+    if( mxIsDouble(data_X) )
+    {
+      ptr_double = mxGetPr(data_X);
+      for(i=0; i < nData; i++) {
+	for(j=0; j < nDim; j++ ) {
+	  ptr_double[LIBOCAS_INDEX(j,i,nDim)] = ptr_double[LIBOCAS_INDEX(j,i,nDim)]*data_y[i];
+	}
       }
+      
+      add_new_cut = &full_add_new_cut;
+      compute_output = &full_compute_output;
     }
 
+    /* features in single precision */
+    if( mxIsSingle(data_X) )
+    {
+      ptr_single = (float*)mxGetPr(data_X);
+      for(i=0; i < nData; i++) {
+	for(j=0; j < nDim; j++ ) {
+	  ptr_single[LIBOCAS_INDEX(j,i,nDim)] = ptr_single[LIBOCAS_INDEX(j,i,nDim)]*data_y[i];
+	}
+      }
+      
+      add_new_cut = &full_single_add_new_cut;
+      compute_output = &full_single_compute_output;
+    }
+    
+    /* features in int8  */
+    if( mxIsInt8(data_X) )
+    {
+      ptr_int8 = (int8_t*)mxGetPr(data_X);
+      for(i=0; i < nData; i++) {
+	for(j=0; j < nDim; j++ ) {
+	  ptr_int8[LIBOCAS_INDEX(j,i,nDim)] = ptr_int8[LIBOCAS_INDEX(j,i,nDim)]/(int8_t)data_y[i];
+	}
+      }
+      
+      add_new_cut = &full_int8_add_new_cut;
+      compute_output = &full_int8_compute_output;
+    }    
+
     /* init cutting plane buffer */
     full_A = mxCalloc(BufSize*nDim,sizeof(double));
     if( full_A == NULL )
       mexErrMsgTxt("Not enough memory for cutting plane buffer full_A.");    
 
     init_time=get_time()-init_time;
-
-    if(verb)
-    {
-      mexPrintf("Starting optimization:\n");
     
-      if(num_of_Cs == 1)
-        ocas = svm_ocas_solver( C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method, 
-                                &full_compute_W, &full_update_W, &full_add_new_cut, 
-                                &full_compute_output, &qsort_data, &ocas_print, 0);
-      else
-        ocas = svm_ocas_solver_difC( vec_C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method, 
-                                &full_compute_W, &full_update_W, &full_add_new_cut, 
-                                &full_compute_output, &qsort_data, &ocas_print, 0);
-
+    if(num_of_Cs == 1)
+    {
+      ocas = svm_ocas_solver( C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method, 
+                              &full_compute_W, &update_W, add_new_cut, 
+                              compute_output, &qsort_data, print_function, 0);
     }
     else
     {
-      if(num_of_Cs == 1)
-        ocas = svm_ocas_solver( C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method, 
-                                &full_compute_W, &full_update_W, &full_add_new_cut, 
-                                &full_compute_output, &qsort_data, &ocas_print_null, 0);
-      else
-        ocas = svm_ocas_solver_difC( vec_C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method, 
-                                     &full_compute_W, &full_update_W, &full_add_new_cut, 
-                                     &full_compute_output, &qsort_data, &ocas_print_null, 0);
+      ocas = svm_ocas_solver_difC( vec_C, nData, TolRel, TolAbs, QPBound, MaxTime,
+                                   BufSize, Method, 
+                                   &full_compute_W, &update_W, add_new_cut, 
+                                   compute_output, &qsort_data, print_function, 0);
     }
   }
 
+  total_time=get_time()-total_time;
+
   if(verb)
   {
     mexPrintf("Stopping condition: ");
@@ -396,15 +363,12 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
        case 1: mexPrintf("1-Q_D/Q_P <= TolRel(=%f) satisfied.\n", TolRel); break;
        case 2: mexPrintf("Q_P-Q_D <= TolAbs(=%f) satisfied.\n", TolAbs); break;
        case 3: mexPrintf("Q_P <= QPBound(=%f) satisfied.\n", QPBound); break;
-       case 4: mexPrintf("Optimization time (=%f) >= MaxTime(=%f).\n", ocas.ocas_time, MaxTime); break;
+       case 4: mexPrintf("Optimization time (=%f) >= MaxTime(=%f).\n", 
+                          ocas.ocas_time, MaxTime); break;
        case -1: mexPrintf("Has not converged!\n" ); break;
        case -2: mexPrintf("Not enough memory for the solver.\n" ); break;
     }
-  }
 
-  total_time=get_time()-total_time;
-  if(verb)
-  {
     mexPrintf("Timing statistics:\n"
               "   init_time      : %f[s]\n"
               "   qp_solver_time : %f[s]\n"
@@ -421,8 +385,9 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
     mexPrintf("Training error: %.4f%%\n", 100*(double)ocas.trn_err/(double)nData);
   }
 
-  /* multiply data ba labels as it was at the begining */
-  if( mxIsSparse(data_X)== true ) {
+  /* multiply data by labels as it was at the begining */
+  if( mxIsSparse(data_X)== true ) 
+  {
     /* for i=1:nData, X(:,i) = X(:,i)*y(i); end*/
     for(i=0; i < nData; i++) 
     {
@@ -431,42 +396,59 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
   }
   else
   {
-    ptr = mxGetPr(data_X);
-    for(i=0; i < nData; i++) {
-      for(j=0; j < nDim; j++ ) {
-        ptr[LIBOCAS_INDEX(j,i,nDim)] = ptr[LIBOCAS_INDEX(j,i,nDim)]/data_y[i];
+    
+    /* features in double precision */
+    if( mxIsDouble(data_X) )
+    {    
+      ptr_double = mxGetPr(data_X);
+      for(i=0; i < nData; i++) {
+	for(j=0; j < nDim; j++ ) {
+	  ptr_double[LIBOCAS_INDEX(j,i,nDim)] = ptr_double[LIBOCAS_INDEX(j,i,nDim)]/data_y[i];
+	}
       }
     }
+
+    /* features in single precision */
+    if( mxIsSingle(data_X) )
+    {    
+      ptr_single = (float*)mxGetPr(data_X);
+      for(i=0; i < nData; i++) {
+	for(j=0; j < nDim; j++ ) {
+	  ptr_single[LIBOCAS_INDEX(j,i,nDim)] = ptr_single[LIBOCAS_INDEX(j,i,nDim)]/data_y[i];
+	}
+      }
+    }
+    
+    /* features in int8  */
+    if( mxIsInt8(data_X) )
+    {    
+      ptr_int8 = (int8_t*)mxGetPr(data_X);
+      for(i=0; i < nData; i++) {
+	for(j=0; j < nDim; j++ ) {
+	  ptr_int8[LIBOCAS_INDEX(j,i,nDim)] = ptr_int8[LIBOCAS_INDEX(j,i,nDim)]/data_y[i];
+	}
+      }
+    }        
   }
 
+  /* divide labels by Cs as it was at the begining */
   if(num_of_Cs > 1)
   {
     for(i=0; i < nData; i++) 
       data_y[i] = data_y[i]/vec_C[i];
   }
 
-
+  /* create output variables */
   plhs[1] = mxCreateDoubleScalar( W0 );
   
-  /* return ocas optimizer statistics */
-  /* typedef struct {
-     uint32_t nIter;    
-     uint32_t nCutPlanes;
-     double trn_err;      
-     double Q_P;          
-     double Q_D;
-     double output_time;
-     double sort_time;
-     double solver_time;
-     int8_t exitflag;       
-     } ocas_return_value_T; */
-
   const char *field_names[] = {"nTrnErrors","Q_P","Q_D","nIter","nCutPlanes","exitflag",
-                               "init_time","output_time","sort_time","qp_solver_time","add_time",
-                               "w_time","print_time","ocas_time","total_time"}; 
+                               "init_time","output_time","sort_time",
+                               "qp_solver_time","add_time","w_time","print_time",
+                               "ocas_time","total_time"}; 
   mwSize dims[2] = {1,1};  
 
-  plhs[2] = mxCreateStructArray(2, dims, (sizeof(field_names)/sizeof(*field_names)), field_names);
+  plhs[2] = mxCreateStructArray(2, dims, (sizeof(field_names)/sizeof(*field_names)), 
+                                field_names);
   
   mxSetField(plhs[2],0,"nIter",mxCreateDoubleScalar((double)ocas.nIter));
   mxSetField(plhs[2],0,"nCutPlanes",mxCreateDoubleScalar((double)ocas.nCutPlanes));
diff --git a/version.h b/version.h
index ed306ef..c79cd4a 100644
--- a/version.h
+++ b/version.h
@@ -1,3 +1,3 @@
 /* this text will be printed in all programs */
 
-#define OCAS_VERSION "v0.93, (C) 2008, 2009, 2010 Vojtech Franc, Soeren Sonnenburg"
+#define OCAS_VERSION "v0.95, (C) 2008-2012 Vojtech Franc, Soeren Sonnenburg"

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/libocas.git



More information about the debian-science-commits mailing list