├── svm_light
├── LICENSE.txt
├── svm_learn_main.c
├── kernel.h
├── Makefile
├── svm_classify.c
├── svm_loqo.c
├── svm_learn.h
├── svm_common.h
└── svm_hideo.c
├── svm_struct
├── svm_struct_main.c
├── Makefile
├── svm_struct_common.c
├── svm_struct_common.h
├── svm_struct_learn.h
└── svm_struct_classify.c
├── svm-struct-matlab.xcodeproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
└── project.pbxproj
├── .gitignore
├── makefile_windows.m
├── README_STRUCT.txt
├── svm_struct_learn_custom.c
├── LICENSE.txt
├── test_svm_struct_learn.m
├── test_svm_struct_learn_ker.m
├── README_MATLAB.txt
├── svm_struct_api.h
├── Makefile
├── svm_struct_learn.m
├── svm_struct_api_types.h
├── svm_struct_learn_mex.c
└── svm_struct_api.c
/svm_light/LICENSE.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vedaldi/svm-struct-matlab/HEAD/svm_light/LICENSE.txt
--------------------------------------------------------------------------------
/svm_light/svm_learn_main.c:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vedaldi/svm-struct-matlab/HEAD/svm_light/svm_learn_main.c
--------------------------------------------------------------------------------
/svm_struct/svm_struct_main.c:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vedaldi/svm-struct-matlab/HEAD/svm_struct/svm_struct_main.c
--------------------------------------------------------------------------------
/svm-struct-matlab.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | svm_struct_learn.mex*
2 | .DS_Store
3 |
4 | *.pbxuser
5 | *.perspective
6 | *.perspectivev3
7 |
8 | build/
9 |
10 | *.mode1v3
11 | *.mode2v3
12 |
13 | svm-struct-matlab.xcodeproj/xcuserdata/
14 | svm-struct-matlab.xcodeproj/project.xcworkspace/xcuserdata/
15 |
16 | svm-struct-matlab-*.tar.gz
17 |
18 | versions
19 |
--------------------------------------------------------------------------------
/makefile_windows.m:
--------------------------------------------------------------------------------
1 | %% svm_light .o files
2 | fprintf('doing hideo \n');
3 | mex -largeArrayDims -c -DWIN ./svm_light/svm_hideo.c
4 | fprintf('doing learn \n');
5 | mex -largeArrayDims -c -DWIN ./svm_light/svm_learn.c
6 | fprintf('doing common \n');
7 | mex -largeArrayDims -c -DWIN ./svm_light/svm_common.c
8 |
9 | %% svm_struct .o files
10 | mex -largeArrayDims -c -DWIN ./svm_struct/svm_struct_learn.c
11 | mex -largeArrayDims -c -DWIN ./svm_struct/svm_struct_common.c
12 |
13 | %% svm_struct - custom .o files
14 | mex -largeArrayDims -c -DWIN ./svm_struct_api.c
15 | mex -largeArrayDims -c -DWIN ./svm_struct_learn_custom.c
16 |
17 | mex -largeArrayDims -DWIN -output svm_struct_learn svm_struct_learn_mex.c svm_struct_api.obj svm_struct_learn_custom.obj svm_struct_learn.obj svm_struct_common.obj svm_common.obj svm_learn.obj svm_hideo.obj
18 |
19 | delete *.obj
20 |
--------------------------------------------------------------------------------
/README_STRUCT.txt:
--------------------------------------------------------------------------------
1 | Readme for the SVM-light structure learning API
2 | -----------------------------------------------
3 | Thorsten Joachims, 03.07.2004
4 |
5 | The API allows to implement different versions of the learning
6 | algorithm for learning different kinds of structures. To adapt to a
7 | new structure, one needs to modify the files
8 |
9 | svm_struct_api_types.h
10 | svm_struct_api.c
11 |
12 | Both files already contain empty templates. The first file contains
13 | the type definitions that need to be changed. PATTERN is the structure
14 | for storing the x-part of an example (x,y), LABEL is the y-part. The
15 | learned model will be stored in STRUCTMODEL. Finally,
16 | STRUCT_LEARN_PARM can be used to store any parameters that you might
17 | want to pass to the function.
18 |
19 | The second file contains the function you need to implement. See the
20 | documentation in the file for details.
21 |
--------------------------------------------------------------------------------
/svm_struct/Makefile:
--------------------------------------------------------------------------------
1 | # Makefile for SVM-struct, 03.10.06
2 |
3 | #Use the following to compile under unix or cygwin
4 | CC = gcc
5 | LD = gcc
6 |
7 | #Call 'make' using the following line to make CYGWIN produce stand-alone Windows executables
8 | # make 'SFLAGS=-mno-cygwin'
9 |
10 | CFLAGS = $(SFLAGS) -O3 -fomit-frame-pointer -ffast-math -Wall
11 | LDFLAGS = $(SFLAGS) -O3 -lm -Wall
12 | #CFLAGS = $(SFLAGS) -pg -Wall
13 | #LDFLAGS = $(SFLAGS) -pg -Wall
14 |
15 | all: svm_struct_noexe
16 |
17 | svm_struct_noexe: svm_struct_learn.o svm_struct_classify.o svm_struct_common.o svm_struct_main.o
18 |
19 | .PHONY: clean
20 | clean:
21 | rm -f *.o *.tcov *.d core gmon.out *.stackdump
22 |
23 |
24 | #----------------------#
25 | #---- STRUCT SVM ----#
26 | #----------------------#
27 |
28 | svm_struct_common.o: svm_struct_common.c svm_struct_common.h ../svm_struct_api_types.h
29 | $(CC) -c $(CFLAGS) svm_struct_common.c -o svm_struct_common.o
30 |
31 | svm_struct_learn.o: svm_struct_learn.c ../svm_light/svm_learn.h svm_struct_common.h ../svm_struct_api.h ../svm_struct_api_types.h
32 | $(CC) -c $(CFLAGS) svm_struct_learn.c -o svm_struct_learn.o
33 |
34 | svm_struct_main.o: svm_struct_main.c ../svm_light/svm_common.h ../svm_light/svm_learn.h svm_struct_learn.h svm_struct_common.h ../svm_struct_api.h ../svm_struct_api_types.h
35 | $(CC) -c $(CFLAGS) svm_struct_main.c -o svm_struct_main.o
36 |
37 | svm_struct_classify.o: svm_struct_classify.c svm_struct_common.h ../svm_struct_api_types.h ../svm_struct_api.h ../svm_light/svm_common.h
38 | $(CC) -c $(CFLAGS) svm_struct_classify.c -o svm_struct_classify.o
39 |
--------------------------------------------------------------------------------
/svm_struct_learn_custom.c:
--------------------------------------------------------------------------------
1 | /***********************************************************************/
2 | /* */
3 | /* svm_struct_learn_custom.c (instantiated for SVM-perform) */
4 | /* */
5 | /* Allows implementing a custom/alternate algorithm for solving */
6 | /* the structual SVM optimization problem. The algorithm can use */
7 | /* full access to the SVM-struct API and to SVM-light. */
8 | /* */
9 | /* Author: Thorsten Joachims */
10 | /* Date: 09.01.08 */
11 | /* */
12 | /* Copyright (c) 2008 Thorsten Joachims - All rights reserved */
13 | /* */
14 | /* This software is available for non-commercial use only. It must */
15 | /* not be modified and distributed without prior permission of the */
16 | /* author. The author is not responsible for implications from the */
17 | /* use of this software. */
18 | /* */
19 | /***********************************************************************/
20 |
21 | #include
22 | #include
23 | #include
24 | #include "svm_struct_api.h"
25 | #include "svm_light/svm_common.h"
26 | #include "svm_struct/svm_struct_common.h"
27 | #include "svm_struct/svm_struct_learn.h"
28 |
29 |
30 | void svm_learn_struct_joint_custom(SAMPLE sample, STRUCT_LEARN_PARM *sparm,
31 | LEARN_PARM *lparm, KERNEL_PARM *kparm,
32 | STRUCTMODEL *sm)
33 | /* Input: sample (training examples)
34 | sparm (structural learning parameters)
35 | lparm (svm learning parameters)
36 | kparm (kernel parameters)
37 | Output: sm (learned model) */
38 | {
39 | /* Put your algorithm here. See svm_struct_learn.c for an example of
40 | how to access this API. */
41 | }
42 |
43 |
--------------------------------------------------------------------------------
/svm_struct/svm_struct_common.c:
--------------------------------------------------------------------------------
1 | /***********************************************************************/
2 | /* */
3 | /* svm_struct_common.h */
4 | /* */
5 | /* Functions and types used by multiple components of SVM-struct. */
6 | /* */
7 | /* Author: Thorsten Joachims */
8 | /* Date: 03.07.04 */
9 | /* */
10 | /* Copyright (c) 2004 Thorsten Joachims - All rights reserved */
11 | /* */
12 | /* This software is available for non-commercial use only. It must */
13 | /* not be modified and distributed without prior permission of the */
14 | /* author. The author is not responsible for implications from the */
15 | /* use of this software. */
16 | /* */
17 | /***********************************************************************/
18 |
19 | #include
20 | #include
21 | #include
22 |
23 | #include "svm_struct_common.h"
24 |
25 | long struct_verbosity; /* verbosity level (0-4) */
26 |
27 | void printIntArray(int* x, int n)
28 | {
29 | int i;
30 | for(i=0;i= rhs[i] */
46 | int m; /* m is the total number of constrains */
47 | DOC **lhs;
48 | double *rhs;
49 | } CONSTSET;
50 |
51 |
52 | /**** print methods ****/
53 | void printIntArray(int*,int);
54 | void printDoubleArray(double*,int);
55 | void printWordArray(WORD*);
56 | void printModel(MODEL *);
57 | void printW(double *, long, long, double);
58 |
59 | extern long struct_verbosity; /* verbosity level (0-4) */
60 |
61 | #endif
62 |
--------------------------------------------------------------------------------
/test_svm_struct_learn.m:
--------------------------------------------------------------------------------
1 | function test_svm_struct_learn
2 | % TEST_SVM_STRUCT_LEARN
3 | % A demo function for SVM_STRUCT_LEARN(). It shows how to use
4 | % SVM-struct to learn a standard linear SVM.
5 |
6 | randn('state',0) ;
7 | rand('state',0) ;
8 |
9 | % ------------------------------------------------------------------
10 | % Generate data
11 | % ------------------------------------------------------------------
12 |
13 | th = pi/3 ;
14 | c = cos(th) ;
15 | s = sin(th) ;
16 |
17 | patterns = {} ;
18 | labels = {} ;
19 | for i=1:100
20 | patterns{i} = diag([2 .5]) * randn(2, 1) ;
21 | labels{i} = 2*(randn > 0) - 1 ;
22 | patterns{i}(2) = patterns{i}(2) + labels{i} ;
23 | patterns{i} = [c -s ; s c] * patterns{i} ;
24 | end
25 |
26 | % ------------------------------------------------------------------
27 | % Run SVM struct
28 | % ------------------------------------------------------------------
29 |
30 | parm.patterns = patterns ;
31 | parm.labels = labels ;
32 | parm.lossFn = @lossCB ;
33 | parm.constraintFn = @constraintCB ;
34 | parm.featureFn = @featureCB ;
35 | parm.dimension = 2 ;
36 | parm.verbose = 1 ;
37 | model = svm_struct_learn(' -c 1.0 -o 1 -v 1 ', parm) ;
38 | w = model.w ;
39 |
40 | % ------------------------------------------------------------------
41 | % Plots
42 | % ------------------------------------------------------------------
43 |
44 | figure(1) ; clf ; hold on ;
45 | x = [patterns{:}] ;
46 | y = [labels{:}] ;
47 | plot(x(1, y>0), x(2,y>0), 'g.') ;
48 | plot(x(1, y<0), x(2,y<0), 'r.') ;
49 | set(line([0 w(1)], [0 w(2)]), 'color', 'y', 'linewidth', 4) ;
50 | xlim([-3 3]) ;
51 | ylim([-3 3]) ;
52 | set(line(10*[w(2) -w(2)], 10*[-w(1) w(1)]), ...
53 | 'color', 'y', 'linewidth', 2, 'linestyle', '-') ;
54 | axis equal ;
55 | set(gca, 'color', 'b') ;
56 | w
57 | end
58 |
59 | % ------------------------------------------------------------------
60 | % SVM struct callbacks
61 | % ------------------------------------------------------------------
62 |
63 | function delta = lossCB(param, y, ybar)
64 | delta = double(y ~= ybar) ;
65 | if param.verbose
66 | fprintf('delta = loss(%3d, %3d) = %f\n', y, ybar, delta) ;
67 | end
68 | end
69 |
70 | function psi = featureCB(param, x, y)
71 | psi = sparse(y*x/2) ;
72 | if param.verbose
73 | fprintf('w = psi([%8.3f,%8.3f], %3d) = [%8.3f, %8.3f]\n', ...
74 | x, y, full(psi(1)), full(psi(2))) ;
75 | end
76 | end
77 |
78 | function yhat = constraintCB(param, model, x, y)
79 | % slack resaling: argmax_y delta(yi, y) (1 + - )
80 | % margin rescaling: argmax_y delta(yi, y) +
81 | if dot(y*x, model.w) > 1, yhat = y ; else yhat = - y ; end
82 | if param.verbose
83 | fprintf('yhat = violslack([%8.3f,%8.3f], [%8.3f,%8.3f], %3d) = %3d\n', ...
84 | model.w, x, y, yhat) ;
85 | end
86 | end
87 |
--------------------------------------------------------------------------------
/svm_light/kernel.h:
--------------------------------------------------------------------------------
1 | /************************************************************************/
2 | /* */
3 | /* kernel.h */
4 | /* */
5 | /* User defined kernel function. Feel free to plug in your own. */
6 | /* */
7 | /* Copyright: Thorsten Joachims */
8 | /* Date: 16.12.97 */
9 | /* */
10 | /************************************************************************/
11 |
12 | /* KERNEL_PARM is defined in svm_common.h The field 'custom' is reserved for */
13 | /* parameters of the user defined kernel. You can also access and use */
14 | /* the parameters of the other kernels. Just replace the line
15 | return((double)(1.0));
16 | with your own kernel. */
17 |
18 | /* Example: The following computes the polynomial kernel. sprod_ss
19 | computes the inner product between two sparse vectors.
20 |
21 | return((CFLOAT)pow(kernel_parm->coef_lin*sprod_ss(a,b)
22 | +kernel_parm->coef_const,(double)kernel_parm->poly_degree));
23 | */
24 |
25 | /* If you are implementing a kernel that is not based on a
26 | feature/value representation, you might want to make use of the
27 | field "userdefined" in SVECTOR. By default, this field will contain
28 | whatever string you put behind a # sign in the example file. So, if
29 | a line in your training file looks like
30 |
31 | -1 1:3 5:6 #abcdefg
32 |
33 | then the SVECTOR field "words" will contain the vector 1:3 5:6, and
34 | "userdefined" will contain the string "abcdefg". */
35 |
36 | #include "../svm_struct_api_types.h"
37 |
38 | double custom_kernel(KERNEL_PARM *kernel_parm, SVECTOR *a, SVECTOR *b)
39 | /* plug in you favorite kernel */
40 | {
41 | mxArray* structParm_array ;
42 | mxArray* kernelFn_array ;
43 | mxArray* args [6] ;
44 | mxArray* k_array ;
45 | double k ;
46 | int status ;
47 |
48 | {
49 | MexKernelInfo* info = (MexKernelInfo*) kernel_parm -> custom ;
50 | structParm_array = (mxArray*) info -> structParm ;
51 | kernelFn_array = (mxArray*) info -> kernelFn ;
52 | }
53 |
54 | args[0] = kernelFn_array ;
55 | args[1] = structParm_array ;
56 | args[2] = MexPhiCustomGetPattern (a->userdefined) ;
57 | args[3] = MexPhiCustomGetLabel (a->userdefined) ;
58 | args[4] = MexPhiCustomGetPattern (b->userdefined) ;
59 | args[5] = MexPhiCustomGetLabel (b->userdefined) ;
60 |
61 | status = mexCallMATLAB(1, &k_array, 6, args, "feval") ;
62 |
63 | if (status) {
64 | mexErrMsgTxt("Error while executing SPARM.KERNELFN") ;
65 | }
66 | if (mxGetClassID(k_array) == mxUNKNOWN_CLASS) {
67 | mexErrMsgTxt("SPARM.KERNELFN did not reutrn a result") ;
68 | }
69 |
70 | k = mxGetScalar (k_array) ;
71 | mxDestroyArray (k_array) ;
72 |
73 | return (k) ;
74 | }
75 |
--------------------------------------------------------------------------------
/test_svm_struct_learn_ker.m:
--------------------------------------------------------------------------------
1 | function test_svm_struct_learn_ker
2 | % TEST_SVM_STRUCT_LEARN
3 | % Test function for SVM_STRUCT_LEARN(). It shows how to use
4 | % SVM-struct to learn a standard linear SVM while using the generic
5 | % kernel interface.
6 |
7 | randn('state',0) ;
8 | rand('state',0) ;
9 |
10 | % ------------------------------------------------------------------
11 | % Generate data
12 | % ------------------------------------------------------------------
13 |
14 | th = pi/3 ;
15 | c = cos(th) ;
16 | s = sin(th) ;
17 |
18 | patterns = {} ;
19 | labels = {} ;
20 | for i=1:100
21 | patterns{i} = diag([2 .5]) * randn(2, 1) ;
22 | labels{i} = 2*(randn > 0) - 1 ;
23 | patterns{i}(2) = patterns{i}(2) + labels{i} ;
24 | patterns{i} = [c -s ; s c] * patterns{i} ;
25 | end
26 |
27 | % ------------------------------------------------------------------
28 | % Run SVM struct
29 | % ------------------------------------------------------------------
30 |
31 | parm.patterns = patterns ;
32 | parm.labels = labels ;
33 | parm.lossFn = @lossCB
34 | parm.constraintFn =@constraintCB ;
35 | parm.kernelFn = @kernelCB ;
36 | parm.verbose = 1 ;
37 | model = svm_struct_learn(' -c 1.0 -o 1 -v 1 -t 4 ', parm) ;
38 | w = cat(2, model.svPatterns{:}) * (model.alpha .* cat(1, model.svLabels{:})) / 2 ;
39 |
40 | % ------------------------------------------------------------------
41 | % Plots
42 | % ------------------------------------------------------------------
43 |
44 | figure(1) ; clf ; hold on ;
45 | x = [patterns{:}] ;
46 | y = [labels{:}] ;
47 | plot(x(1, y>0), x(2,y>0), 'g.') ;
48 | plot(x(1, y<0), x(2,y<0), 'r.') ;
49 | set(line([0 w(1)], [0 w(2)]), 'color', 'y', 'linewidth', 4) ;
50 | xlim([-3 3]) ;
51 | ylim([-3 3]) ;
52 | set(line(10*[w(2) -w(2)], 10*[-w(1) w(1)]), ...
53 | 'color', 'y', 'linewidth', 2, 'linestyle', '-') ;
54 | axis equal ;
55 | set(gca, 'color', 'b') ;
56 | w
57 | end
58 |
59 | % --------------------------------------------------------------------
60 | % SVM struct callbacks
61 | % --------------------------------------------------------------------
62 |
63 | function delta = lossCB(param, y, ybar)
64 | % loss function delta(y, ybar)
65 | delta = double(y ~= ybar) ;
66 | if param.verbose
67 | fprintf('delta = loss(%3d, %3d) = %f\n', y, ybar, delta) ;
68 | end
69 | end
70 |
71 | function k = kernelCB(param, x,y, xp, yp)
72 | k = x' * xp * y * yp / 4 ;
73 | end
74 |
75 | function yhat = constraintCB(param, model, x, y)
76 | % slack resaling: argmax_y delta(yi, y) (1 + - )
77 | % margin rescaling: argmax_y delta(yi, y) +
78 |
79 | % the kernel is linear, get a weight vector back
80 | if size(model.svPatterns, 2) == 0
81 | w = zeros(size(x)) ;
82 | else
83 | w = [model.svPatterns{:}] * (model.alpha .* [model.svLabels{:}]') / 2 ;
84 | end
85 | if dot(y*x, w) > 1, yhat = y ; else yhat = -y ; end
86 | if param.verbose
87 | fprintf('yhat = violslack([%8.3f,%8.3f], [%8.3f,%8.3f], %3d) = %3d\n', ...
88 | w, x, y, yhat) ;
89 | end
90 | end
91 |
--------------------------------------------------------------------------------
/README_MATLAB.txt:
--------------------------------------------------------------------------------
1 | SVM^struct for MATLAB
2 | V1.2
3 | Andrea Vedaldi
4 |
5 | This is a patch to Thorsten Joachims (http://www.joachims.org/)
6 | SVM-struct implementation that provides a simple-to-use MATLAB
7 | interface.
8 |
9 | OBTAINING:
10 |
11 | svm-struct-matlab homepage is
12 | http://www.vlfeat.org/~vedaldi/code/svm-struct-matlab.html. The GIT
13 | repository of the project can be downloaded at
14 | https://github.com/vedaldi/svm-srtuct-matlab.
15 |
16 | COMPILING:
17 |
18 | To compile this software use the included Makefile. It should work out
19 | of the box on Linux and Mac OS X provided that MATLAB MEX program is
20 | in the command line path. So just issue
21 |
22 | > make
23 |
24 | The only files that are needed to run the package with MATLAB are
25 | svm_struct_learn.mex* (MEX program) and svm_struct_learn.m
26 | (documentation).
27 |
28 | If MEX is not on the command line, the path can be specified as
29 |
30 | > make MEX=/bin/mex
31 |
32 | where is MATLAB root directory. Finally, it is also
33 | possible to specify manually the architecture
34 |
35 | > make ARCH=maci # Mac Intel 32 bit
36 | > make ARCH=maci64 # Mac Intel 64 bit
37 | > make ARCH=glnx86 # Linux 32 bit
38 | > make ARCH=glnxa64 # Linux 64 bit
39 |
40 | To clean the build products use
41 |
42 | > make clean # clean all build but the MEX file
43 | > make distclean # clean all build products
44 |
45 | USAGE:
46 |
47 | There is only one MATLAB command, i.e. SVM_STRUCT_LEARN. This commands
48 | take as input handles to the function implementing the maximal
49 | constraint violation search, the loss, and the feature map. See
50 | TEST_SVM_STRUCT_LEARN and TEST_SVM_STRUCT_LEARN_KER for example usage
51 | and SVM_STRUCT_LEARN built-in help for further information.
52 |
53 | CHANGES:
54 |
55 | 1.3 - Adds support for the endIterationFn callback.
56 | 1.2 - Adds support for Xcode 4.0 and Mac OS X 10.7 and greater
57 | 1.1 - Adds Windows support (thanks to Iasonas Kokkinos).
58 | 1.0 - Initial public release
59 |
60 | LICENSE:
61 |
62 | The MATLAB wrapper of T. Joachim's SVM^struct is distributed under the
63 | following ``MIT license''. This license covers only the additions to
64 | T. Joachims SVM^struct code that constitute the MATLAB interface (the
65 | "Software") and does not cover SVM^struct itself. See the file
66 | LICENSE.txt for the SVM^struct license.
67 |
68 | Copyright (C) 2011 by Andrea Vedaldi
69 |
70 | Permission is hereby granted, free of charge, to any person obtaining a copy
71 | of this software and associated documentation files (the "Software"), to deal
72 | in the Software without restriction, including without limitation the rights
73 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
74 | copies of the Software, and to permit persons to whom the Software is
75 | furnished to do so, subject to the following conditions:
76 |
77 | The above copyright notice and this permission notice shall be included in
78 | all copies or substantial portions of the Software.
79 |
80 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
81 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
82 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
83 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
84 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
85 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
86 | THE SOFTWARE.
87 |
88 |
--------------------------------------------------------------------------------
/svm_light/Makefile:
--------------------------------------------------------------------------------
1 | #
2 | # makefile for svm_light
3 | #
4 | # Thorsten Joachims, 2002
5 | #
6 |
7 | #Use the following to compile under unix or cygwin
8 | CC = gcc
9 | LD = gcc
10 |
11 | #Uncomment the following line to make CYGWIN produce stand-alone Windows executables
12 | #SFLAGS= -mno-cygwin
13 |
14 | CFLAGS= $(SFLAGS) -O3 # release C-Compiler flags
15 | LFLAGS= $(SFLAGS) -O3 # release linker flags
16 | #CFLAGS= $(SFLAGS) -pg -Wall -pedantic # debugging C-Compiler flags
17 | #LFLAGS= $(SFLAGS) -pg # debugging linker flags
18 | LIBS=-L. -lm # used libraries
19 |
20 | all: svm_learn_hideo svm_classify
21 |
22 | tidy:
23 | rm -f *.o
24 | rm -f pr_loqo/*.o
25 |
26 | clean: tidy
27 | rm -f svm_learn
28 | rm -f svm_classify
29 | rm -f libsvmlight.so
30 |
31 | help: info
32 |
33 | info:
34 | @echo
35 | @echo "make for SVM-light Thorsten Joachims, 1998"
36 | @echo
37 | @echo "Thanks to Ralf Herbrich for the initial version."
38 | @echo
39 | @echo "USAGE: make [svm_learn | svm_learn_loqo | svm_learn_hideo | "
40 | @echo " libsvmlight_hideo | libsvmlight_loqo | "
41 | @echo " svm_classify | all | clean | tidy]"
42 | @echo
43 | @echo " svm_learn builds the learning module (prefers HIDEO)"
44 | @echo " svm_learn_hideo builds the learning module using HIDEO optimizer"
45 | @echo " svm_learn_loqo builds the learning module using PR_LOQO optimizer"
46 | @echo " svm_classify builds the classfication module"
47 | @echo " libsvmlight_hideo builds shared object library that can be linked into"
48 | @echo " other code using HIDEO"
49 | @echo " libsvmlight_loqo builds shared object library that can be linked into"
50 | @echo " other code using PR_LOQO"
51 | @echo " all (default) builds svm_learn + svm_classify"
52 | @echo " clean removes .o and target files"
53 | @echo " tidy removes .o files"
54 | @echo
55 |
56 | # Create executables svm_learn and svm_classify
57 |
58 | svm_learn_hideo: svm_learn_main.o svm_learn.o svm_common.o svm_hideo.o
59 | $(LD) $(LFLAGS) svm_learn_main.o svm_learn.o svm_common.o svm_hideo.o -o svm_learn $(LIBS)
60 |
61 | #svm_learn_loqo: svm_learn_main.o svm_learn.o svm_common.o svm_loqo.o loqo
62 | # $(LD) $(LFLAGS) svm_learn_main.o svm_learn.o svm_common.o svm_loqo.o pr_loqo/pr_loqo.o -o svm_learn $(LIBS)
63 |
64 | svm_classify: svm_classify.o svm_common.o
65 | $(LD) $(LFLAGS) svm_classify.o svm_common.o -o svm_classify $(LIBS)
66 |
67 |
68 | # Create library libsvmlight.so, so that external code can get access to the
69 | # learning and classification functions of svm-light by linking this library.
70 |
71 | svm_learn_hideo_noexe: svm_learn_main.o svm_learn.o svm_common.o svm_hideo.o
72 |
73 | libsvmlight_hideo: svm_learn_main.o svm_learn.o svm_common.o svm_hideo.o
74 | $(LD) -shared svm_learn.o svm_common.o svm_hideo.o -o libsvmlight.so
75 |
76 | #svm_learn_loqo_noexe: svm_learn_main.o svm_learn.o svm_common.o svm_loqo.o loqo
77 |
78 | #libsvmlight_loqo: svm_learn_main.o svm_learn.o svm_common.o svm_loqo.o
79 | # $(LD) -shared svm_learn.o svm_common.o svm_loqo.o pr_loqo/pr_loqo.o -o libsvmlight.so
80 |
81 | # Compile components
82 |
83 | svm_hideo.o: svm_hideo.c
84 | $(CC) -c $(CFLAGS) svm_hideo.c -o svm_hideo.o
85 |
86 | #svm_loqo.o: svm_loqo.c
87 | # $(CC) -c $(CFLAGS) svm_loqo.c -o svm_loqo.o
88 |
89 | svm_common.o: svm_common.c svm_common.h kernel.h
90 | $(CC) -c $(CFLAGS) svm_common.c -o svm_common.o
91 |
92 | svm_learn.o: svm_learn.c svm_common.h
93 | $(CC) -c $(CFLAGS) svm_learn.c -o svm_learn.o
94 |
95 | svm_learn_main.o: svm_learn_main.c svm_learn.h svm_common.h
96 | $(CC) -c $(CFLAGS) svm_learn_main.c -o svm_learn_main.o
97 |
98 | svm_classify.o: svm_classify.c svm_common.h kernel.h
99 | $(CC) -c $(CFLAGS) svm_classify.c -o svm_classify.o
100 |
101 | #loqo: pr_loqo/pr_loqo.o
102 |
103 | #pr_loqo/pr_loqo.o: pr_loqo/pr_loqo.c
104 | # $(CC) -c $(CFLAGS) pr_loqo/pr_loqo.c -o pr_loqo/pr_loqo.o
105 |
106 |
--------------------------------------------------------------------------------
/svm_struct_api.h:
--------------------------------------------------------------------------------
1 | /***********************************************************************/
2 | /* */
3 | /* svm_struct_api.h */
4 | /* */
5 | /* Definition of API for attaching implementing SVM learning of */
6 | /* structures (e.g. parsing, multi-label classification, HMM) */
7 | /* */
8 | /* Author: Thorsten Joachims */
9 | /* Date: 03.07.04 */
10 | /* */
11 | /* Copyright (c) 2004 Thorsten Joachims - All rights reserved */
12 | /* */
13 | /* This software is available for non-commercial use only. It must */
14 | /* not be modified and distributed without prior permission of the */
15 | /* author. The author is not responsible for implications from the */
16 | /* use of this software. */
17 | /* */
18 | /***********************************************************************/
19 |
20 | #include "svm_struct_api_types.h"
21 | #include "svm_struct/svm_struct_common.h"
22 |
23 | #ifndef svm_struct_api
24 | #define svm_struct_api
25 |
26 | void svm_struct_learn_api_init(int argc, char* argv[]);
27 | void svm_struct_learn_api_exit();
28 | void svm_struct_classify_api_init(int argc, char* argv[]);
29 | void svm_struct_classify_api_exit();
30 | SAMPLE read_struct_examples(char *file, STRUCT_LEARN_PARM *sparm);
31 | void init_struct_model(SAMPLE sample, STRUCTMODEL *sm,
32 | STRUCT_LEARN_PARM *sparm, LEARN_PARM *lparm,
33 | KERNEL_PARM *kparm);
34 | CONSTSET init_struct_constraints(SAMPLE sample, STRUCTMODEL *sm,
35 | STRUCT_LEARN_PARM *sparm);
36 | LABEL find_most_violated_constraint_slackrescaling(PATTERN x, LABEL y,
37 | STRUCTMODEL *sm,
38 | STRUCT_LEARN_PARM *sparm);
39 | LABEL find_most_violated_constraint_marginrescaling(PATTERN x, LABEL y,
40 | STRUCTMODEL *sm,
41 | STRUCT_LEARN_PARM *sparm);
42 | LABEL classify_struct_example(PATTERN x, STRUCTMODEL *sm,
43 | STRUCT_LEARN_PARM *sparm);
44 | int empty_label(LABEL y);
45 | SVECTOR *psi(PATTERN x, LABEL y, STRUCTMODEL *sm,
46 | STRUCT_LEARN_PARM *sparm);
47 | double loss(LABEL y, LABEL ybar, STRUCT_LEARN_PARM *sparm);
48 | int finalize_iteration(double ceps, int cached_constraint,
49 | SAMPLE sample, STRUCTMODEL *sm,
50 | CONSTSET cset, double *alpha,
51 | STRUCT_LEARN_PARM *sparm);
52 | void print_struct_learning_stats(SAMPLE sample, STRUCTMODEL *sm,
53 | CONSTSET cset, double *alpha,
54 | STRUCT_LEARN_PARM *sparm);
55 | void print_struct_testing_stats(SAMPLE sample, STRUCTMODEL *sm,
56 | STRUCT_LEARN_PARM *sparm,
57 | STRUCT_TEST_STATS *teststats);
58 | void eval_prediction(long exnum, EXAMPLE ex, LABEL prediction,
59 | STRUCTMODEL *sm, STRUCT_LEARN_PARM *sparm,
60 | STRUCT_TEST_STATS *teststats);
61 | void write_struct_model(char *file,STRUCTMODEL *sm,
62 | STRUCT_LEARN_PARM *sparm);
63 | STRUCTMODEL read_struct_model(char *file, STRUCT_LEARN_PARM *sparm);
64 | void write_label(FILE *fp, LABEL y);
65 | void free_pattern(PATTERN x);
66 | void free_label(LABEL y);
67 | void free_struct_model(STRUCTMODEL sm);
68 | void free_struct_sample(SAMPLE s);
69 | void print_struct_help();
70 | void parse_struct_parameters(STRUCT_LEARN_PARM *sparm);
71 | void print_struct_help_classify();
72 | void parse_struct_parameters_classify(STRUCT_LEARN_PARM *sparm);
73 | void svm_learn_struct_joint_custom(SAMPLE sample,
74 | STRUCT_LEARN_PARM *sparm,
75 | LEARN_PARM *lparm, KERNEL_PARM *kparm,
76 | STRUCTMODEL *sm);
77 |
78 | #endif
79 |
--------------------------------------------------------------------------------
/svm_struct/svm_struct_learn.h:
--------------------------------------------------------------------------------
1 | /***********************************************************************/
2 | /* */
3 | /* svm_struct_learn.h */
4 | /* */
5 | /* Basic algorithm for learning structured outputs (e.g. parses, */
6 | /* sequences, multi-label classification) with a Support Vector */
7 | /* Machine. */
8 | /* */
9 | /* Author: Thorsten Joachims */
10 | /* Date: 03.07.04 */
11 | /* */
12 | /* Copyright (c) 2004 Thorsten Joachims - All rights reserved */
13 | /* */
14 | /* This software is available for non-commercial use only. It must */
15 | /* not be modified and distributed without prior permission of the */
16 | /* author. The author is not responsible for implications from the */
17 | /* use of this software. */
18 | /* */
19 | /***********************************************************************/
20 |
21 | #ifndef SVM_STRUCT_LEARN
22 | #define SVM_STRUCT_LEARN
23 |
24 | #ifdef __cplusplus
25 | extern "C" {
26 | #endif
27 | #include "../svm_light/svm_common.h"
28 | #include "../svm_light/svm_learn.h"
29 | #ifdef __cplusplus
30 | }
31 | #endif
32 | #include "svm_struct_common.h"
33 | #include "../svm_struct_api_types.h"
34 |
35 | #define SLACK_RESCALING 1
36 | #define MARGIN_RESCALING 2
37 |
38 | #define NSLACK_ALG 0
39 | #define NSLACK_SHRINK_ALG 1
40 | #define ONESLACK_PRIMAL_ALG 2
41 | #define ONESLACK_DUAL_ALG 3
42 | #define ONESLACK_DUAL_CACHE_ALG 4
43 |
44 | typedef struct ccacheelem {
45 | SVECTOR *fydelta; /* left hand side of constraint */
46 | double rhs; /* right hand side of constraint */
47 | double viol; /* violation score under current model */
48 | struct ccacheelem *next; /* next in linked list */
49 | } CCACHEELEM;
50 |
51 | typedef struct ccache {
52 | int n; /* number of examples */
53 | CCACHEELEM **constlist; /* array of pointers to constraint lists
54 | - one list per example. The first
55 | element of the list always points to
56 | the most violated constraint under the
57 | current model for each example. */
58 | STRUCTMODEL *sm; /* pointer to model */
59 | double *avg_viol_gain; /* array of average values by which
60 | violation of globally most violated
61 | constraint exceeds that of most violated
62 | constraint in cache */
63 | int *changed; /* array of boolean indicating whether the
64 | most violated ybar change compared to
65 | last iter? */
66 | } CCACHE;
67 |
68 | void find_most_violated_constraint(SVECTOR **fydelta, double *lossval,
69 | EXAMPLE *ex, SVECTOR *fycached, long n,
70 | STRUCTMODEL *sm,STRUCT_LEARN_PARM *sparm,
71 | double *rt_viol, double *rt_psi,
72 | long *argmax_count);
73 | CCACHE *create_constraint_cache(SAMPLE sample, STRUCT_LEARN_PARM *sparm,
74 | STRUCTMODEL *sm);
75 | void free_constraint_cache(CCACHE *ccache);
76 | double add_constraint_to_constraint_cache(CCACHE *ccache, MODEL *svmModel,
77 | int exnum, SVECTOR *fydelta,
78 | double rhs, double gainthresh,
79 | int maxconst, double *rt_cachesum);
80 | void update_constraint_cache_for_model(CCACHE *ccache, MODEL *svmModel);
81 | double compute_violation_of_constraint_in_cache(CCACHE *ccache, double thresh);
82 | double find_most_violated_joint_constraint_in_cache(CCACHE *ccache,
83 | double thresh, double *lhs_n, SVECTOR **lhs, double *rhs);
84 | void svm_learn_struct(SAMPLE sample, STRUCT_LEARN_PARM *sparm,
85 | LEARN_PARM *lparm, KERNEL_PARM *kparm,
86 | STRUCTMODEL *sm, int alg_type);
87 | void svm_learn_struct_joint(SAMPLE sample, STRUCT_LEARN_PARM *sparm,
88 | LEARN_PARM *lparm, KERNEL_PARM *kparm,
89 | STRUCTMODEL *sm, int alg_type);
90 | void svm_learn_struct_joint_custom(SAMPLE sample, STRUCT_LEARN_PARM *sparm,
91 | LEARN_PARM *lparm, KERNEL_PARM *kparm,
92 | STRUCTMODEL *sm);
93 | void remove_inactive_constraints(CONSTSET *cset, double *alpha,
94 | long i, long *alphahist, long mininactive);
95 | MATRIX *init_kernel_matrix(CONSTSET *cset, KERNEL_PARM *kparm);
96 | MATRIX *update_kernel_matrix(MATRIX *matrix, int newpos, CONSTSET *cset,
97 | KERNEL_PARM *kparm);
98 |
99 | #endif
100 |
101 |
102 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | # file: Makefile
2 | # brief: Compile MEXified SVM-struct
3 | # author: Andrea Vedaldi
4 |
5 | MEX ?= mex
6 | VER = 1.2
7 | PACKAGE = svm-struct-matlab
8 |
9 | # --------------------------------------------------------------------
10 | # Auto-detect architecture
11 | # --------------------------------------------------------------------
12 |
13 | Darwin_PPC_ARCH := mac
14 | Darwin_Power_Macintosh_ARCH := mac
15 | Darwin_i386_ARCH := maci64
16 | Darwin_x86_64_ARCH := maci64
17 | Linux_i386_ARCH := glnx86
18 | Linux_i686_ARCH := glnx86
19 | Linux_unknown_ARC := glnx86
20 | Linux_x86_64_ARCH := glnxa64
21 |
22 | UNAME := $(shell uname -sm)
23 | ARCH ?= $($(shell echo "$(UNAME)" | tr \ _)_ARCH)
24 |
25 | # Mac OS X Intel 32
26 | ifeq ($(ARCH),maci)
27 | SDKROOT ?= $(shell xcodebuild -version -sdk macosx | sed -n '/^Path\:/p' | sed 's/^Path: //')
28 | MACOSX_DEPLOYMENT_TARGET ?= 10.4
29 | CFLAGS += -m32 -isysroot $(SDKROOT) -mmacosx-version-min=$(MACOSX_DEPLOYMENT_TARGET)
30 | LDFLAGS += -Wl,-syslibroot,$(SDKROOT) -mmacosx-version-min=$(MACOSX_DEPLOYMENT_TARGET)
31 | MEXEXT = mexmaci
32 | CC = gcc
33 | MEXFLAGS += CC='$(CC)' LD='$(CC)'
34 | endif
35 |
36 | # Mac OS X Intel 64
37 | ifeq ($(ARCH),maci64)
38 | SDKROOT ?= $(shell xcodebuild -version -sdk macosx | sed -n '/^Path\:/p' | sed 's/^Path: //')
39 | MACOSX_DEPLOYMENT_TARGET ?= 10.4
40 | CFLAGS += -m64 -isysroot $(SDKROOT) -mmacosx-version-min=$(MACOSX_DEPLOYMENT_TARGET)
41 | LDFLAGS += -Wl,-syslibroot,$(SDKROOT) -mmacosx-version-min=$(MACOSX_DEPLOYMENT_TARGET)
42 | MEXEXT = mexmaci64
43 | CC = gcc
44 | MEXFLAGS += CC='$(CC)' LD='$(CC)'
45 | endif
46 |
47 | # Linux-32
48 | ifeq ($(ARCH),glnx86)
49 | CFLAGS += -march=i686
50 | LDFLAGS +=
51 | MEXEXT = mexglx
52 | endif
53 |
54 | # Linux-64
55 | ifeq ($(ARCH),glnxa64)
56 | LDFLAGS +=
57 | MEXEXT = mexa64
58 | endif
59 |
60 | MEXFLAGS += -largeArrayDims -$(ARCH) CFLAGS='$$CFLAGS $(CFLAGS) -Wall' LDFLAGS='$$LDFLAGS $(LDFLAGS)'
61 | BUILD = build/$(ARCH)
62 |
63 | # --------------------------------------------------------------------
64 | # Build
65 | # --------------------------------------------------------------------
66 |
67 | svm_light_objs := \
68 | $(BUILD)/svm_light/svm_hideo.o \
69 | $(BUILD)/svm_light/svm_learn.o \
70 | $(BUILD)/svm_light/svm_common.o
71 |
72 | svm_struct_objs := \
73 | $(BUILD)/svm_struct/svm_struct_learn.o \
74 | $(BUILD)/svm_struct/svm_struct_common.o
75 |
76 | svm_custom_objs := \
77 | $(BUILD)/svm_struct_api.o \
78 | $(BUILD)/svm_struct_learn_custom.o
79 |
80 | $(BUILD)/%.o : %.c
81 | $(MEX) $(MEXFLAGS) -outdir "$(dir $@)" -c "$<"
82 |
83 | svm_struct_learn.$(MEXEXT) : svm_struct_learn_mex.c \
84 | $(svm_custom_objs) \
85 | $(svm_light_objs) \
86 | $(svm_struct_objs)
87 | $(MEX) $(MEXFLAGS) $^ -output "$@"
88 |
89 | .PHONY: clean
90 | clean:
91 | rm -fv $(svm_custom_objs) $(svm_struct_objs) $(svm_light_objs)
92 | find . -name '*~' -delete
93 |
94 | .PHONY: distclean
95 | distclean: clean
96 | for ext in mexmaci mexmaci64 mexglx mexa64 ; \
97 | do \
98 | rm -fv svm_struct_learn.$${ext} ; \
99 | done
100 | rm -rf build
101 | rm -rf $(PACKAGE)-*.tar.gz
102 |
103 | .PHONY: dist
104 | dist:
105 | git archive --format=tar --prefix=$(PACKAGE)-$(VER)/ v$(VER) | gzip >$(PACKAGE)-$(VER).tar.gz
106 | @if [ -n "$$(git diff v$(VER) HEAD)" ] ; \
107 | then \
108 | echo "Warning: the repository HEAD is not the same as the tag v$(VER)" ; \
109 | fi
110 |
111 |
112 | # svm_struct dependencies
113 | svm_struct_api.o: \
114 | $(BUILD)/.dir \
115 | svm_struct_api.c \
116 | svm_struct_api.h \
117 | svm_struct_api_types.h \
118 | svm_struct/svm_struct_common.h
119 |
120 | svm_struct_learn_custom.o: \
121 | $(BUILD)/.dir \
122 | svm_struct_learn_custom.c \
123 | svm_struct_api.h \
124 | svm_struct_api_types.h \
125 | svm_light/svm_common.h \
126 | svm_struct/svm_struct_common.h
127 |
128 | svm_struct/svm_struct_mex.o : \
129 | $(BUILD)/.dir \
130 | svm_struct/svm_struct_mex.c
131 |
132 | svm_struct/svm_struct_common.o : \
133 | $(BUILD)/.dir \
134 | svm_struct/svm_struct_common.c \
135 | svm_struct/svm_struct_common.h \
136 | svm_light/svm_common.h \
137 | svm_struct_api_types.h
138 |
139 | svm_struct/svm_struct_learn.o : \
140 | $(BUILD)/.dir \
141 | svm_struct/svm_struct_learn.c \
142 | svm_struct/svm_struct_common.h \
143 | svm_light/svm_common.h \
144 | svm_light/svm_learn.h \
145 | svm_struct_api_types.h \
146 | svm_struct_api.h
147 |
148 | svm_struct/svm_struct_classify.o : \
149 | $(BUILD)/.dir \
150 | svm_struct/svm_struct_classify.c \
151 | svm_struct/svm_struct_common.h \
152 | svm_light/svm_common.h \
153 | svm_struct_api_types.h \
154 | svm_struct_api.h
155 |
156 | # svm_light dependencies
157 | svm_light/svm_learn.o : \
158 | $(BUILD)/.dir \
159 | svm_light/svm_learn.c \
160 | svm_light/svm_learn.h \
161 | svm_light/svm_common.h
162 |
163 | svm_light/svm_common.o : \
164 | $(BUILD)/.dir \
165 | svm_light/svm_common.c \
166 | svm_light/svm_common.h \
167 | svm_light/kernel.h
168 |
169 | svm_light/svm_hideo.o : \
170 | $(BUILD)/.dir \
171 | svm_light/svm_hideo.c
172 |
173 |
--------------------------------------------------------------------------------
/svm_struct/svm_struct_classify.c:
--------------------------------------------------------------------------------
1 | /***********************************************************************/
2 | /* */
3 | /* svm_struct_classify.c */
4 | /* */
5 | /* Classification module of SVM-struct. */
6 | /* */
7 | /* Author: Thorsten Joachims */
8 | /* Date: 03.07.04 */
9 | /* */
10 | /* Copyright (c) 2004 Thorsten Joachims - All rights reserved */
11 | /* */
12 | /* This software is available for non-commercial use only. It must */
13 | /* not be modified and distributed without prior permission of the */
14 | /* author. The author is not responsible for implications from the */
15 | /* use of this software. */
16 | /* */
17 | /************************************************************************/
18 |
19 | #include
20 | #ifdef __cplusplus
21 | extern "C" {
22 | #endif
23 | #include "../svm_light/svm_common.h"
24 | #ifdef __cplusplus
25 | }
26 | #endif
27 | #include "../svm_struct_api.h"
28 | #include "svm_struct_common.h"
29 |
30 | char testfile[200];
31 | char modelfile[200];
32 | char predictionsfile[200];
33 |
34 | void read_input_parameters(int, char **, char *, char *, char *,
35 | STRUCT_LEARN_PARM *, long*, long *);
36 | void print_help(void);
37 |
38 |
39 | int main (int argc, char* argv[])
40 | {
41 | long correct=0,incorrect=0,no_accuracy=0;
42 | long i;
43 | double t1,runtime=0;
44 | double avgloss=0,l;
45 | FILE *predfl;
46 | STRUCTMODEL model;
47 | STRUCT_LEARN_PARM sparm;
48 | STRUCT_TEST_STATS teststats;
49 | SAMPLE testsample;
50 | LABEL y;
51 |
52 | svm_struct_classify_api_init(argc,argv);
53 |
54 | read_input_parameters(argc,argv,testfile,modelfile,predictionsfile,&sparm,
55 | &verbosity,&struct_verbosity);
56 |
57 | if(struct_verbosity>=1) {
58 | printf("Reading model..."); fflush(stdout);
59 | }
60 | model=read_struct_model(modelfile,&sparm);
61 | if(struct_verbosity>=1) {
62 | fprintf(stdout, "done.\n");
63 | }
64 |
65 | if(model.svm_model->kernel_parm.kernel_type == LINEAR) { /* linear kernel */
66 | /* compute weight vector */
67 | add_weight_vector_to_linear_model(model.svm_model);
68 | model.w=model.svm_model->lin_weights;
69 | }
70 |
71 | if(struct_verbosity>=1) {
72 | printf("Reading test examples..."); fflush(stdout);
73 | }
74 | testsample=read_struct_examples(testfile,&sparm);
75 | if(struct_verbosity>=1) {
76 | printf("done.\n"); fflush(stdout);
77 | }
78 |
79 | if(struct_verbosity>=1) {
80 | printf("Classifying test examples..."); fflush(stdout);
81 | }
82 |
83 | if ((predfl = fopen (predictionsfile, "w")) == NULL)
84 | { perror (predictionsfile); exit (1); }
85 |
86 | for(i=0;i=2) {
103 | if((i+1) % 100 == 0) {
104 | printf("%ld..",i+1); fflush(stdout);
105 | }
106 | }
107 | free_label(y);
108 | }
109 | avgloss/=testsample.n;
110 | fclose(predfl);
111 |
112 | if(struct_verbosity>=1) {
113 | printf("done\n");
114 | printf("Runtime (without IO) in cpu-seconds: %.2f\n",
115 | (float)(runtime/100.0));
116 | }
117 | if((!no_accuracy) && (struct_verbosity>=1)) {
118 | printf("Average loss on test set: %.4f\n",(float)avgloss);
119 | printf("Zero/one-error on test set: %.2f%% (%ld correct, %ld incorrect, %d total)\n",(float)100.0*incorrect/testsample.n,correct,incorrect,testsample.n);
120 | }
121 | print_struct_testing_stats(testsample,&model,&sparm,&teststats);
122 | free_struct_sample(testsample);
123 | free_struct_model(model);
124 |
125 | svm_struct_classify_api_exit();
126 |
127 | return(0);
128 | }
129 |
130 | void read_input_parameters(int argc,char *argv[],char *testfile,
131 | char *modelfile,char *predictionsfile,
132 | STRUCT_LEARN_PARM *struct_parm,
133 | long *verbosity,long *struct_verbosity)
134 | {
135 | long i;
136 |
137 | /* set default */
138 | strcpy (modelfile, "svm_model");
139 | strcpy (predictionsfile, "svm_predictions");
140 | (*verbosity)=0;/*verbosity for svm_light*/
141 | (*struct_verbosity)=1; /*verbosity for struct learning portion*/
142 | struct_parm->custom_argc=0;
143 |
144 | for(i=1;(icustom_argv[struct_parm->custom_argc++],argv[i]);i++; strcpy(struct_parm->custom_argv[struct_parm->custom_argc++],argv[i]);break;
150 | case 'v': i++; (*struct_verbosity)=atol(argv[i]); break;
151 | case 'y': i++; (*verbosity)=atol(argv[i]); break;
152 | default: printf("\nUnrecognized option %s!\n\n",argv[i]);
153 | print_help();
154 | exit(0);
155 | }
156 | }
157 | if((i+1)>=argc) {
158 | printf("\nNot enough input parameters!\n\n");
159 | print_help();
160 | exit(0);
161 | }
162 | strcpy (testfile, argv[i]);
163 | strcpy (modelfile, argv[i+1]);
164 | if((i+2) this help\n");
179 | printf(" -v [0..3] -> verbosity level (default 2)\n\n");
180 |
181 | print_struct_help_classify();
182 | }
183 |
184 |
185 |
186 |
187 |
--------------------------------------------------------------------------------
/svm_light/svm_classify.c:
--------------------------------------------------------------------------------
1 | /***********************************************************************/
2 | /* */
3 | /* svm_classify.c */
4 | /* */
5 | /* Classification module of Support Vector Machine. */
6 | /* */
7 | /* Author: Thorsten Joachims */
8 | /* Date: 02.07.02 */
9 | /* */
10 | /* Copyright (c) 2002 Thorsten Joachims - All rights reserved */
11 | /* */
12 | /* This software is available for non-commercial use only. It must */
13 | /* not be modified and distributed without prior permission of the */
14 | /* author. The author is not responsible for implications from the */
15 | /* use of this software. */
16 | /* */
17 | /************************************************************************/
18 |
19 | # include "svm_common.h"
20 |
21 | char docfile[200];
22 | char modelfile[200];
23 | char predictionsfile[200];
24 |
25 | void read_input_parameters(int, char **, char *, char *, char *, long *,
26 | long *);
27 | void print_help(void);
28 |
29 |
30 | int main (int argc, char* argv[])
31 | {
32 | DOC *doc; /* test example */
33 | WORD *words;
34 | long max_docs,max_words_doc,lld;
35 | long totdoc=0,queryid,slackid;
36 | long correct=0,incorrect=0,no_accuracy=0;
37 | long res_a=0,res_b=0,res_c=0,res_d=0,wnum,pred_format;
38 | long j;
39 | double t1,runtime=0;
40 | double dist,doc_label,costfactor;
41 | char *line,*comment;
42 | FILE *predfl,*docfl;
43 | MODEL *model;
44 |
45 | read_input_parameters(argc,argv,docfile,modelfile,predictionsfile,
46 | &verbosity,&pred_format);
47 |
48 | nol_ll(docfile,&max_docs,&max_words_doc,&lld); /* scan size of input file */
49 | max_words_doc+=2;
50 | lld+=2;
51 |
52 | line = (char *)my_malloc(sizeof(char)*lld);
53 | words = (WORD *)my_malloc(sizeof(WORD)*(max_words_doc+10));
54 |
55 | model=read_model(modelfile);
56 |
57 | if(model->kernel_parm.kernel_type == 0) { /* linear kernel */
58 | /* compute weight vector */
59 | add_weight_vector_to_linear_model(model);
60 | }
61 |
62 | if(verbosity>=2) {
63 | printf("Classifying test examples.."); fflush(stdout);
64 | }
65 |
66 | if ((docfl = fopen (docfile, "r")) == NULL)
67 | { perror (docfile); exit (1); }
68 | if ((predfl = fopen (predictionsfile, "w")) == NULL)
69 | { perror (predictionsfile); exit (1); }
70 |
71 | while((!feof(docfl)) && fgets(line,(int)lld,docfl)) {
72 | if(line[0] == '#') continue; /* line contains comments */
73 | parse_document(line,words,&doc_label,&queryid,&slackid,&costfactor,&wnum,
74 | max_words_doc,&comment);
75 | totdoc++;
76 | if(model->kernel_parm.kernel_type == LINEAR) {/* For linear kernel, */
77 | for(j=0;(words[j]).wnum != 0;j++) { /* check if feature numbers */
78 | if((words[j]).wnum>model->totwords) /* are not larger than in */
79 | (words[j]).wnum=0; /* model. Remove feature if */
80 | } /* necessary. */
81 | }
82 | doc = create_example(-1,0,0,0.0,create_svector(words,comment,1.0));
83 | t1=get_runtime();
84 |
85 | if(model->kernel_parm.kernel_type == LINEAR) { /* linear kernel */
86 | dist=classify_example_linear(model,doc);
87 | }
88 | else { /* non-linear kernel */
89 | dist=classify_example(model,doc);
90 | }
91 |
92 | runtime+=(get_runtime()-t1);
93 | free_example(doc,1);
94 |
95 | if(dist>0) {
96 | if(pred_format==0) { /* old weired output format */
97 | fprintf(predfl,"%.8g:+1 %.8g:-1\n",dist,-dist);
98 | }
99 | if(doc_label>0) correct++; else incorrect++;
100 | if(doc_label>0) res_a++; else res_b++;
101 | }
102 | else {
103 | if(pred_format==0) { /* old weired output format */
104 | fprintf(predfl,"%.8g:-1 %.8g:+1\n",-dist,dist);
105 | }
106 | if(doc_label<0) correct++; else incorrect++;
107 | if(doc_label>0) res_c++; else res_d++;
108 | }
109 | if(pred_format==1) { /* output the value of decision function */
110 | fprintf(predfl,"%.8g\n",dist);
111 | }
112 | if((int)(0.01+(doc_label*doc_label)) != 1)
113 | { no_accuracy=1; } /* test data is not binary labeled */
114 | if(verbosity>=2) {
115 | if(totdoc % 100 == 0) {
116 | printf("%ld..",totdoc); fflush(stdout);
117 | }
118 | }
119 | }
120 | fclose(predfl);
121 | fclose(docfl);
122 | free(line);
123 | free(words);
124 | free_model(model,1);
125 |
126 | if(verbosity>=2) {
127 | printf("done\n");
128 |
129 | /* Note by Gary Boone Date: 29 April 2000 */
130 | /* o Timing is inaccurate. The timer has 0.01 second resolution. */
131 | /* Because classification of a single vector takes less than */
132 | /* 0.01 secs, the timer was underflowing. */
133 | printf("Runtime (without IO) in cpu-seconds: %.2f\n",
134 | (float)(runtime/100.0));
135 |
136 | }
137 | if((!no_accuracy) && (verbosity>=1)) {
138 | printf("Accuracy on test set: %.2f%% (%ld correct, %ld incorrect, %ld total)\n",(float)(correct)*100.0/totdoc,correct,incorrect,totdoc);
139 | printf("Precision/recall on test set: %.2f%%/%.2f%%\n",(float)(res_a)*100.0/(res_a+res_b),(float)(res_a)*100.0/(res_a+res_c));
140 | }
141 |
142 | return(0);
143 | }
144 |
145 | void read_input_parameters(int argc, char **argv, char *docfile,
146 | char *modelfile, char *predictionsfile,
147 | long int *verbosity, long int *pred_format)
148 | {
149 | long i;
150 |
151 | /* set default */
152 | strcpy (modelfile, "svm_model");
153 | strcpy (predictionsfile, "svm_predictions");
154 | (*verbosity)=2;
155 | (*pred_format)=1;
156 |
157 | for(i=1;(i=argc) {
169 | printf("\nNot enough input parameters!\n\n");
170 | print_help();
171 | exit(0);
172 | }
173 | strcpy (docfile, argv[i]);
174 | strcpy (modelfile, argv[i+1]);
175 | if((i+2) this help\n");
191 | printf(" -v [0..3] -> verbosity level (default 2)\n");
192 | printf(" -f [0,1] -> 0: old output format of V1.0\n");
193 | printf(" -> 1: output the value of decision function (default)\n\n");
194 | }
195 |
196 |
197 |
198 |
199 |
--------------------------------------------------------------------------------
/svm_light/svm_loqo.c:
--------------------------------------------------------------------------------
1 | /***********************************************************************/
2 | /* */
3 | /* svm_loqo.c */
4 | /* */
5 | /* Interface to the PR_LOQO optimization package for SVM. */
6 | /* */
7 | /* Author: Thorsten Joachims */
8 | /* Date: 19.07.99 */
9 | /* */
10 | /* Copyright (c) 1999 Universitaet Dortmund - All rights reserved */
11 | /* */
12 | /* This software is available for non-commercial use only. It must */
13 | /* not be modified and distributed without prior permission of the */
14 | /* author. The author is not responsible for implications from the */
15 | /* use of this software. */
16 | /* */
17 | /***********************************************************************/
18 |
19 | # include
20 | # include "pr_loqo/pr_loqo.h"
21 | # include "svm_common.h"
22 |
23 | /* Common Block Declarations */
24 |
25 | long verbosity;
26 |
27 | /* /////////////////////////////////////////////////////////////// */
28 |
29 | # define DEF_PRECISION_LINEAR 1E-8
30 | # define DEF_PRECISION_NONLINEAR 1E-14
31 |
32 | double *optimize_qp();
33 | double *primal=0,*dual=0;
34 | double init_margin=0.15;
35 | long init_iter=500,precision_violations=0;
36 | double model_b;
37 | double opt_precision=DEF_PRECISION_LINEAR;
38 |
39 | /* /////////////////////////////////////////////////////////////// */
40 |
41 | void *my_malloc();
42 |
43 | double *optimize_qp(qp,epsilon_crit,nx,threshold,learn_parm)
44 | QP *qp;
45 | double *epsilon_crit;
46 | long nx; /* Maximum number of variables in QP */
47 | double *threshold;
48 | LEARN_PARM *learn_parm;
49 | /* start the optimizer and return the optimal values */
50 | {
51 | register long i,j,result;
52 | double margin,obj_before,obj_after;
53 | double sigdig,dist,epsilon_loqo;
54 | int iter;
55 |
56 | if(!primal) { /* allocate memory at first call */
57 | primal=(double *)my_malloc(sizeof(double)*nx*3);
58 | dual=(double *)my_malloc(sizeof(double)*(nx*2+1));
59 | }
60 |
61 | if(verbosity>=4) { /* really verbose */
62 | printf("\n\n");
63 | for(i=0;iopt_n;i++) {
64 | printf("%f: ",qp->opt_g0[i]);
65 | for(j=0;jopt_n;j++) {
66 | printf("%f ",qp->opt_g[i*qp->opt_n+j]);
67 | }
68 | printf(": a%ld=%.10f < %f",i,qp->opt_xinit[i],qp->opt_up[i]);
69 | printf(": y=%f\n",qp->opt_ce[i]);
70 | }
71 | for(j=0;jopt_m;j++) {
72 | printf("EQ-%ld: %f*a0",j,qp->opt_ce[j]);
73 | for(i=1;iopt_n;i++) {
74 | printf(" + %f*a%ld",qp->opt_ce[i],i);
75 | }
76 | printf(" = %f\n\n",-qp->opt_ce0[0]);
77 | }
78 | }
79 |
80 | obj_before=0; /* calculate objective before optimization */
81 | for(i=0;iopt_n;i++) {
82 | obj_before+=(qp->opt_g0[i]*qp->opt_xinit[i]);
83 | obj_before+=(0.5*qp->opt_xinit[i]*qp->opt_xinit[i]*qp->opt_g[i*qp->opt_n+i]);
84 | for(j=0;jopt_xinit[j]*qp->opt_xinit[i]*qp->opt_g[j*qp->opt_n+i]);
86 | }
87 | }
88 |
89 | result=STILL_RUNNING;
90 | qp->opt_ce0[0]*=(-1.0);
91 | /* Run pr_loqo. If a run fails, try again with parameters which lead */
92 | /* to a slower, but more robust setting. */
93 | for(margin=init_margin,iter=init_iter;
94 | (margin<=0.9999999) && (result!=OPTIMAL_SOLUTION);) {
95 | sigdig=-log10(opt_precision);
96 |
97 | result=pr_loqo((int)qp->opt_n,(int)qp->opt_m,
98 | (double *)qp->opt_g0,(double *)qp->opt_g,
99 | (double *)qp->opt_ce,(double *)qp->opt_ce0,
100 | (double *)qp->opt_low,(double *)qp->opt_up,
101 | (double *)primal,(double *)dual,
102 | (int)(verbosity-2),
103 | (double)sigdig,(int)iter,
104 | (double)margin,(double)(qp->opt_up[0])/4.0,(int)0);
105 |
106 | if(isnan(dual[0])) { /* check for choldc problem */
107 | if(verbosity>=2) {
108 | printf("NOTICE: Restarting PR_LOQO with more conservative parameters.\n");
109 | }
110 | if(init_margin<0.80) { /* become more conservative in general */
111 | init_margin=(4.0*margin+1.0)/5.0;
112 | }
113 | margin=(margin+1.0)/2.0;
114 | (opt_precision)*=10.0; /* reduce precision */
115 | if(verbosity>=2) {
116 | printf("NOTICE: Reducing precision of PR_LOQO.\n");
117 | }
118 | }
119 | else if(result!=OPTIMAL_SOLUTION) {
120 | iter+=2000;
121 | init_iter+=10;
122 | (opt_precision)*=10.0; /* reduce precision */
123 | if(verbosity>=2) {
124 | printf("NOTICE: Reducing precision of PR_LOQO due to (%ld).\n",result);
125 | }
126 | }
127 | }
128 |
129 | if(qp->opt_m) /* Thanks to Alex Smola for this hint */
130 | model_b=dual[0];
131 | else
132 | model_b=0;
133 |
134 | /* Check the precision of the alphas. If results of current optimization */
135 | /* violate KT-Conditions, relax the epsilon on the bounds on alphas. */
136 | epsilon_loqo=1E-10;
137 | for(i=0;iopt_n;i++) {
138 | dist=-model_b*qp->opt_ce[i];
139 | dist+=(qp->opt_g0[i]+1.0);
140 | for(j=0;jopt_g[j*qp->opt_n+i]);
142 | }
143 | for(j=i;jopt_n;j++) {
144 | dist+=(primal[j]*qp->opt_g[i*qp->opt_n+j]);
145 | }
146 | /* printf("LOQO: a[%d]=%f, dist=%f, b=%f\n",i,primal[i],dist,dual[0]); */
147 | if((primal[i]<(qp->opt_up[i]-epsilon_loqo)) && (dist < (1.0-(*epsilon_crit)))) {
148 | epsilon_loqo=(qp->opt_up[i]-primal[i])*2.0;
149 | }
150 | else if((primal[i]>(0+epsilon_loqo)) && (dist > (1.0+(*epsilon_crit)))) {
151 | epsilon_loqo=primal[i]*2.0;
152 | }
153 | }
154 |
155 | for(i=0;iopt_n;i++) { /* clip alphas to bounds */
156 | if(primal[i]<=(0+epsilon_loqo)) {
157 | primal[i]=0;
158 | }
159 | else if(primal[i]>=(qp->opt_up[i]-epsilon_loqo)) {
160 | primal[i]=qp->opt_up[i];
161 | }
162 | }
163 |
164 | obj_after=0; /* calculate objective after optimization */
165 | for(i=0;iopt_n;i++) {
166 | obj_after+=(qp->opt_g0[i]*primal[i]);
167 | obj_after+=(0.5*primal[i]*primal[i]*qp->opt_g[i*qp->opt_n+i]);
168 | for(j=0;jopt_g[j*qp->opt_n+i]);
170 | }
171 | }
172 |
173 | /* if optimizer returned NAN values, reset and retry with smaller */
174 | /* working set. */
175 | if(isnan(obj_after) || isnan(model_b)) {
176 | for(i=0;iopt_n;i++) {
177 | primal[i]=qp->opt_xinit[i];
178 | }
179 | model_b=0;
180 | if(learn_parm->svm_maxqpsize>2) {
181 | learn_parm->svm_maxqpsize--; /* decrease size of qp-subproblems */
182 | }
183 | }
184 |
185 | if(obj_after >= obj_before) { /* check whether there was progress */
186 | (opt_precision)/=100.0;
187 | precision_violations++;
188 | if(verbosity>=2) {
189 | printf("NOTICE: Increasing Precision of PR_LOQO.\n");
190 | }
191 | }
192 |
193 | if(precision_violations > 500) {
194 | (*epsilon_crit)*=10.0;
195 | precision_violations=0;
196 | if(verbosity>=1) {
197 | printf("\nWARNING: Relaxing epsilon on KT-Conditions.\n");
198 | }
199 | }
200 |
201 | (*threshold)=model_b;
202 |
203 | if(result!=OPTIMAL_SOLUTION) {
204 | printf("\nERROR: PR_LOQO did not converge. \n");
205 | return(qp->opt_xinit);
206 | }
207 | else {
208 | return(primal);
209 | }
210 | }
211 |
212 |
--------------------------------------------------------------------------------
/svm_struct_learn.m:
--------------------------------------------------------------------------------
1 | % SVM_STRUCT_LEARN Calls the SVM-struct solver
2 | % MODEL = SVM_STRUCT_LEARN(ARGS, PARM) runs SVM-struct solver with
3 | % parameters ARGS on the problem PARM. See [1-6] for the
4 | % theory. SPARM is a structure of with the fields
5 | %
6 | % PATTERNS:: patterns (X)
7 | % A cell array of patterns. The entries can have any nature
8 | % (they can just be indexes of the actual data for example).
9 | %
10 | % LABELS:: labels (Y)
11 | % A cell array of labels. The entries can have any nature.
12 | %
13 | % LOSSFN:: loss function callback
14 | % A handle to the loss function. This function has the form
15 | % L = LOSS(PARAM, Y, YBAR) where PARAM is the SPARM structure,
16 | % Y a ground truth label, YBAR another label, and L a
17 | % non-negative scalar.
18 | %
19 | % CONSTRAINTFN:: constraint callback
20 | % A handle to the constraint generation function. This function
21 | % has the form YBAR = FUNC(PARAM, MODEL, X, Y) where PARAM is
22 | % the input PARM structure, MODEL is the a structure
23 | % representing the current model, X is an input pattern, and Y
24 | % is its ground truth label. YBAR is the most violated labels.
25 | %
26 | % FEATUREN:: feature map callback
27 | % A handle to the feature map. This function has the form PSI =
28 | % FEATURE(PARAM, X, Y) where PARAM is the input PARM structure,
29 | % X is a pattern, Y is a label, and PSI a sparse vector of
30 | % dimension PARM.DIMENSION. This handle does not need to be
31 | % specified if kernels are used.
32 | %
33 | % ENDITERATIONFN:: end iteration callback
34 | % The optional callback CONTINUE = ENDITERATIONFN(PARAM, MODEL)
35 | % is called at the end of each cutting plane iteration. This can
36 | % be used to display diagnostic information. The callback should
37 | % return a logcial value, usually equal to FALSE. If the value
38 | % is TRUE, then the algorithm keeps iterating even if the
39 | % convergence criterion has been satisfied.
40 | %
41 | % DIMENSION:: dimension of the feature map
42 | % The dimension of the feature map. This value does not need to
43 | % be specified i kernels are used.
44 | %
45 | % KERNELFN:: kernel function callback
46 | % A handle to the kernel function. This function has the form K
47 | % = KERN(PARAM, X, Y, XP, YP) where PARAM is the input PARM
48 | % structure, and X, Y and XP, YP are two pattern-label pairs,
49 | % input of the joint kernel. This handle does not need to be
50 | % specified if feature maps are used.
51 | %
52 | % MODEL is a structure with fields:
53 | %
54 | % W:: weight vector
55 | % This is a spare vector of size PARAM.DIMENSION. It is used
56 | % with feature maps.
57 | %
58 | % ALPHA:: dual variables
59 | % SVPATTERNS:: patterns which are support vectors
60 | % SVLABELS:: labels which are support vectors
61 | % Used with kernels.
62 | %
63 | % ARGS is a string specifying options in the usual struct
64 | % SVM. These are:
65 | %
66 | % General Options::
67 | % -v [0..3] -> verbosity level (default 1)
68 | % -y [0..3] -> verbosity level for svm_light (default 0)
69 | %
70 | % Learning Options::
71 | % -c float -> C: trade-off between training error
72 | % and margin (default 0.01)
73 | % -p [1,2] -> L-norm to use for slack variables. Use 1 for L1-norm,
74 | % use 2 for squared slacks. (default 1)
75 | % -o [1,2] -> Rescaling method to use for loss.
76 | % 1: slack rescaling
77 | % 2: margin rescaling
78 | % -l [0..] -> Loss function to use.
79 | % 0: zero/one loss
80 | % ?: see below in application specific options
81 | %
82 | % Optimization Options (see [2][5])::
83 | % -w [0,..,9] -> choice of structural learning algorithm
84 | % 0: n-slack algorithm described in [2]
85 | % 1: n-slack algorithm with shrinking heuristic
86 | % 2: 1-slack algorithm (primal) described in [5]
87 | % 3: 1-slack algorithm (dual) described in [5]
88 | % 4: 1-slack algorithm (dual) with constraint cache [5]
89 | % 9: custom algorithm in svm_struct_learn_custom.c
90 | % -e float -> epsilon: allow that tolerance for termination
91 | % criterion
92 | % -k [1..] -> number of new constraints to accumulate before
93 | % recomputing the QP solution (default 100) (-w 0 and 1 only)
94 | % -f [5..] -> number of constraints to cache for each example
95 | % (default 5) (used with -w 4)
96 | % -b [1..100] -> percentage of training set for which to refresh cache
97 | % when no epsilon violated constraint can be constructed
98 | % from current cache (default 100%%) (used with -w 4)
99 | %
100 | % SVM-light Options for Solving QP Subproblems (see [3])::
101 | % -n [2..q] -> number of new variables entering the working set
102 | % in each svm-light iteration (default n = q).
103 | % Set n < q to prevent zig-zagging.
104 | % -m [5..] -> size of svm-light cache for kernel evaluations in MB
105 | % (default 40) (used only for -w 1 with kernels)
106 | % -h [5..] -> number of svm-light iterations a variable needs to be
107 | % optimal before considered for shrinking (default 100)
108 | % -# int -> terminate svm-light QP subproblem optimization, if no
109 | % progress after this number of iterations.
110 | % (default 100000)
111 | %
112 | % Kernel Options::
113 | % -t int -> type of kernel function:
114 | % 0: linear (default)
115 | % 1: polynomial (s a*b+c)^d
116 | % 2: radial basis function exp(-gamma ||a-b||^2)
117 | % 3: sigmoid tanh(s a*b + c)
118 | % 4: user defined kernel from kernel.h
119 | % -d int -> parameter d in polynomial kernel
120 | % -g float -> parameter gamma in rbf kernel
121 | % -s float -> parameter s in sigmoid/poly kernel
122 | % -r float -> parameter c in sigmoid/poly kernel
123 | % -u string -> parameter of user defined kernel
124 | %
125 | % Output Options::
126 | % -a string -> write all alphas to this file after learning
127 | % (in the same order as in the training set)
128 | % References::
129 | % [1] T. Joachims, Learning to Align Sequences: A Maximum Margin Approach.
130 | % Technical Report, September, 2003.
131 | % [2] I. Tsochantaridis, T. Joachims, T. Hofmann, and Y. Altun, Large Margin
132 | % Methods for Structured and Interdependent Output Variables, Journal
133 | % of Machine Learning Research (JMLR), Vol. 6(Sep):1453-1484, 2005.
134 | % [3] T. Joachims, Making Large-Scale SVM Learning Practical. Advances in
135 | % Kernel Methods - Support Vector Learning, B. Schölkopf and C. Burges and
136 | % A. Smola (ed.), MIT Press, 1999.
137 | % [4] T. Joachims, Learning to Classify Text Using Support Vector
138 | % Machines: Methods, Theory, and Algorithms. Dissertation, Kluwer,
139 | % 2002.
140 | % [5] T. Joachims, T. Finley, Chun-Nam Yu, Cutting-Plane Training of Structural
141 | % SVMs, Machine Learning Journal, to appear.
142 | % [6] http://svmlight.joachims.org/
143 |
144 | % Authors:: Andrea Vedaldi (MATLAB MEX version)
145 |
--------------------------------------------------------------------------------
/svm_light/svm_learn.h:
--------------------------------------------------------------------------------
1 | /***********************************************************************/
2 | /* */
3 | /* svm_learn.h */
4 | /* */
5 | /* Declarations for learning module of Support Vector Machine. */
6 | /* */
7 | /* Author: Thorsten Joachims */
8 | /* Date: 02.07.02 */
9 | /* */
10 | /* Copyright (c) 2002 Thorsten Joachims - All rights reserved */
11 | /* */
12 | /* This software is available for non-commercial use only. It must */
13 | /* not be modified and distributed without prior permission of the */
14 | /* author. The author is not responsible for implications from the */
15 | /* use of this software. */
16 | /* */
17 | /***********************************************************************/
18 |
19 | #ifndef SVM_LEARN
20 | #define SVM_LEARN
21 |
22 | void svm_learn_classification(DOC **, double *, long, long, LEARN_PARM *,
23 | KERNEL_PARM *, KERNEL_CACHE *, MODEL *,
24 | double *);
25 | void svm_learn_regression(DOC **, double *, long, long, LEARN_PARM *,
26 | KERNEL_PARM *, KERNEL_CACHE **, MODEL *);
27 | void svm_learn_ranking(DOC **, double *, long, long, LEARN_PARM *,
28 | KERNEL_PARM *, KERNEL_CACHE **, MODEL *);
29 | void svm_learn_optimization(DOC **, double *, long, long, LEARN_PARM *,
30 | KERNEL_PARM *, KERNEL_CACHE *, MODEL *,
31 | double *);
32 | long optimize_to_convergence(DOC **, long *, long, long, LEARN_PARM *,
33 | KERNEL_PARM *, KERNEL_CACHE *, SHRINK_STATE *,
34 | MODEL *, long *, long *, double *,
35 | double *, double *,
36 | TIMING *, double *, long, long);
37 | long optimize_to_convergence_sharedslack(DOC **, long *, long, long,
38 | LEARN_PARM *,
39 | KERNEL_PARM *, KERNEL_CACHE *, SHRINK_STATE *,
40 | MODEL *, double *, double *, double *,
41 | TIMING *, double *);
42 | double compute_objective_function(double *, double *, double *, double,
43 | long *, long *);
44 | void clear_index(long *);
45 | void add_to_index(long *, long);
46 | long compute_index(long *,long, long *);
47 | void optimize_svm(DOC **, long *, long *, long *, double, long *, long *,
48 | MODEL *,
49 | long, long *, long, double *, double *, double *,
50 | LEARN_PARM *, CFLOAT *, KERNEL_PARM *, QP *, double *);
51 | void compute_matrices_for_optimization(DOC **, long *, long *, long *, double,
52 | long *,
53 | long *, long *, MODEL *, double *,
54 | double *, double *, long, long, LEARN_PARM *,
55 | CFLOAT *, KERNEL_PARM *, QP *);
56 | long calculate_svm_model(DOC **, long *, long *, double *, double *,
57 | double *, double *, LEARN_PARM *, long *,
58 | long *, MODEL *);
59 | long check_optimality(MODEL *, long *, long *, double *, double *,
60 | double *, long,
61 | LEARN_PARM *,double *, double, long *, long *, long *,
62 | long *, long, KERNEL_PARM *);
63 | long check_optimality_sharedslack(DOC **docs, MODEL *model, long int *label,
64 | double *a, double *lin, double *c, double *slack,
65 | double *alphaslack, long int totdoc,
66 | LEARN_PARM *learn_parm, double *maxdiff,
67 | double epsilon_crit_org, long int *misclassified,
68 | long int *active2dnum,
69 | long int *last_suboptimal_at,
70 | long int iteration, KERNEL_PARM *kernel_parm);
71 | void compute_shared_slacks(DOC **docs, long int *label, double *a,
72 | double *lin, double *c, long int *active2dnum,
73 | LEARN_PARM *learn_parm,
74 | double *slack, double *alphaslack);
75 | long identify_inconsistent(double *, long *, long *, long, LEARN_PARM *,
76 | long *, long *);
77 | long identify_misclassified(double *, long *, long *, long,
78 | MODEL *, long *, long *);
79 | long identify_one_misclassified(double *, long *, long *, long,
80 | MODEL *, long *, long *);
81 | long incorporate_unlabeled_examples(MODEL *, long *,long *, long *,
82 | double *, double *, long, double *,
83 | long *, long *, long, KERNEL_PARM *,
84 | LEARN_PARM *);
85 | void update_linear_component(DOC **, long *, long *, double *, double *,
86 | long *, long, long, KERNEL_PARM *,
87 | KERNEL_CACHE *, double *,
88 | CFLOAT *, double *);
89 | long select_next_qp_subproblem_grad(long *, long *, double *,
90 | double *, double *, long,
91 | long, LEARN_PARM *, long *, long *,
92 | long *, double *, long *, KERNEL_CACHE *,
93 | long, long *, long *);
94 | long select_next_qp_subproblem_rand(long *, long *, double *,
95 | double *, double *, long,
96 | long, LEARN_PARM *, long *, long *,
97 | long *, double *, long *, KERNEL_CACHE *,
98 | long *, long *, long);
99 | long select_next_qp_slackset(DOC **docs, long int *label, double *a,
100 | double *lin, double *slack, double *alphaslack,
101 | double *c, LEARN_PARM *learn_parm,
102 | long int *active2dnum, double *maxviol);
103 | void select_top_n(double *, long, long *, long);
104 | void init_shrink_state(SHRINK_STATE *, long, long);
105 | void shrink_state_cleanup(SHRINK_STATE *);
106 | long shrink_problem(DOC **, LEARN_PARM *, SHRINK_STATE *, KERNEL_PARM *,
107 | long *, long *, long, long, long, double *, long *);
108 | void reactivate_inactive_examples(long *, long *, double *, SHRINK_STATE *,
109 | double *, double*, long, long, long, LEARN_PARM *,
110 | long *, DOC **, KERNEL_PARM *,
111 | KERNEL_CACHE *, MODEL *, CFLOAT *,
112 | double *, double *);
113 |
114 | /* cache kernel evalutations to improve speed */
115 | KERNEL_CACHE *kernel_cache_init(long, long);
116 | void kernel_cache_cleanup(KERNEL_CACHE *);
117 | void get_kernel_row(KERNEL_CACHE *,DOC **, long, long, long *, CFLOAT *,
118 | KERNEL_PARM *);
119 | void cache_kernel_row(KERNEL_CACHE *,DOC **, long, KERNEL_PARM *);
120 | void cache_multiple_kernel_rows(KERNEL_CACHE *,DOC **, long *, long,
121 | KERNEL_PARM *);
122 | void kernel_cache_shrink(KERNEL_CACHE *,long, long, long *);
123 | void kernel_cache_reset_lru(KERNEL_CACHE *);
124 | long kernel_cache_malloc(KERNEL_CACHE *);
125 | void kernel_cache_free(KERNEL_CACHE *,long);
126 | long kernel_cache_free_lru(KERNEL_CACHE *);
127 | CFLOAT *kernel_cache_clean_and_malloc(KERNEL_CACHE *,long);
128 | long kernel_cache_touch(KERNEL_CACHE *,long);
129 | long kernel_cache_check(KERNEL_CACHE *,long);
130 | long kernel_cache_space_available(KERNEL_CACHE *);
131 |
132 | void compute_xa_estimates(MODEL *, long *, long *, long, DOC **,
133 | double *, double *, KERNEL_PARM *,
134 | LEARN_PARM *, double *, double *, double *);
135 | double xa_estimate_error(MODEL *, long *, long *, long, DOC **,
136 | double *, double *, KERNEL_PARM *,
137 | LEARN_PARM *);
138 | double xa_estimate_recall(MODEL *, long *, long *, long, DOC **,
139 | double *, double *, KERNEL_PARM *,
140 | LEARN_PARM *);
141 | double xa_estimate_precision(MODEL *, long *, long *, long, DOC **,
142 | double *, double *, KERNEL_PARM *,
143 | LEARN_PARM *);
144 | void avg_similarity_of_sv_of_one_class(MODEL *, DOC **, double *, long *, KERNEL_PARM *, double *, double *);
145 | double most_similar_sv_of_same_class(MODEL *, DOC **, double *, long, long *, KERNEL_PARM *, LEARN_PARM *);
146 | double distribute_alpha_t_greedily(long *, long, DOC **, double *, long, long *, KERNEL_PARM *, LEARN_PARM *, double);
147 | double distribute_alpha_t_greedily_noindex(MODEL *, DOC **, double *, long, long *, KERNEL_PARM *, LEARN_PARM *, double);
148 | void estimate_transduction_quality(MODEL *, long *, long *, long, DOC **, double *);
149 | double estimate_margin_vcdim(MODEL *, double, double);
150 | double estimate_sphere(MODEL *);
151 | double estimate_r_delta_average(DOC **, long, KERNEL_PARM *);
152 | double estimate_r_delta(DOC **, long, KERNEL_PARM *);
153 | double length_of_longest_document_vector(DOC **, long, KERNEL_PARM *);
154 |
155 | void write_model(char *, MODEL *);
156 | void write_prediction(char *, MODEL *, double *, double *, long *, long *,
157 | long, LEARN_PARM *);
158 | void write_alphas(char *, double *, long *, long);
159 |
160 | typedef struct cache_parm_s {
161 | KERNEL_CACHE *kernel_cache;
162 | CFLOAT *cache;
163 | DOC **docs;
164 | long m;
165 | KERNEL_PARM *kernel_parm;
166 | long offset,stepsize;
167 | } cache_parm_t;
168 |
169 | #endif
170 |
--------------------------------------------------------------------------------
/svm-struct-matlab.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXFileReference section */
10 | 2D002F7B104FCC3200981B2C /* Makefile */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 4; path = Makefile; sourceTree = ""; wrapsLines = 0; };
11 | 2D002F7D104FCC3200981B2C /* kernel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = kernel.h; sourceTree = ""; tabWidth = 8; };
12 | 2D002F80104FCC3200981B2C /* svm_classify.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.c; path = svm_classify.c; sourceTree = ""; tabWidth = 8; usesTabs = 0; };
13 | 2D002F81104FCC3200981B2C /* svm_common.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.c; path = svm_common.c; sourceTree = ""; tabWidth = 8; usesTabs = 0; };
14 | 2D002F82104FCC3200981B2C /* svm_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = svm_common.h; sourceTree = ""; tabWidth = 8; };
15 | 2D002F84104FCC3200981B2C /* svm_hideo.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.c; path = svm_hideo.c; sourceTree = ""; tabWidth = 8; usesTabs = 0; };
16 | 2D002F86104FCC3200981B2C /* svm_learn.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.c; path = svm_learn.c; sourceTree = ""; tabWidth = 8; usesTabs = 0; };
17 | 2D002F87104FCC3200981B2C /* svm_learn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = svm_learn.h; sourceTree = ""; tabWidth = 8; };
18 | 2D002F89104FCC3200981B2C /* svm_learn_main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = svm_learn_main.c; sourceTree = ""; tabWidth = 8; };
19 | 2D002F8A104FCC3200981B2C /* svm_loqo.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.c; path = svm_loqo.c; sourceTree = ""; tabWidth = 8; usesTabs = 0; };
20 | 2D002F8D104FCC3200981B2C /* svm_struct_classify.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = svm_struct_classify.c; sourceTree = ""; tabWidth = 8; };
21 | 2D002F8E104FCC3200981B2C /* svm_struct_common.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.c; path = svm_struct_common.c; sourceTree = ""; tabWidth = 8; usesTabs = 0; };
22 | 2D002F8F104FCC3200981B2C /* svm_struct_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = svm_struct_common.h; sourceTree = ""; tabWidth = 8; };
23 | 2D002F91104FCC3200981B2C /* svm_struct_learn.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.c; path = svm_struct_learn.c; sourceTree = ""; tabWidth = 8; usesTabs = 0; };
24 | 2D002F92104FCC3200981B2C /* svm_struct_learn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = svm_struct_learn.h; sourceTree = ""; tabWidth = 8; };
25 | 2D002F94104FCC3200981B2C /* svm_struct_main.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.c; path = svm_struct_main.c; sourceTree = ""; tabWidth = 8; usesTabs = 0; };
26 | 2D002F95104FCC3200981B2C /* svm_struct_api.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.c; lineEnding = 0; path = svm_struct_api.c; sourceTree = ""; tabWidth = 8; xcLanguageSpecificationIdentifier = xcode.lang.c; };
27 | 2D002F96104FCC3200981B2C /* svm_struct_api.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = svm_struct_api.h; sourceTree = ""; tabWidth = 8; };
28 | 2D002F97104FCC3200981B2C /* svm_struct_api_types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = svm_struct_api_types.h; sourceTree = ""; tabWidth = 8; };
29 | 2D002F98104FCC3200981B2C /* svm_struct_learn.m */ = {isa = PBXFileReference; explicitFileType = sourcecode; fileEncoding = 4; lineEnding = 0; path = svm_struct_learn.m; sourceTree = ""; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
30 | 2D002F99104FCC3200981B2C /* svm_struct_learn_custom.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = svm_struct_learn_custom.c; sourceTree = ""; tabWidth = 8; };
31 | 2D002F9A104FCC3200981B2C /* test_svm_struct_learn.m */ = {isa = PBXFileReference; explicitFileType = sourcecode; fileEncoding = 4; lineEnding = 0; path = test_svm_struct_learn.m; sourceTree = ""; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
32 | 2D002F9B104FCC3200981B2C /* test_svm_struct_learn_ker.m */ = {isa = PBXFileReference; explicitFileType = sourcecode; fileEncoding = 4; lineEnding = 0; path = test_svm_struct_learn_ker.m; sourceTree = ""; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
33 | 2D0030081050194100981B2C /* svm_struct_learn_mex.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = svm_struct_learn_mex.c; sourceTree = ""; };
34 | 2D60637D13C8CAB70083CAB2 /* README_MATLAB.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README_MATLAB.txt; sourceTree = ""; wrapsLines = 0; };
35 | /* End PBXFileReference section */
36 |
37 | /* Begin PBXGroup section */
38 | 2D002F66104FCBBE00981B2C = {
39 | isa = PBXGroup;
40 | children = (
41 | 2D60637D13C8CAB70083CAB2 /* README_MATLAB.txt */,
42 | 2D002F7B104FCC3200981B2C /* Makefile */,
43 | 2D002F7C104FCC3200981B2C /* svm_light */,
44 | 2D002F8B104FCC3200981B2C /* svm_struct */,
45 | 2D002F95104FCC3200981B2C /* svm_struct_api.c */,
46 | 2D002F96104FCC3200981B2C /* svm_struct_api.h */,
47 | 2D002F97104FCC3200981B2C /* svm_struct_api_types.h */,
48 | 2D002F99104FCC3200981B2C /* svm_struct_learn_custom.c */,
49 | 2D0030081050194100981B2C /* svm_struct_learn_mex.c */,
50 | 2D002F98104FCC3200981B2C /* svm_struct_learn.m */,
51 | 2D002F9A104FCC3200981B2C /* test_svm_struct_learn.m */,
52 | 2D002F9B104FCC3200981B2C /* test_svm_struct_learn_ker.m */,
53 | );
54 | sourceTree = "";
55 | };
56 | 2D002F7C104FCC3200981B2C /* svm_light */ = {
57 | isa = PBXGroup;
58 | children = (
59 | 2D002F7D104FCC3200981B2C /* kernel.h */,
60 | 2D002F80104FCC3200981B2C /* svm_classify.c */,
61 | 2D002F81104FCC3200981B2C /* svm_common.c */,
62 | 2D002F82104FCC3200981B2C /* svm_common.h */,
63 | 2D002F84104FCC3200981B2C /* svm_hideo.c */,
64 | 2D002F86104FCC3200981B2C /* svm_learn.c */,
65 | 2D002F87104FCC3200981B2C /* svm_learn.h */,
66 | 2D002F89104FCC3200981B2C /* svm_learn_main.c */,
67 | 2D002F8A104FCC3200981B2C /* svm_loqo.c */,
68 | );
69 | path = svm_light;
70 | sourceTree = "";
71 | tabWidth = 8;
72 | };
73 | 2D002F8B104FCC3200981B2C /* svm_struct */ = {
74 | isa = PBXGroup;
75 | children = (
76 | 2D002F8D104FCC3200981B2C /* svm_struct_classify.c */,
77 | 2D002F8E104FCC3200981B2C /* svm_struct_common.c */,
78 | 2D002F8F104FCC3200981B2C /* svm_struct_common.h */,
79 | 2D002F91104FCC3200981B2C /* svm_struct_learn.c */,
80 | 2D002F92104FCC3200981B2C /* svm_struct_learn.h */,
81 | 2D002F94104FCC3200981B2C /* svm_struct_main.c */,
82 | );
83 | path = svm_struct;
84 | sourceTree = "";
85 | tabWidth = 8;
86 | };
87 | /* End PBXGroup section */
88 |
89 | /* Begin PBXLegacyTarget section */
90 | 2D002F9C104FCC8300981B2C /* all */ = {
91 | isa = PBXLegacyTarget;
92 | buildArgumentsString = "$(ACTION)";
93 | buildConfigurationList = 2D002FA7104FCCBB00981B2C /* Build configuration list for PBXLegacyTarget "all" */;
94 | buildPhases = (
95 | );
96 | buildToolPath = /usr/bin/make;
97 | dependencies = (
98 | );
99 | name = all;
100 | passBuildSettingsInEnvironment = 1;
101 | productName = all;
102 | };
103 | /* End PBXLegacyTarget section */
104 |
105 | /* Begin PBXProject section */
106 | 2D002F68104FCBBE00981B2C /* Project object */ = {
107 | isa = PBXProject;
108 | attributes = {
109 | LastUpgradeCheck = 0450;
110 | };
111 | buildConfigurationList = 2D002F6B104FCBBE00981B2C /* Build configuration list for PBXProject "svm-struct-matlab" */;
112 | compatibilityVersion = "Xcode 3.2";
113 | developmentRegion = English;
114 | hasScannedForEncodings = 0;
115 | knownRegions = (
116 | en,
117 | );
118 | mainGroup = 2D002F66104FCBBE00981B2C;
119 | projectDirPath = "";
120 | projectRoot = "";
121 | targets = (
122 | 2D002F9C104FCC8300981B2C /* all */,
123 | );
124 | };
125 | /* End PBXProject section */
126 |
127 | /* Begin XCBuildConfiguration section */
128 | 2D002F69104FCBBE00981B2C /* Debug */ = {
129 | isa = XCBuildConfiguration;
130 | buildSettings = {
131 | ARCH = "$(ARCH_$(ARCHS))";
132 | ARCHS = (
133 | i386,
134 | x86_64,
135 | );
136 | ARCH_i386 = maci;
137 | ARCH_x86_64 = maci64;
138 | DOXYGEN = doxygen;
139 | HEADER_SEARCH_PATHS = "$(MATLABROOT)/extern/include";
140 | MACOSX_DEPLOYMENT_TARGET = 10.5;
141 | MATLABROOT = /Applications/Matlab_R2011A.app;
142 | MEX = "$(MATLABROOT)/bin/mex";
143 | ONLY_ACTIVE_ARCH = YES;
144 | SDKROOT = macosx;
145 | };
146 | name = Debug;
147 | };
148 | 2D002F6A104FCBBE00981B2C /* Release */ = {
149 | isa = XCBuildConfiguration;
150 | buildSettings = {
151 | ARCH = "$(ARCH_$(ARCHS))";
152 | ARCHS = (
153 | i386,
154 | x86_64,
155 | );
156 | ARCH_i386 = maci;
157 | ARCH_x86_64 = maci64;
158 | DOXYGEN = doxygen;
159 | HEADER_SEARCH_PATHS = "$(MATLABROOT)/extern/include";
160 | MACOSX_DEPLOYMENT_TARGET = 10.5;
161 | MATLABROOT = /Applications/Matlab_R2011A.app;
162 | MEX = "$(MATLABROOT)/bin/mex";
163 | NDEBUG = yes;
164 | ONLY_ACTIVE_ARCH = YES;
165 | SDKROOT = macosx;
166 | };
167 | name = Release;
168 | };
169 | 2D002F9D104FCC8300981B2C /* Debug */ = {
170 | isa = XCBuildConfiguration;
171 | buildSettings = {
172 | COMBINE_HIDPI_IMAGES = YES;
173 | };
174 | name = Debug;
175 | };
176 | 2D002F9E104FCC8300981B2C /* Release */ = {
177 | isa = XCBuildConfiguration;
178 | buildSettings = {
179 | COMBINE_HIDPI_IMAGES = YES;
180 | };
181 | name = Release;
182 | };
183 | /* End XCBuildConfiguration section */
184 |
185 | /* Begin XCConfigurationList section */
186 | 2D002F6B104FCBBE00981B2C /* Build configuration list for PBXProject "svm-struct-matlab" */ = {
187 | isa = XCConfigurationList;
188 | buildConfigurations = (
189 | 2D002F69104FCBBE00981B2C /* Debug */,
190 | 2D002F6A104FCBBE00981B2C /* Release */,
191 | );
192 | defaultConfigurationIsVisible = 0;
193 | defaultConfigurationName = Release;
194 | };
195 | 2D002FA7104FCCBB00981B2C /* Build configuration list for PBXLegacyTarget "all" */ = {
196 | isa = XCConfigurationList;
197 | buildConfigurations = (
198 | 2D002F9D104FCC8300981B2C /* Debug */,
199 | 2D002F9E104FCC8300981B2C /* Release */,
200 | );
201 | defaultConfigurationIsVisible = 0;
202 | defaultConfigurationName = Release;
203 | };
204 | /* End XCConfigurationList section */
205 | };
206 | rootObject = 2D002F68104FCBBE00981B2C /* Project object */;
207 | }
208 |
--------------------------------------------------------------------------------
/svm_struct_api_types.h:
--------------------------------------------------------------------------------
1 | /***********************************************************************/
2 | /* */
3 | /* svm_struct_api_types.h */
4 | /* */
5 | /* Definition of API for attaching implementing SVM learning of */
6 | /* structures (e.g. parsing, multi-label classification, HMM) */
7 | /* */
8 | /* Author: Thorsten Joachims */
9 | /* Date: 13.10.03 */
10 | /* */
11 | /* Copyright (c) 2003 Thorsten Joachims - All rights reserved */
12 | /* */
13 | /* This software is available for non-commercial use only. It must */
14 | /* not be modified and distributed without prior permission of the */
15 | /* author. The author is not responsible for implications from the */
16 | /* use of this software. */
17 | /* */
18 | /***********************************************************************/
19 |
20 | #ifndef svm_struct_api_types
21 | #define svm_struct_api_types
22 |
23 | # include "svm_light/svm_common.h"
24 | # include "svm_light/svm_learn.h"
25 |
26 | # ifndef WIN
27 | # include "strings.h"
28 | # else
29 | # include
30 | # endif
31 |
32 | #ifndef WIN
33 | #define inline_comm __inline__
34 | #else
35 | #define inline_comm __inline
36 | #endif
37 |
38 |
39 | typedef struct MexKernelInfo_
40 | {
41 | mxArray const * structParm ;
42 | mxArray const * kernelFn ;
43 | } MexKernelInfo ;
44 |
45 | inline_comm static int
46 | uIsString(const mxArray* A, int L)
47 | {
48 | int M = mxGetM(A) ;
49 | int N = mxGetN(A) ;
50 | return
51 | mxIsChar(A) &&
52 | mxGetNumberOfDimensions(A) == 2 &&
53 | (M == 1 || (M == 0 && N == 0)) &&
54 | (L < 0 || N == L) ;
55 | }
56 |
57 | inline_comm static int
58 | uIsReal (const mxArray* A)
59 | {
60 | return
61 | mxIsDouble(A) &&
62 | ! mxIsComplex(A) ;
63 | }
64 |
65 | inline_comm static int
66 | uIsRealScalar(const mxArray* A)
67 | {
68 | return
69 | uIsReal (A) && mxGetNumberOfElements(A) == 1 ;
70 | }
71 |
72 | inline_comm static int
73 | uIsLogicalScalar(const mxArray* A)
74 | {
75 | return
76 | mxIsLogical(A) && mxGetNumberOfElements(A) == 1 ;
77 | }
78 |
79 | inline_comm static mxArray *
80 | newMxArrayFromDoubleVector (int n, double const* v)
81 | {
82 | mxArray* array = mxCreateDoubleMatrix(n, 1, mxREAL) ;
83 | memcpy(mxGetPr(array), v, sizeof(double) * n) ;
84 | return (array) ;
85 | }
86 |
87 | inline_comm static mxArray *
88 | newMxArrayFromSvector (int n, SVECTOR const* sv)
89 | {
90 | WORD* wi ;
91 | double *pr ;
92 | mwSize nz = 0 ;
93 | mwIndex *ir, *jc ;
94 | mxArray* sv_array ;
95 |
96 | /* count words */
97 | for (wi = sv->words ; wi->wnum >= 1 ; ++ wi) nz ++ ;
98 |
99 | /* allocate sparse array */
100 | sv_array = mxCreateSparse(n, 1, nz, mxREAL) ;
101 | /* mxSetPr(mxMalloc(sizeof(double) * nz)) ;
102 | mxSetIr(mxMalloc(sizeof(mwIndex) * nz)) ;
103 | mxSetJc(mxMalloc(sizeof(mwIndex) * 2)) ;*/
104 | ir = mxGetIr (sv_array) ;
105 | jc = mxGetJc (sv_array) ;
106 | pr = mxGetPr (sv_array) ;
107 |
108 | /* copy fields */
109 | for (wi = sv->words ; wi->wnum >= 1 ; ++ wi) {
110 | *pr ++ = wi -> weight ;
111 | *ir ++ = wi -> wnum ;
112 | if (wi -> wnum > n) {
113 | char str [512] ;
114 | #ifndef WIN
115 | snprintf(str, sizeof(str),
116 | "Component index %d larger than sparse vector dimension %d",
117 | wi -> wnum, n) ;
118 | #else
119 | sprintf(str, sizeof(str),
120 | "Component index %d larger than sparse vector dimension %d",
121 | wi -> wnum, n) ;
122 | #endif
123 | mexErrMsgTxt(str) ;
124 | }
125 | }
126 | jc [0] = 0 ;
127 | jc [1] = nz ;
128 |
129 | return (sv_array) ;
130 | }
131 |
132 |
133 | # define INST_NAME "MATLAB MEX interface"
134 | # define INST_VERSION "V0.1"
135 | # define INST_VERSION_DATE "??.??.??"
136 |
137 | /* default precision for solving the optimization problem */
138 | # define DEFAULT_EPS 0.1
139 | /* default loss rescaling method: 1=slack_rescaling, 2=margin_rescaling */
140 | # define DEFAULT_RESCALING 2
141 | /* default loss function: */
142 | # define DEFAULT_LOSS_FCT 0
143 | /* default optimization algorithm to use: */
144 | # define DEFAULT_ALG_TYPE 3
145 | /* store Psi(x,y) (for ALG_TYPE 1) instead of recomputing it every time: */
146 | # define USE_FYCACHE 1
147 | /* decide whether to evaluate sum before storing vectors in constraint
148 | cache:
149 | 0 = NO,
150 | 1 = YES (best, if sparse vectors and long vector lists),
151 | 2 = YES (best, if short vector lists),
152 | 3 = YES (best, if dense vectors and long vector lists) */
153 | # define COMPACT_CACHED_VECTORS 1
154 | /* minimum absolute value below which values in sparse vectors are
155 | rounded to zero. Values are stored in the FVAL type defined in svm_common.h
156 | RECOMMENDATION: assuming you use FVAL=float, use
157 | 10E-15 if COMPACT_CACHED_VECTORS is 1
158 | 10E-10 if COMPACT_CACHED_VECTORS is 2 or 3
159 | */
160 | # define COMPACT_ROUNDING_THRESH 10E-15
161 |
162 | typedef struct pattern {
163 | /* this defines the x-part of a training example, e.g. the structure
164 | for storing a natural language sentence in NLP parsing */
165 | mxArray* mex ;
166 | } PATTERN;
167 |
168 | typedef struct label {
169 | /* this defines the y-part (the label) of a training example,
170 | e.g. the parse tree of the corresponding sentence. */
171 | mxArray* mex ;
172 | int isOwner ;
173 | } LABEL;
174 |
175 | typedef struct structmodel {
176 | double *w; /* pointer to the learned weights */
177 | MODEL *svm_model; /* the learned SVM model */
178 | long sizePsi; /* maximum number of weights in w */
179 | double walpha;
180 | /* other information that is needed for the stuctural model can be
181 | added here, e.g. the grammar rules for NLP parsing */
182 | } STRUCTMODEL;
183 |
184 | typedef struct struct_learn_parm {
185 | double epsilon; /* precision for which to solve
186 | quadratic program */
187 | double newconstretrain; /* number of new constraints to
188 | accumulate before recomputing the QP
189 | solution (used in w=1 algorithm) */
190 | int ccache_size; /* maximum number of constraints to
191 | cache for each example (used in w=4
192 | algorithm) */
193 | double batch_size; /* size of the mini batches in percent
194 | of training set size (used in w=4
195 | algorithm) */
196 | double C; /* trade-off between margin and loss */
197 | char custom_argv[50][300]; /* storage for the --* command line options */
198 | int custom_argc; /* number of --* command line options */
199 | int slack_norm; /* norm to use in objective function
200 | for slack variables; 1 -> L1-norm,
201 | 2 -> L2-norm */
202 | int loss_type; /* selected loss type from -r
203 | command line option. Select between
204 | slack rescaling (1) and margin
205 | rescaling (2) */
206 | int loss_function; /* select between different loss
207 | functions via -l command line
208 | option */
209 | /* further parameters that are passed to init_struct_model() */
210 | mxArray const * mex ;
211 | } STRUCT_LEARN_PARM ;
212 |
213 | typedef struct struct_test_stats {
214 | #ifdef WIN
215 | int dum;
216 | #endif
217 | /* you can add variables for keeping statistics when evaluating the
218 | test predictions in svm_struct_classify. This can be used in the
219 | function eval_prediction and print_struct_testing_stats. */
220 | } STRUCT_TEST_STATS;
221 |
222 | inline_comm static mxArray *
223 | newMxArrayEncapsulatingDoubleVector (int n, double * v)
224 | {
225 | #if 1
226 | mxArray * v_array = mxCreateDoubleMatrix (0, 0, mxREAL) ;
227 | mxSetPr (v_array, v) ;
228 | mxSetM (v_array, n) ;
229 | mxSetN (v_array, 1) ;
230 | return v_array ;
231 | #else
232 | return newMxArrayFromDoubleVector (n, v) ;
233 | #endif
234 | }
235 |
236 | inline_comm static mxArray *
237 | newMxArrayEncapsulatingSmodel (STRUCTMODEL * smodel)
238 | {
239 | mxArray * alpha_array;
240 | mxArray * svPatterns_array;
241 | mxArray * svLabels_array;
242 |
243 | mwSize dims [] = {1, 1} ;
244 | char const * fieldNames [] = {
245 | "w", "alpha", "svPatterns", "svLabels"
246 | } ;
247 | mxArray * smodel_array = mxCreateStructArray (2, dims, 4, fieldNames) ;
248 |
249 | /* we cannot just encapsulate the arrays because we need to shift by
250 | * one */
251 | if (smodel -> svm_model -> kernel_parm .kernel_type == LINEAR) {
252 | mxSetField (smodel_array, 0, "w",
253 | newMxArrayFromDoubleVector
254 | (smodel->sizePsi, smodel->w + 1) ) ;
255 | } else {
256 | int numFeatures = 0, fi, svi ;
257 | SVECTOR * sv ;
258 | double * alpha ;
259 |
260 | /* count how much space we need to store the expansion */
261 | for (svi = 1 ; svi < smodel->svm_model->sv_num ; ++svi) {
262 | for (sv = smodel->svm_model->supvec[svi]->fvec ;
263 | sv ;
264 | sv = sv -> next) {
265 | ++ numFeatures ;
266 | }
267 | }
268 |
269 | alpha_array = mxCreateDoubleMatrix (numFeatures, 1, mxREAL) ;
270 | svPatterns_array = mxCreateCellMatrix (1, numFeatures) ;
271 | svLabels_array = mxCreateCellMatrix (1, numFeatures) ;
272 |
273 | /* fill in the values */
274 | alpha = mxGetPr (alpha_array) ;
275 | for (fi = 0, svi = 1 ; svi < smodel->svm_model->sv_num ; ++svi) {
276 | for (sv = smodel->svm_model->supvec[svi]->fvec ;
277 | sv ;
278 | sv = sv -> next, ++ fi) {
279 | alpha [fi] = smodel->svm_model->alpha[svi] * sv->factor ;
280 | mxSetCell(svPatterns_array, fi, MexPhiCustomGetPattern (sv->userdefined)) ;
281 | mxSetCell(svLabels_array, fi, MexPhiCustomGetLabel (sv->userdefined)) ;
282 | }
283 | }
284 |
285 | mxSetField (smodel_array, 0, "alpha", alpha_array) ;
286 | mxSetField (smodel_array, 0, "svPatterns", svPatterns_array) ;
287 | mxSetField (smodel_array, 0, "svLabels", svLabels_array) ;
288 | }
289 | return smodel_array ;
290 | }
291 |
292 | inline_comm static void
293 | destroyMxArrayEncapsulatingDoubleVector (mxArray * array)
294 | {
295 | if (array) {
296 | mxSetN (array, 0) ;
297 | mxSetM (array, 0) ;
298 | mxSetPr (array, NULL) ;
299 | mxDestroyArray (array) ;
300 | }
301 | }
302 |
303 | inline_comm static void
304 | destroyMxArrayEncapsulatingSmodel (mxArray * array)
305 | {
306 | if (array) {
307 | /* w and alpha are freed by mxDestroyArray, but we do not want this
308 | * to happen to the encapsulated patterns and labels yet (or are these shared?) */
309 | int i, n ;
310 | mxArray * svPatterns_array = mxGetField (array, 0, "svPatterns") ;
311 | mxArray * svLabels_array = mxGetField (array, 0, "svLabels") ;
312 | if (svPatterns_array) {
313 | n = mxGetNumberOfElements (svPatterns_array) ;
314 | for (i = 0 ; i < n ; ++ i) {
315 | mxSetCell (svPatterns_array, i, NULL) ;
316 | mxSetCell (svLabels_array, i, NULL) ;
317 | }
318 | }
319 | mxDestroyArray (array) ;
320 | }
321 | }
322 |
323 |
324 | #endif
325 |
--------------------------------------------------------------------------------
/svm_struct_learn_mex.c:
--------------------------------------------------------------------------------
1 | /***********************************************************************/
2 | /* */
3 | /* svm_struct_main.c */
4 | /* */
5 | /* Command line interface to the alignment learning module of the */
6 | /* Support Vector Machine. */
7 | /* */
8 | /* Author: Thorsten Joachims */
9 | /* Date: 03.07.04 */
10 | /* */
11 | /* Copyright (c) 2004 Thorsten Joachims - All rights reserved */
12 | /* */
13 | /* This software is available for non-commercial use only. It must */
14 | /* not be modified and distributed without prior permission of the */
15 | /* author. The author is not responsible for implications from the */
16 | /* use of this software. */
17 | /* */
18 | /***********************************************************************/
19 |
20 | #ifdef __cplusplus
21 | extern "C" {
22 | #endif
23 |
24 | #include "svm_light/svm_common.h"
25 | #include "svm_light/svm_learn.h"
26 |
27 | #ifdef __cplusplus
28 | }
29 | #endif
30 |
31 | # include "svm_struct/svm_struct_learn.h"
32 | # include "svm_struct/svm_struct_common.h"
33 | # include "svm_struct_api.h"
34 |
35 | #include
36 | #include
37 | #include
38 |
39 | void read_input_parameters (int, char **,
40 | long *, long *,
41 | STRUCT_LEARN_PARM *, LEARN_PARM *, KERNEL_PARM *,
42 | int *);
43 |
44 | void arg_split (char *string, int *argc, char ***argv) ;
45 | void init_qp_solver() ;
46 | void free_qp_solver() ;
47 |
48 | /** ------------------------------------------------------------------
49 | ** @brief MEX entry point
50 | **/
51 |
52 | void
53 | mexFunction (int nout, mxArray ** out, int nin, mxArray const ** in)
54 | {
55 | SAMPLE sample; /* training sample */
56 | LEARN_PARM learn_parm;
57 | KERNEL_PARM kernel_parm;
58 | STRUCT_LEARN_PARM struct_parm;
59 | STRUCTMODEL structmodel;
60 | int alg_type;
61 |
62 | enum {IN_ARGS=0, IN_SPARM} ;
63 | enum {OUT_W=0} ;
64 |
65 | char arg [1024 + 1] ;
66 | int argc ;
67 | char ** argv ;
68 |
69 | mxArray const * sparm_array;
70 | mxArray const * patterns_array ;
71 | mxArray const * labels_array ;
72 | mxArray const * kernelFn_array ;
73 | int numExamples, ei ;
74 | mxArray * model_array;
75 |
76 | /* SVM-light is not fully reentrant, so we need to run this patch first */
77 | init_qp_solver() ;
78 | verbosity = 0 ;
79 | kernel_cache_statistic = 0 ;
80 |
81 | if (nin != 2) {
82 | mexErrMsgTxt("Two arguments required") ;
83 | }
84 |
85 | /* Parse ARGS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
86 |
87 | if (! uIsString(in[IN_ARGS], -1)) {
88 | mexErrMsgTxt("ARGS must be a string") ;
89 | }
90 |
91 | mxGetString(in[IN_ARGS], arg, sizeof(arg) / sizeof(char)) ;
92 | arg_split (arg, &argc, &argv) ;
93 |
94 | svm_struct_learn_api_init(argc+1, argv-1) ;
95 |
96 | read_input_parameters (argc+1,argv-1,
97 | &verbosity, &struct_verbosity,
98 | &struct_parm, &learn_parm,
99 | &kernel_parm, &alg_type ) ;
100 |
101 | if (kernel_parm.kernel_type != LINEAR &&
102 | kernel_parm.kernel_type != CUSTOM) {
103 | mexErrMsgTxt ("Only LINEAR or CUSTOM kerneles are supported") ;
104 | }
105 |
106 | /* Parse SPARM ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
107 | sparm_array = in [IN_SPARM] ;
108 | // jk remove
109 |
110 | if (! sparm_array) {
111 | mexErrMsgTxt("SPARM must be a structure") ;
112 | }
113 | struct_parm.mex = sparm_array ;
114 |
115 | patterns_array = mxGetField(sparm_array, 0, "patterns") ;
116 | if (! patterns_array ||
117 | ! mxIsCell(patterns_array)) {
118 | mexErrMsgTxt("SPARM.PATTERNS must be a cell array") ;
119 | }
120 |
121 | numExamples = mxGetNumberOfElements(patterns_array) ;
122 |
123 | labels_array = mxGetField(sparm_array, 0, "labels") ;
124 | if (! labels_array ||
125 | ! mxIsCell(labels_array) ||
126 | ! mxGetNumberOfElements(labels_array) == numExamples) {
127 | mexErrMsgTxt("SPARM.LABELS must be a cell array "
128 | "with the same number of elements of "
129 | "SPARM.PATTERNS") ;
130 | }
131 |
132 | sample.n = numExamples ;
133 | sample.examples = (EXAMPLE *) my_malloc (sizeof(EXAMPLE) * numExamples) ;
134 | for (ei = 0 ; ei < numExamples ; ++ ei) {
135 | sample.examples[ei].x.mex = mxGetCell(patterns_array, ei) ;
136 | sample.examples[ei].y.mex = mxGetCell(labels_array, ei) ;
137 | sample.examples[ei].y.isOwner = 0 ;
138 | }
139 |
140 | if (struct_verbosity >= 1) {
141 | mexPrintf("There are %d training examples\n", numExamples) ;
142 | }
143 |
144 | kernelFn_array = mxGetField(sparm_array, 0, "kernelFn") ;
145 | if (! kernelFn_array && kernel_parm.kernel_type == CUSTOM) {
146 | mexErrMsgTxt("SPARM.KERNELFN must be defined for CUSTOM kernels") ;
147 | }
148 | if (kernelFn_array) {
149 | MexKernelInfo * info ;
150 | if (mxGetClassID(kernelFn_array) != mxFUNCTION_CLASS) {
151 | mexErrMsgTxt("SPARM.KERNELFN must be a valid function handle") ;
152 | }
153 | info = (MexKernelInfo*) kernel_parm.custom ;
154 | info -> structParm = sparm_array ;
155 | info -> kernelFn = kernelFn_array ;
156 | }
157 |
158 | /* Learning ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
159 | switch (alg_type) {
160 | case 0:
161 | svm_learn_struct(sample,&struct_parm,&learn_parm,&kernel_parm,&structmodel,NSLACK_ALG) ;
162 | break ;
163 | case 1:
164 | svm_learn_struct(sample,&struct_parm,&learn_parm,&kernel_parm,&structmodel,NSLACK_SHRINK_ALG);
165 | break ;
166 | case 2:
167 | svm_learn_struct_joint(sample,&struct_parm,&learn_parm,&kernel_parm,&structmodel,ONESLACK_PRIMAL_ALG);
168 | break ;
169 | case 3:
170 | svm_learn_struct_joint(sample,&struct_parm,&learn_parm,&kernel_parm,&structmodel,ONESLACK_DUAL_ALG);
171 | break ;
172 | case 4:
173 | svm_learn_struct_joint(sample,&struct_parm,&learn_parm,&kernel_parm,&structmodel,ONESLACK_DUAL_CACHE_ALG);
174 | break ;
175 | case 9:
176 | svm_learn_struct_joint_custom(sample,&struct_parm,&learn_parm,&kernel_parm,&structmodel);
177 | break ;
178 | default:
179 | mexErrMsgTxt("Unknown algorithm type") ;
180 | }
181 |
182 | /* Write output ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
183 |
184 | /* Warning: The model contains references to the original data 'docs'.
185 | If you want to free the original data, and only keep the model, you
186 | have to make a deep copy of 'model'. */
187 |
188 | // jk change
189 | model_array = newMxArrayEncapsulatingSmodel (&structmodel) ;
190 | out[OUT_W] = mxDuplicateArray (model_array) ;
191 | destroyMxArrayEncapsulatingSmodel (model_array) ;
192 |
193 | free_struct_sample (sample) ;
194 | free_struct_model (structmodel) ;
195 | svm_struct_learn_api_exit () ;
196 | free_qp_solver () ;
197 | }
198 |
199 | /** ------------------------------------------------------------------
200 | ** @brief Parse argument string
201 | **/
202 |
203 | void
204 | read_input_parameters (int argc,char *argv[],
205 | long *verbosity,long *struct_verbosity,
206 | STRUCT_LEARN_PARM *struct_parm,
207 | LEARN_PARM *learn_parm, KERNEL_PARM *kernel_parm,
208 | int *alg_type)
209 | {
210 | long i ;
211 |
212 | (*alg_type)=DEFAULT_ALG_TYPE;
213 |
214 | /* SVM struct options */
215 | (*struct_verbosity)=1;
216 |
217 | struct_parm->C=-0.01;
218 | struct_parm->slack_norm=1;
219 | struct_parm->epsilon=DEFAULT_EPS;
220 | struct_parm->custom_argc=0;
221 | struct_parm->loss_function=DEFAULT_LOSS_FCT;
222 | struct_parm->loss_type=DEFAULT_RESCALING;
223 | struct_parm->newconstretrain=100;
224 | struct_parm->ccache_size=5;
225 | struct_parm->batch_size=100;
226 |
227 | /* SVM light options */
228 | (*verbosity)=0;
229 |
230 | strcpy (learn_parm->predfile, "trans_predictions");
231 | strcpy (learn_parm->alphafile, "");
232 | learn_parm->biased_hyperplane=1;
233 | learn_parm->remove_inconsistent=0;
234 | learn_parm->skip_final_opt_check=0;
235 | learn_parm->svm_maxqpsize=10;
236 | learn_parm->svm_newvarsinqp=0;
237 | learn_parm->svm_iter_to_shrink=-9999;
238 | learn_parm->maxiter=100000;
239 | learn_parm->kernel_cache_size=40;
240 | learn_parm->svm_c=99999999; /* overridden by struct_parm->C */
241 | learn_parm->eps=0.001; /* overridden by struct_parm->epsilon */
242 | learn_parm->transduction_posratio=-1.0;
243 | learn_parm->svm_costratio=1.0;
244 | learn_parm->svm_costratio_unlab=1.0;
245 | learn_parm->svm_unlabbound=1E-5;
246 | learn_parm->epsilon_crit=0.001;
247 | learn_parm->epsilon_a=1E-10; /* changed from 1e-15 */
248 | learn_parm->compute_loo=0;
249 | learn_parm->rho=1.0;
250 | learn_parm->xa_depth=0;
251 |
252 | kernel_parm->kernel_type=0;
253 | kernel_parm->poly_degree=3;
254 | kernel_parm->rbf_gamma=1.0;
255 | kernel_parm->coef_lin=1;
256 | kernel_parm->coef_const=1;
257 | strcpy (kernel_parm->custom,"empty");
258 |
259 | /* Parse -x options, delegat --x ones */
260 | for(i=1;(ialphafile,argv[i]); break;
264 | case 'c': i++; struct_parm->C=atof(argv[i]); break;
265 | case 'p': i++; struct_parm->slack_norm=atol(argv[i]); break;
266 | case 'e': i++; struct_parm->epsilon=atof(argv[i]); break;
267 | case 'k': i++; struct_parm->newconstretrain=atol(argv[i]); break;
268 | case 'h': i++; learn_parm->svm_iter_to_shrink=atol(argv[i]); break;
269 | case '#': i++; learn_parm->maxiter=atol(argv[i]); break;
270 | case 'm': i++; learn_parm->kernel_cache_size=atol(argv[i]); break;
271 | case 'w': i++; (*alg_type)=atol(argv[i]); break;
272 | case 'o': i++; struct_parm->loss_type=atol(argv[i]); break;
273 | case 'n': i++; learn_parm->svm_newvarsinqp=atol(argv[i]); break;
274 | case 'q': i++; learn_parm->svm_maxqpsize=atol(argv[i]); break;
275 | case 'l': i++; struct_parm->loss_function=atol(argv[i]); break;
276 | case 'f': i++; struct_parm->ccache_size=atol(argv[i]); break;
277 | case 'b': i++; struct_parm->batch_size=atof(argv[i]); break;
278 | case 't': i++; kernel_parm->kernel_type=atol(argv[i]); break;
279 | case 'd': i++; kernel_parm->poly_degree=atol(argv[i]); break;
280 | case 'g': i++; kernel_parm->rbf_gamma=atof(argv[i]); break;
281 | case 's': i++; kernel_parm->coef_lin=atof(argv[i]); break;
282 | case 'r': i++; kernel_parm->coef_const=atof(argv[i]); break;
283 | case 'u': i++; strcpy(kernel_parm->custom,argv[i]); break;
284 | case 'v': i++; (*struct_verbosity)=atol(argv[i]); break;
285 | case 'y': i++; (*verbosity)=atol(argv[i]); break;
286 | case '-':
287 | strcpy(struct_parm->custom_argv[struct_parm->custom_argc++],argv[i]);
288 | i++;
289 | strcpy(struct_parm->custom_argv[struct_parm->custom_argc++],argv[i]);
290 | break;
291 | default:
292 | {
293 | char msg [1024+1] ;
294 | #ifndef WIN
295 | snprintf(msg, sizeof(msg)/sizeof(char),
296 | "Unrecognized option '%s'",argv[i]) ;
297 | #else
298 | sprintf(msg, sizeof(msg)/sizeof(char),
299 | "Unrecognized option '%s'",argv[i]) ;
300 | #endif
301 | mexErrMsgTxt(msg) ;
302 | }
303 | }
304 | }
305 |
306 | /* whatever is left is an error */
307 | if (i < argc) {
308 | char msg [1024+1] ;
309 | #ifndef WIN
310 | snprintf(msg, sizeof(msg)/sizeof(char),
311 | "Unrecognized argument '%s'", argv[i]) ;
312 | #else
313 | sprintf(msg, sizeof(msg)/sizeof(char),
314 | "Unrecognized argument '%s'", argv[i]) ;
315 | #endif
316 | mexErrMsgTxt(msg) ;
317 | }
318 |
319 | /* Check parameter validity */
320 | if(learn_parm->svm_iter_to_shrink == -9999) {
321 | learn_parm->svm_iter_to_shrink=100;
322 | }
323 |
324 | if((learn_parm->skip_final_opt_check)
325 | && (kernel_parm->kernel_type == LINEAR)) {
326 | mexWarnMsgTxt("It does not make sense to skip the final optimality check for linear kernels.");
327 | learn_parm->skip_final_opt_check=0;
328 | }
329 | if((learn_parm->skip_final_opt_check)
330 | && (learn_parm->remove_inconsistent)) {
331 | mexErrMsgTxt("It is necessary to do the final optimality check when removing inconsistent examples.");
332 | }
333 | if((learn_parm->svm_maxqpsize<2)) {
334 | char msg [1025] ;
335 | #ifndef WIN
336 | snprintf(msg, sizeof(msg)/sizeof(char),
337 | "Maximum size of QP-subproblems not in valid range: %ld [2..]",learn_parm->svm_maxqpsize) ;
338 | #else
339 | sprintf(msg, sizeof(msg)/sizeof(char),
340 | "Maximum size of QP-subproblems not in valid range: %ld [2..]",learn_parm->svm_maxqpsize) ;
341 | #endif
342 | mexErrMsgTxt(msg) ;
343 | }
344 | if((learn_parm->svm_maxqpsizesvm_newvarsinqp)) {
345 | char msg [1025] ;
346 | #ifndef WIN
347 | snprintf(msg, sizeof(msg)/sizeof(char),
348 | "Maximum size of QP-subproblems [%ld] must be larger than the number of"
349 | " new variables [%ld] entering the working set in each iteration.",
350 | learn_parm->svm_maxqpsize, learn_parm->svm_newvarsinqp) ;
351 | #else
352 | sprintf(msg, sizeof(msg)/sizeof(char),
353 | "Maximum size of QP-subproblems [%ld] must be larger than the number of"
354 | " new variables [%ld] entering the working set in each iteration.",
355 | learn_parm->svm_maxqpsize, learn_parm->svm_newvarsinqp) ;
356 | #endif
357 | mexErrMsgTxt(msg) ;
358 | }
359 | if(learn_parm->svm_iter_to_shrink<1) {
360 | char msg [1025] ;
361 | #ifndef WIN
362 | snprintf(msg, sizeof(msg)/sizeof(char),
363 | "Maximum number of iterations for shrinking not in valid range: %ld [1,..]",
364 | learn_parm->svm_iter_to_shrink);
365 | #else
366 | sprintf(msg, sizeof(msg)/sizeof(char),
367 | "Maximum number of iterations for shrinking not in valid range: %ld [1,..]",
368 | learn_parm->svm_iter_to_shrink);
369 | #endif
370 | mexErrMsgTxt(msg) ;
371 | }
372 | if(struct_parm->C<0) {
373 | mexErrMsgTxt("You have to specify a value for the parameter '-c' (C>0)!");
374 | }
375 | if(((*alg_type) < 0) || (((*alg_type) > 5) && ((*alg_type) != 9))) {
376 | mexErrMsgTxt("Algorithm type must be either '0', '1', '2', '3', '4', or '9'!");
377 | }
378 | if(learn_parm->transduction_posratio>1) {
379 | mexErrMsgTxt("The fraction of unlabeled examples to classify as positives must "
380 | "be less than 1.0 !!!");
381 | }
382 | if(learn_parm->svm_costratio<=0) {
383 | mexErrMsgTxt("The COSTRATIO parameter must be greater than zero!");
384 | }
385 | if(struct_parm->epsilon<=0) {
386 | mexErrMsgTxt("The epsilon parameter must be greater than zero!");
387 | }
388 | if((struct_parm->ccache_size<=0) && ((*alg_type) == 4)) {
389 | mexErrMsgTxt("The cache size must be at least 1!");
390 | }
391 | if(((struct_parm->batch_size<=0) || (struct_parm->batch_size>100))
392 | && ((*alg_type) == 4)) {
393 | mexErrMsgTxt("The batch size must be in the interval ]0,100]!");
394 | }
395 | if((struct_parm->slack_norm<1) || (struct_parm->slack_norm>2)) {
396 | mexErrMsgTxt("The norm of the slacks must be either 1 (L1-norm) or 2 (L2-norm)!");
397 | }
398 | if((struct_parm->loss_type != SLACK_RESCALING)
399 | && (struct_parm->loss_type != MARGIN_RESCALING)) {
400 | mexErrMsgTxt("The loss type must be either 1 (slack rescaling) or 2 (margin rescaling)!");
401 | }
402 | if(learn_parm->rho<0) {
403 | mexErrMsgTxt("The parameter rho for xi/alpha-estimates and leave-one-out pruning must"
404 | " be greater than zero (typically 1.0 or 2.0, see T. Joachims, Estimating the"
405 | " Generalization Performance of an SVM Efficiently, ICML, 2000.)!");
406 | }
407 | if((learn_parm->xa_depth<0) || (learn_parm->xa_depth>100)) {
408 | mexErrMsgTxt("The parameter depth for ext. xi/alpha-estimates must be in [0..100] (zero"
409 | "for switching to the conventional xa/estimates described in T. Joachims,"
410 | "Estimating the Generalization Performance of an SVM Efficiently, ICML, 2000.)") ;
411 | }
412 |
413 | parse_struct_parameters (struct_parm) ;
414 | }
415 |
416 | void
417 | arg_split (char *string, int *argc, char ***argv)
418 | {
419 | size_t size;
420 | char *d, *p;
421 |
422 | for (size = 1, p = string; *p; p++) {
423 | if (isspace((int) *p)) {
424 | size++;
425 | }
426 | }
427 | size++; /* leave space for final NULL pointer. */
428 |
429 | *argv = (char **) my_malloc(((size * sizeof(char *)) + (p - string) + 1));
430 |
431 | for (*argc = 0, p = string, d = ((char *) *argv) + size*sizeof(char *);
432 | *p != 0; ) {
433 | (*argv)[*argc] = NULL;
434 | while (*p && isspace((int) *p)) p++;
435 | if (*argc == 0 && *p == '#') {
436 | break;
437 | }
438 | if (*p) {
439 | char *s = p;
440 | (*argv)[(*argc)++] = d;
441 | while (*p && !isspace((int) *p)) p++;
442 | memcpy(d, s, p-s);
443 | d += p-s;
444 | *d++ = 0;
445 | while (*p && isspace((int) *p)) p++;
446 | }
447 | }
448 | }
449 |
--------------------------------------------------------------------------------
/svm_light/svm_common.h:
--------------------------------------------------------------------------------
1 | /************************************************************************/
2 | /* */
3 | /* svm_common.h */
4 | /* */
5 | /* Definitions and functions used in both svm_learn and svm_classify. */
6 | /* */
7 | /* Author: Thorsten Joachims */
8 | /* Date: 31.10.05 */
9 | /* */
10 | /* Copyright (c) 2005 Thorsten Joachims - All rights reserved */
11 | /* */
12 | /* This software is available for non-commercial use only. It must */
13 | /* not be modified and distributed without prior permission of the */
14 | /* author. The author is not responsible for implications from the */
15 | /* use of this software. */
16 | /* */
17 | /************************************************************************/
18 |
19 | #ifndef SVM_COMMON
20 | #define SVM_COMMON
21 |
22 | #include "mex.h"
23 | #include
24 |
25 | #define malloc(x) (mxMalloc(x))
26 | #define realloc(x,y) (mxRealloc((x),(y)))
27 | #define free(x) (mxFree(x))
28 |
29 | struct MexPhiCustomImpl_
30 | {
31 | int counter ;
32 | mxArray * x ;
33 | mxArray * y ;
34 | } ;
35 |
36 | typedef struct MexPhiCustomImpl_ * MexPhiCustom ;
37 |
38 | #ifndef WIN
39 | #define inline_comm __inline__
40 | #else
41 | #define inline_comm __inline
42 | #endif
43 |
44 | inline_comm static MexPhiCustom
45 | newMexPhiCustomFromPatternLabel (mxArray const * x, mxArray const *y)
46 | {
47 | MexPhiCustom phi ;
48 | phi = mxMalloc (sizeof(struct MexPhiCustomImpl_)) ;
49 | phi -> counter = 1 ;
50 | phi -> x = mxDuplicateArray (x) ;
51 | phi -> y = mxDuplicateArray (y) ;
52 | return phi ;
53 | }
54 |
55 | inline_comm static void
56 | releaseMexPhiCustom (MexPhiCustom phi)
57 | {
58 | if (phi) {
59 | phi -> counter -- ;
60 | if (phi -> counter == 0) {
61 | mxDestroyArray (phi -> x) ;
62 | mxDestroyArray (phi -> y) ;
63 | mxFree (phi) ;
64 | }
65 | }
66 | }
67 |
68 | inline_comm static void
69 | retainMexPhiCustom (MexPhiCustom phi) {
70 | if (phi) {
71 | phi -> counter ++ ;
72 | }
73 | }
74 |
75 | inline_comm static mxArray *
76 | MexPhiCustomGetPattern (MexPhiCustom phi) {
77 | assert (phi) ;
78 | return phi -> x ;
79 | }
80 |
81 | inline_comm static mxArray *
82 | MexPhiCustomGetLabel (MexPhiCustom phi) {
83 | assert (phi) ;
84 | return phi -> y ;
85 | }
86 |
87 | # include
88 |
89 | #ifdef _MSC_VER
90 | typedef __int32 int32_t;
91 | typedef unsigned __int32 uint32_t;
92 | typedef __int64 int64_t;
93 | typedef unsigned __int64 uint64_t;
94 | #else
95 | #include
96 | #endif
97 |
98 | # include
99 | # include
100 | # include
101 | # include
102 | # include
103 | # include
104 |
105 | # define VERSION "V6.20"
106 | # define VERSION_DATE "14.08.08"
107 |
108 | # define CFLOAT float /* the type of float to use for caching */
109 | /* kernel evaluations. Using float saves */
110 | /* us some memory, but you can use double, too */
111 | # define FNUM int32_t /* the type used for storing feature ids */
112 | # define FNUM_MAX 2147483647 /* maximum value that FNUM type can take */
113 | # define FVAL float /* the type used for storing feature values */
114 | # define MAXFEATNUM 99999999 /* maximum feature number (must be in
115 | valid range of FNUM type and long int!) */
116 |
117 | # define LINEAR 0 /* linear kernel type */
118 | # define POLY 1 /* polynomial kernel type */
119 | # define RBF 2 /* rbf kernel type */
120 | # define SIGMOID 3 /* sigmoid kernel type */
121 | # define CUSTOM 4 /* userdefined kernel function from kernel.h */
122 | # define GRAM 5 /* use explicit gram matrix from kernel_parm */
123 |
124 | # define CLASSIFICATION 1 /* train classification model */
125 | # define REGRESSION 2 /* train regression model */
126 | # define RANKING 3 /* train ranking model */
127 | # define OPTIMIZATION 4 /* train on general set of constraints */
128 |
129 | # define MAXSHRINK 50000 /* maximum number of shrinking rounds */
130 |
131 | typedef struct word {
132 | FNUM wnum; /* word number */
133 | FVAL weight; /* word weight */
134 | } WORD;
135 |
136 | typedef struct svector {
137 | WORD *words; /* The features/values in the vector by
138 | increasing feature-number. Feature
139 | numbers that are skipped are
140 | interpreted as having value zero. */
141 | double twonorm_sq; /* The squared euclidian length of the
142 | vector. Used to speed up the RBF kernel. */
143 | /* char *userdefined; */
144 | MexPhiCustom userdefined ;
145 | /* You can put additional information
146 | here. This can be useful, if you are
147 | implementing your own kernel that
148 | does not work with feature/values
149 | representations (for example a
150 | string kernel). By default,
151 | svm-light will put here the string
152 | after the # sign from each line of
153 | the input file. */
154 | long kernel_id; /* Feature vectors with different
155 | kernel_id's are orthogonal (ie. the
156 | feature number do not match). This
157 | is used for computing component
158 | kernels for linear constraints which
159 | are a sum of several different
160 | weight vectors. (currently not
161 | implemented). */
162 | struct svector *next; /* Let's you set up a list of SVECTOR's
163 | for linear constraints which are a
164 | sum of multiple feature
165 | vectors. List is terminated by
166 | NULL. */
167 | double factor; /* Factor by which this feature vector
168 | is multiplied in the sum. */
169 | } SVECTOR;
170 |
171 | typedef struct doc {
172 | long docnum; /* Document ID. This has to be the position of
173 | the document in the training set array. */
174 | long queryid; /* for learning rankings, constraints are
175 | generated for documents with the same
176 | queryID. */
177 | double costfactor; /* Scales the cost of misclassifying this
178 | document by this factor. The effect of this
179 | value is, that the upper bound on the alpha
180 | for this example is scaled by this factor.
181 | The factors are set by the feature
182 | 'cost:' in the training data. */
183 | long slackid; /* Index of the slack variable
184 | corresponding to this
185 | constraint. All constraints with the
186 | same slackid share the same slack
187 | variable. This can only be used for
188 | svm_learn_optimization. */
189 | long kernelid; /* Position in gram matrix where kernel
190 | value can be found when using an
191 | explicit gram matrix
192 | (i.e. kernel_type=GRAM). */
193 | SVECTOR *fvec; /* Feature vector of the example. The
194 | feature vector can actually be a
195 | list of feature vectors. For
196 | example, the list will have two
197 | elements, if this DOC is a
198 | preference constraint. The one
199 | vector that is supposed to be ranked
200 | higher, will have a factor of +1,
201 | the lower ranked one should have a
202 | factor of -1. */
203 | } DOC;
204 |
205 | typedef struct learn_parm {
206 | long type; /* selects between regression and
207 | classification */
208 | double svm_c; /* upper bound C on alphas */
209 | double eps; /* regression epsilon (eps=1.0 for
210 | classification */
211 | double svm_costratio; /* factor to multiply C for positive examples */
212 | double transduction_posratio;/* fraction of unlabeled examples to be */
213 | /* classified as positives */
214 | long biased_hyperplane; /* if nonzero, use hyperplane w*x+b=0
215 | otherwise w*x=0 */
216 | long sharedslack; /* if nonzero, it will use the shared
217 | slack variable mode in
218 | svm_learn_optimization. It requires
219 | that the slackid is set for every
220 | training example */
221 | long svm_maxqpsize; /* size q of working set */
222 | long svm_newvarsinqp; /* new variables to enter the working set
223 | in each iteration */
224 | long kernel_cache_size; /* size of kernel cache in megabytes */
225 | double epsilon_crit; /* tolerable error for distances used
226 | in stopping criterion */
227 | double epsilon_shrink; /* how much a multiplier should be above
228 | zero for shrinking */
229 | long svm_iter_to_shrink; /* iterations h after which an example can
230 | be removed by shrinking */
231 | long maxiter; /* number of iterations after which the
232 | optimizer terminates, if there was
233 | no progress in maxdiff */
234 | long remove_inconsistent; /* exclude examples with alpha at C and
235 | retrain */
236 | long skip_final_opt_check; /* do not check KT-Conditions at the end of
237 | optimization for examples removed by
238 | shrinking. WARNING: This might lead to
239 | sub-optimal solutions! */
240 | long compute_loo; /* if nonzero, computes leave-one-out
241 | estimates */
242 | double rho; /* parameter in xi/alpha-estimates and for
243 | pruning leave-one-out range [1..2] */
244 | long xa_depth; /* parameter in xi/alpha-estimates upper
245 | bounding the number of SV the current
246 | alpha_t is distributed over */
247 | char predfile[200]; /* file for predicitions on unlabeled examples
248 | in transduction */
249 | char alphafile[200]; /* file to store optimal alphas in. use
250 | empty string if alphas should not be
251 | output */
252 |
253 | /* you probably do not want to touch the following */
254 | double epsilon_const; /* tolerable error on eq-constraint */
255 | double epsilon_a; /* tolerable error on alphas at bounds */
256 | double opt_precision; /* precision of solver, set to e.g. 1e-21
257 | if you get convergence problems */
258 |
259 | /* the following are only for internal use */
260 | long svm_c_steps; /* do so many steps for finding optimal C */
261 | double svm_c_factor; /* increase C by this factor every step */
262 | double svm_costratio_unlab;
263 | double svm_unlabbound;
264 | double *svm_cost; /* individual upper bounds for each var */
265 | long totwords; /* number of features */
266 | } LEARN_PARM;
267 |
268 | typedef struct matrix {
269 | int n; /* number of rows */
270 | int m; /* number of colums */
271 | double **element;
272 | } MATRIX;
273 |
274 | typedef struct kernel_parm {
275 | long kernel_type; /* 0=linear, 1=poly, 2=rbf, 3=sigmoid,
276 | 4=custom, 5=matrix */
277 | long poly_degree;
278 | double rbf_gamma;
279 | double coef_lin;
280 | double coef_const;
281 | char custom[50]; /* for user supplied kernel */
282 | MATRIX *gram_matrix; /* here one can directly supply the kernel
283 | matrix. The matrix is accessed if
284 | kernel_type=5 is selected. */
285 | } KERNEL_PARM;
286 |
287 | typedef struct model {
288 | long sv_num;
289 | long at_upper_bound;
290 | double b;
291 | DOC **supvec;
292 | double *alpha;
293 | long *index; /* index from docnum to position in model */
294 | long totwords; /* number of features */
295 | long totdoc; /* number of training documents */
296 | KERNEL_PARM kernel_parm; /* kernel */
297 |
298 | /* the following values are not written to file */
299 | double loo_error,loo_recall,loo_precision; /* leave-one-out estimates */
300 | double xa_error,xa_recall,xa_precision; /* xi/alpha estimates */
301 | double *lin_weights; /* weights for linear case using
302 | folding */
303 | double maxdiff; /* precision, up to which this
304 | model is accurate */
305 | } MODEL;
306 |
307 | /* The following specifies a quadratic problem of the following form
308 |
309 | minimize g0 * x + 1/2 x' * G * x
310 | subject to ce*x - ce0 = 0
311 | l <= x <= u
312 | */
313 | typedef struct quadratic_program {
314 | long opt_n; /* number of variables */
315 | long opt_m; /* number of linear equality constraints */
316 | double *opt_ce,*opt_ce0; /* linear equality constraints
317 | opt_ce[i]*x - opt_ceo[i]=0 */
318 | double *opt_g; /* hessian of objective */
319 | double *opt_g0; /* linear part of objective */
320 | double *opt_xinit; /* initial value for variables */
321 | double *opt_low,*opt_up; /* box constraints */
322 | } QP;
323 |
324 | typedef struct kernel_cache {
325 | long *index; /* cache some kernel evalutations */
326 | CFLOAT *buffer; /* to improve speed */
327 | long *invindex;
328 | long *active2totdoc;
329 | long *totdoc2active;
330 | long *lru;
331 | long *occu;
332 | long elems;
333 | long max_elems;
334 | long time;
335 | long activenum;
336 | long buffsize;
337 | } KERNEL_CACHE;
338 |
339 |
340 | typedef struct timing_profile {
341 | double time_kernel;
342 | double time_opti;
343 | double time_shrink;
344 | double time_update;
345 | double time_model;
346 | double time_check;
347 | double time_select;
348 | } TIMING;
349 |
350 | typedef struct shrink_state {
351 | long *active;
352 | long *inactive_since;
353 | long deactnum;
354 | double **a_history; /* for shrinking with non-linear kernel */
355 | long maxhistory;
356 | double *last_a; /* for shrinking with linear kernel */
357 | double *last_lin; /* for shrinking with linear kernel */
358 | } SHRINK_STATE;
359 |
360 | typedef struct randpair {
361 | long val,sort;
362 | } RANDPAIR;
363 |
364 | double classify_example(MODEL *, DOC *);
365 | double classify_example_linear(MODEL *, DOC *);
366 | double kernel(KERNEL_PARM *, DOC *, DOC *);
367 | double single_kernel(KERNEL_PARM *, SVECTOR *, SVECTOR *);
368 | double custom_kernel(KERNEL_PARM *, SVECTOR *, SVECTOR *);
369 | SVECTOR *create_svector(WORD *, MexPhiCustom, double);
370 | SVECTOR *create_svector_shallow(WORD *, MexPhiCustom, double);
371 | SVECTOR *create_svector_n(double *, long, MexPhiCustom, double);
372 | SVECTOR *create_svector_n_r(double *, long, MexPhiCustom, double, double);
373 | SVECTOR *copy_svector(SVECTOR *);
374 | SVECTOR *copy_svector_shallow(SVECTOR *);
375 | void free_svector(SVECTOR *);
376 | void free_svector_shallow(SVECTOR *);
377 | double sprod_ss(SVECTOR *, SVECTOR *);
378 | SVECTOR* sub_ss(SVECTOR *, SVECTOR *);
379 | SVECTOR* sub_ss_r(SVECTOR *, SVECTOR *, double min_non_zero);
380 | SVECTOR* add_ss(SVECTOR *, SVECTOR *);
381 | SVECTOR* add_ss_r(SVECTOR *, SVECTOR *, double min_non_zero);
382 | SVECTOR* multadd_ss(SVECTOR *a, SVECTOR *b, double fa, double fb);
383 | SVECTOR* multadd_ss_r(SVECTOR *a,SVECTOR *b,double fa, double fb,
384 | double min_non_zero);
385 | SVECTOR* add_list_ns(SVECTOR *a);
386 | SVECTOR* add_dual_list_ns_r(SVECTOR *, SVECTOR *, double min_non_zero);
387 | SVECTOR* add_list_ns_r(SVECTOR *a, double min_non_zero);
388 | SVECTOR* add_list_ss(SVECTOR *);
389 | SVECTOR* add_dual_list_ss_r(SVECTOR *, SVECTOR *, double min_non_zero);
390 | SVECTOR* add_list_ss_r(SVECTOR *, double min_non_zero);
391 | SVECTOR* add_list_sort_ss(SVECTOR *);
392 | SVECTOR* add_dual_list_sort_ss_r(SVECTOR *, SVECTOR *, double min_non_zero);
393 | SVECTOR* add_list_sort_ss_r(SVECTOR *, double min_non_zero);
394 | void add_list_n_ns(double *vec_n, SVECTOR *vec_s, double faktor);
395 | void append_svector_list(SVECTOR *a, SVECTOR *b);
396 | void mult_svector_list(SVECTOR *a, double factor);
397 | void setfactor_svector_list(SVECTOR *a, double factor);
398 | SVECTOR* smult_s(SVECTOR *, double);
399 | SVECTOR* shift_s(SVECTOR *a, long shift);
400 | int featvec_eq(SVECTOR *, SVECTOR *);
401 | double model_length_s(MODEL *);
402 | double model_length_n(MODEL *);
403 | void mult_vector_ns(double *, SVECTOR *, double);
404 | void add_vector_ns(double *, SVECTOR *, double);
405 | double sprod_ns(double *, SVECTOR *);
406 | void add_weight_vector_to_linear_model(MODEL *);
407 | DOC *create_example(long, long, long, double, SVECTOR *);
408 | void free_example(DOC *, long);
409 | long *random_order(long n);
410 | void print_percent_progress(long *progress, long maximum,
411 | long percentperdot, char *symbol);
412 | MATRIX *create_matrix(int n, int m);
413 | MATRIX *realloc_matrix(MATRIX *matrix, int n, int m);
414 | double *create_nvector(int n);
415 | void clear_nvector(double *vec, long int n);
416 | MATRIX *copy_matrix(MATRIX *matrix);
417 | void free_matrix(MATRIX *matrix);
418 | void free_nvector(double *vector);
419 | MATRIX *transpose_matrix(MATRIX *matrix);
420 | MATRIX *cholesky_matrix(MATRIX *A);
421 | double *find_indep_subset_of_matrix(MATRIX *A, double epsilon);
422 | MATRIX *invert_ltriangle_matrix(MATRIX *L);
423 | double *prod_nvector_matrix(double *v, MATRIX *A);
424 | double *prod_matrix_nvector(MATRIX *A, double *v);
425 | double *prod_nvector_ltmatrix(double *v, MATRIX *A);
426 | double *prod_ltmatrix_nvector(MATRIX *A, double *v);
427 | MATRIX *prod_matrix_matrix(MATRIX *A, MATRIX *B);
428 | void print_matrix(MATRIX *matrix);
429 | MODEL *read_model(char *);
430 | MODEL *copy_model(MODEL *);
431 | MODEL *compact_linear_model(MODEL *model);
432 | void free_model(MODEL *, int);
433 | void read_documents(char *, DOC ***, double **, long *, long *);
434 | int parse_document(char *, WORD *, double *, long *, long *, double *, long *, long, char **);
435 | int read_word(char *in, char *out);
436 | double *read_alphas(char *,long);
437 | void set_learning_defaults(LEARN_PARM *, KERNEL_PARM *);
438 | int check_learning_parms(LEARN_PARM *, KERNEL_PARM *);
439 | void nol_ll(char *, long *, long *, long *);
440 | long minl(long, long);
441 | long maxl(long, long);
442 | double get_runtime(void);
443 | int space_or_null(int);
444 | void *my_malloc(size_t);
445 | void copyright_notice(void);
446 | # ifdef _MSC_VER
447 | int isnan(double);
448 | # endif
449 |
450 | extern long verbosity; /* verbosity level (0-4) */
451 | extern long kernel_cache_statistic;
452 |
453 | #endif
454 |
--------------------------------------------------------------------------------
/svm_struct_api.c:
--------------------------------------------------------------------------------
1 | /***********************************************************************/
2 | /* */
3 | /* svm_struct_api.c */
4 | /* */
5 | /* Definition of API for attaching implementing SVM learning of */
6 | /* structures (e.g. parsing, multi-label classification, HMM) */
7 | /* */
8 | /* Author: Thorsten Joachims */
9 | /* Date: 03.07.04 */
10 | /* */
11 | /* Copyright (c) 2004 Thorsten Joachims - All rights reserved */
12 | /* */
13 | /* This software is available for non-commercial use only. It must */
14 | /* not be modified and distributed without prior permission of the */
15 | /* author. The author is not responsible for implications from the */
16 | /* use of this software. */
17 | /* */
18 | /***********************************************************************/
19 |
20 | #include
21 | #include
22 | #include "svm_struct/svm_struct_common.h"
23 | #include "svm_struct_api.h"
24 |
25 | /** ------------------------------------------------------------------
26 | ** @brief
27 | **
28 | ** Called in learning part before anything else is done to allow any
29 | ** initializations that might be necessary.
30 | **/
31 |
32 | void
33 | svm_struct_learn_api_init(int argc, char* argv[])
34 | { }
35 |
36 | /** ------------------------------------------------------------------
37 | ** @brief
38 | **
39 | ** Called in learning part at the very end to allow any clean-up
40 | ** that might be necessary.
41 | **/
42 |
43 | void
44 | svm_struct_learn_api_exit()
45 | { }
46 |
47 | /** ------------------------------------------------------------------
48 | ** @brief
49 | **
50 | ** Called in prediction part before anything else is done to allow
51 | ** any initializations that might be necessary.
52 | **/
53 |
54 | void
55 | svm_struct_classify_api_init (int argc, char* argv[])
56 | { }
57 |
58 | /** ------------------------------------------------------------------
59 | ** @brief
60 | **
61 | ** Called in prediction part at the very end to allow any clean-up
62 | ** that might be necessary.
63 | **/
64 |
65 | void
66 | svm_struct_classify_api_exit()
67 | { }
68 |
69 | /** ------------------------------------------------------------------
70 | ** @brief Initialize structured model
71 | **
72 | ** Initialize structmodel sm. The weight vector w does not need to be
73 | ** initialized, but you need to provide the maximum size of the
74 | ** feature space in sizePsi. This is the maximum number of different
75 | ** weights that can be learned. Later, the weight vector w will
76 | ** contain the learned weights for the model.
77 | **/
78 |
79 | void
80 | init_struct_model (SAMPLE sample, STRUCTMODEL *sm,
81 | STRUCT_LEARN_PARM *sparm, LEARN_PARM *lparm,
82 | KERNEL_PARM *kparm)
83 | {
84 | if (kparm->kernel_type == LINEAR) {
85 | mxArray const * sizePsi_array = mxGetField(sparm->mex, 0, "dimension") ;
86 | if (! sizePsi_array) {
87 | mexErrMsgTxt("Field PARM.DIMENSION not found") ;
88 | }
89 | if (! uIsRealScalar(sizePsi_array)) {
90 | mexErrMsgTxt("PARM.DIMENSION must be a scalar") ;
91 | }
92 |
93 | sm->sizePsi = *mxGetPr(sizePsi_array) ;
94 | if (sm->sizePsi < 1) {
95 | mexErrMsgTxt("PARM.DIMENSION must be not smaller than 1") ;
96 | }
97 | } else {
98 | sm -> sizePsi = 0 ;
99 | }
100 | }
101 |
102 | /** ------------------------------------------------------------------
103 | ** @brief Initialize structred model constraints
104 | **
105 | ** Initializes the optimization problem. Typically, you do not need
106 | ** to change this function, since you want to start with an empty set
107 | ** of constraints. However, if for example you have constraints that
108 | ** certain weights need to be positive, you might put that in
109 | ** here. The constraints are represented as lhs[i]*w >= rhs[i]. lhs
110 | ** is an array of feature vectors, rhs is an array of doubles. m is
111 | ** the number of constraints. The function returns the initial set of
112 | ** constraints.
113 | **/
114 |
115 | CONSTSET
116 | init_struct_constraints (SAMPLE sample, STRUCTMODEL *sm,
117 | STRUCT_LEARN_PARM *sparm)
118 | {
119 |
120 | CONSTSET c;
121 | long sizePsi=sm->sizePsi;
122 | long i;
123 | WORD words[2];
124 |
125 | if(1) { /* normal case: start with empty set of constraints */
126 | c.lhs=NULL;
127 | c.rhs=NULL;
128 | c.m=0;
129 | }
130 | else { /* add constraints so that all learned weights are
131 | positive. WARNING: Currently, they are positive only up to
132 | precision epsilon set by -e. */
133 | c.lhs=my_malloc(sizeof(DOC *)*sizePsi);
134 | c.rhs=my_malloc(sizeof(double)*sizePsi);
135 | for(i=0; isizePsi. If the
156 | ** function cannot find a label, it shall return an empty label as
157 | ** recognized by the function empty_label(y).
158 | **/
159 |
160 | LABEL
161 | classify_struct_example (PATTERN x,
162 | STRUCTMODEL *sm,
163 | STRUCT_LEARN_PARM *sparm)
164 | {
165 | LABEL y ;
166 |
167 | mxArray* fn_array ;
168 | mxArray* w_array ;
169 | mxArray* args [4] ;
170 | int status ;
171 |
172 | fn_array= mxGetField(sparm->mex, 0, "classifyFn") ;
173 | if (! fn_array) {
174 | mexErrMsgTxt("Field PARM.CLASSIFYFN not found") ;
175 | }
176 | if (! mxGetClassID(fn_array) == mxFUNCTION_CLASS) {
177 | mexErrMsgTxt("PARM.CLASSIFYFN must be a valid function handle") ;
178 | }
179 |
180 | /* encapsulate sm->w into a Matlab array */
181 | w_array = mxCreateDoubleMatrix(sm->sizePsi, 1, mxREAL) ;
182 | memcpy(mxGetPr(w_array),
183 | sm->w + 1,
184 | sm->sizePsi * sizeof(double)) ;
185 |
186 | /* evaluate Matlab callback */
187 | args[0] = fn_array ;
188 | args[1] = (mxArray*) sparm->mex ; /* model (discard conts) */
189 | args[2] = w_array ;
190 | args[3] = x.mex ;
191 |
192 | status = mexCallMATLAB(1, &y.mex, 4, args, "feval") ;
193 |
194 | mxDestroyArray(w_array) ;
195 |
196 | if (status) {
197 | mexErrMsgTxt("Error while executing PARM.CLASSIFYFN") ;
198 | }
199 | if (mxGetClassID(y.mex) == mxUNKNOWN_CLASS) {
200 | mexErrMsgTxt("PARM.CLASSIFYFN did not reutrn a result") ;
201 | }
202 |
203 | /* flag this label has one tha should be freed when discared */
204 | y.isOwner = 1 ;
205 |
206 | return (y) ;
207 | }
208 |
209 | /** ------------------------------------------------------------------
210 | ** @brief Find the most violated constraint with slack rescaling
211 | **
212 | ** Finds the label ybar for pattern x that that is responsible for
213 | ** the most violated constraint for the slack rescaling
214 | ** formulation. For linear slack variables, this is that label ybar
215 | ** that maximizes
216 | **
217 | ** argmax_{ybar} loss(y,ybar)*(1-psi(x,y)+psi(x,ybar))
218 | **
219 | ** Note that ybar may be equal to y (i.e. the max is 0), which is
220 | ** different from the algorithms described in
221 | ** [Tschantaridis/05]. Note that this argmax has to take into account
222 | ** the scoring function in sm, especially the weights sm.w, as well
223 | ** as the loss function, and whether linear or quadratic slacks are
224 | ** used. The weights in sm.w correspond to the features defined by
225 | ** psi() and range from index 1 to index sm->sizePsi. Most simple is
226 | ** the case of the zero/one loss function. For the zero/one loss,
227 | ** this function should return the highest scoring label ybar (which
228 | ** may be equal to the correct label y), or the second highest
229 | ** scoring label ybar, if Psi(x,ybar)>Psi(x,y)-1. If the function
230 | ** cannot find a label, it shall return an empty label as recognized
231 | ** by the function empty_label(y).
232 | **/
233 |
234 | LABEL
235 | find_most_violated_constraint_slackrescaling (PATTERN x, LABEL y,
236 | STRUCTMODEL *sm,
237 | STRUCT_LEARN_PARM *sparm)
238 | {
239 | LABEL ybar ;
240 |
241 | mxArray* fn_array ;
242 | mxArray* model_array ;
243 | mxArray* args [5] ;
244 | int status ;
245 |
246 | fn_array = mxGetField(sparm->mex, 0, "constraintFn") ;
247 | if (! fn_array) {
248 | mexErrMsgTxt("Field PARM.CONSTRAINTFN not found") ;
249 | }
250 | if (! mxGetClassID(fn_array) == mxFUNCTION_CLASS) {
251 | mexErrMsgTxt("PARM.CONSTRAINTFN must be a valid function handle") ;
252 | }
253 |
254 | /* encapsulate sm->w into a Matlab array */
255 | model_array = newMxArrayEncapsulatingSmodel (sm) ;
256 |
257 | args[0] = fn_array ;
258 | args[1] = (mxArray*) sparm->mex ; /* model (discard conts) */
259 | args[2] = model_array ;
260 | args[3] = x.mex ;
261 | args[4] = y.mex ;
262 |
263 | /* Apparently we must make sure that model_array is not destoryed by
264 | the automatic cleaning up function. It seems that, because it is constructed by
265 | encapsulating input argument to the MEX file, it must be considered an hybrid
266 | array, i.e. an array which cannot be destroyed by MATLAB automatic
267 | cleanup system, invoked when an error is raised */
268 |
269 | mexSetTrapFlag (1) ;
270 | status = mexCallMATLAB(1, &ybar.mex, 5, args, "feval") ;
271 | mexSetTrapFlag (0) ;
272 |
273 | destroyMxArrayEncapsulatingSmodel (model_array) ;
274 |
275 | if (status) {
276 | mxArray * error_array ;
277 | mexCallMATLAB(1, &error_array, 0, NULL, "lasterror") ;
278 | mexCallMATLAB(0, NULL, 1, &error_array, "disp") ;
279 | mexCallMATLAB(0, NULL, 1, &error_array, "rethrow") ;
280 | }
281 | if (mxGetClassID(ybar.mex) == mxUNKNOWN_CLASS) {
282 | mexErrMsgTxt("PARM.CONSTRAINTFN did not reutrn a result") ;
283 | }
284 | ybar.isOwner = 1 ;
285 |
286 | return(ybar);
287 | }
288 |
289 | /** ------------------------------------------------------------------
290 | ** @brief Find the most violated constraint with margin rescaling
291 | ** Finds the label ybar for pattern x that that is responsible for
292 | ** the most violated constraint for the margin rescaling
293 | ** formulation. For linear slack variables, this is that label ybar
294 | ** that maximizes
295 | **
296 | ** argmax_{ybar} loss(y,ybar)+psi(x,ybar)
297 | **
298 | ** Note that ybar may be equal to y (i.e. the max is 0), which is
299 | ** different from the algorithms described in
300 | ** [Tschantaridis/05]. Note that this argmax has to take into account
301 | ** the scoring function in sm, especially the weights sm.w, as well
302 | ** as the loss function, and whether linear or quadratic slacks are
303 | ** used. The weights in sm.w correspond to the features defined by
304 | ** psi() and range from index 1 to index sm->sizePsi. Most simple is
305 | ** the case of the zero/one loss function. For the zero/one loss,
306 | ** this function should return the highest scoring label ybar (which
307 | ** may be equal to the correct label y), or the second highest
308 | ** scoring label ybar, if Psi(x,ybar)>Psi(x,y)-1. If the function
309 | ** cannot find a label, it shall return an empty label as recognized
310 | ** by the function empty_label(y).
311 | **/
312 |
313 | LABEL
314 | find_most_violated_constraint_marginrescaling (PATTERN x, LABEL y,
315 | STRUCTMODEL *sm,
316 | STRUCT_LEARN_PARM *sparm)
317 | {
318 | LABEL ybar ;
319 | mxArray* fn_array ;
320 | mxArray* model_array ;
321 | mxArray* args [5] ;
322 | int status ;
323 |
324 | fn_array = mxGetField(sparm->mex, 0, "constraintFn") ;
325 | if (! fn_array) {
326 | mexErrMsgTxt("Field PARM.CONSTRAINTFN not found") ;
327 | }
328 | if (! mxGetClassID(fn_array) == mxFUNCTION_CLASS) {
329 | mexErrMsgTxt("PARM.CONSTRAINTFN is not a valid function handle") ;
330 | }
331 |
332 | /* encapsulate sm->w into a Matlab array */
333 | model_array = newMxArrayEncapsulatingSmodel (sm) ;
334 |
335 | args[0] = fn_array ;
336 | args[1] = (mxArray*) sparm->mex ; /* model (discard conts) */
337 | args[2] = model_array ;
338 | args[3] = x.mex ;
339 | args[4] = y.mex ;
340 |
341 | mexSetTrapFlag (1) ;
342 | status = mexCallMATLAB(1, &ybar.mex, 5, args, "feval") ;
343 | mexSetTrapFlag (0) ;
344 |
345 | destroyMxArrayEncapsulatingSmodel (model_array) ;
346 |
347 | if (status) {
348 | mxArray * error_array ;
349 | mexCallMATLAB(1, &error_array, 0, NULL, "lasterror") ;
350 | mexCallMATLAB(0, NULL, 1, &error_array, "error") ;
351 | }
352 | if (mxGetClassID(ybar.mex) == mxUNKNOWN_CLASS) {
353 | mexErrMsgTxt("PARM.CONSTRAINTFN did not reutrn a result") ;
354 | }
355 | ybar.isOwner = 1 ;
356 |
357 | return (ybar) ;
358 | }
359 |
360 | /** ------------------------------------------------------------------
361 | ** @brief Is the label empty?
362 | **
363 | ** Returns true, if y is an empty label. An empty label might be
364 | ** returned by find_most_violated_constraint_???(x, y, sm) if there
365 | ** is no incorrect label that can be found for x, or if it is unable
366 | ** to label x at all.
367 | **/
368 |
369 | int
370 | empty_label (LABEL y)
371 | {
372 | return (y.mex == NULL) ;
373 | }
374 |
375 | /** ------------------------------------------------------------------
376 | ** @brief Evaluate Psi(x, y)
377 | **
378 | ** Returns a feature vector describing the match between pattern x
379 | ** and label y. The feature vector is returned as a list of
380 | ** SVECTOR's. Each SVECTOR is in a sparse representation of pairs
381 | ** , where the last pair has
382 | ** featurenumber 0 as a terminator. Featurenumbers start with 1 and
383 | ** end with sizePsi. Featuresnumbers that are not specified default
384 | ** to value 0. As mentioned before, psi() actually returns a list of
385 | ** SVECTOR's. Each SVECTOR has a field 'factor' and 'next'. 'next'
386 | ** specifies the next element in the list, terminated by a NULL
387 | ** pointer. The list can be though of as a linear combination of
388 | ** vectors, where each vector is weighted by its 'factor'. This
389 | ** linear combination of feature vectors is multiplied with the
390 | ** learned (kernelized) weight vector to score label y for pattern
391 | ** x. Without kernels, there will be one weight in sm.w for each
392 | ** feature. Note that psi has to match
393 | ** find_most_violated_constraint_???(x, y, sm) and vice versa. In
394 | ** particular, find_most_violated_constraint_???(x, y, sm) finds that
395 | ** ybar!=y that maximizes psi(x,ybar,sm)*sm.w (where * is the inner
396 | ** vector product) and the appropriate function of the loss +
397 | ** margin/slack rescaling method. See that paper for details.
398 | **/
399 |
400 | SVECTOR *
401 | psi (PATTERN x, LABEL y, STRUCTMODEL *sm,
402 | STRUCT_LEARN_PARM *sparm)
403 | {
404 | SVECTOR *sv = NULL;
405 |
406 | /* The algorith can use either a linear kernel (explicit feature map)
407 | * or a custom kernel (implicit feature map). For the explicit feature
408 | * map, this function returns a sizePhi-dimensional vector. For
409 | * the implicit feature map this function returns a placeholder
410 | */
411 |
412 | if (sm -> svm_model -> kernel_parm .kernel_type == LINEAR) {
413 | /* For the linear kernel computes the vector Phi(x,y) */
414 | mxArray* out ;
415 | mxArray* fn_array ;
416 | mxArray* args [4] ;
417 | WORD* words = NULL ;
418 | double twonorm_sq = 0 ;
419 | int status ;
420 |
421 | fn_array = mxGetField(sparm->mex, 0, "featureFn") ;
422 | if (! fn_array) {
423 | mexErrMsgTxt("Field PARM.FEATUREFN not found") ;
424 | }
425 | if (! mxGetClassID(fn_array) == mxFUNCTION_CLASS) {
426 | mexErrMsgTxt("PARM.FEATUREFN must be a valid function handle") ;
427 | }
428 |
429 | args[0] = fn_array ;
430 | args[1] = (mxArray*) sparm->mex ; /* model (discard conts) */
431 | args[2] = x.mex ; /* pattern */
432 | args[3] = y.mex ; /* label */
433 | status = mexCallMATLAB(1, &out, 4, args, "feval") ;
434 |
435 | if (status) {
436 | mexErrMsgTxt("Error while executing PARM.FEATUREFN") ;
437 | }
438 | if (mxGetClassID(out) == mxUNKNOWN_CLASS) {
439 | mexErrMsgTxt("PARM.FEATUREFN must reutrn a result") ;
440 | }
441 |
442 | if (! mxIsSparse(out) ||
443 | ! mxGetClassID(out) == mxDOUBLE_CLASS ||
444 | ! mxGetN(out) == 1 ||
445 | ! mxGetM(out) == sm->sizePsi) {
446 | mexErrMsgTxt("PARM.FEATUREFN must return a sparse column vector "
447 | "of the prescribed size") ;
448 | }
449 |
450 | {
451 | double * data = mxGetPr(out) ;
452 | int i ;
453 | mwIndex * colOffsets = mxGetJc(out) ;
454 | mwIndex * rowIndexes = mxGetIr(out) ;
455 | int numNZ = colOffsets[1] - colOffsets[0] ;
456 |
457 | words = (WORD*) my_malloc (sizeof(WORD) * (numNZ + 1)) ;
458 |
459 | for (i = 0 ; i < numNZ ; ++ i) {
460 | words[i].wnum = rowIndexes[i] + 1 ;
461 | words[i].weight = data[i] ;
462 | twonorm_sq += data[i] * data[i] ;
463 | }
464 | words[numNZ].wnum = 0 ;
465 | words[numNZ].weight = 0 ;
466 | }
467 |
468 | sv = create_svector_shallow (words, NULL, 1.0) ;
469 | sv->twonorm_sq = twonorm_sq ;
470 |
471 | mxDestroyArray (out) ;
472 | }
473 | else {
474 | /* For the ustom kernel returns a placeholder for (x,y). */
475 | MexPhiCustom phi = newMexPhiCustomFromPatternLabel(x.mex, y.mex) ;
476 | WORD * words = mxMalloc(sizeof(WORD)) ;
477 | words[0].wnum = 0 ;
478 | words[0].weight = 0 ;
479 | sv = create_svector_shallow(words, phi, 1.0) ;
480 | }
481 |
482 | return (sv) ;
483 | }
484 |
485 | /** ------------------------------------------------------------------
486 | ** @brief Evaluate loss function Delta(y, ybar)
487 | **/
488 |
489 | double
490 | loss (LABEL y, LABEL ybar, STRUCT_LEARN_PARM *sparm)
491 | {
492 |
493 | double loss_value ;
494 | mxArray* fn_array ;
495 | mxArray* out ;
496 | mxArray* args [4] ;
497 | int status ;
498 |
499 | fn_array = mxGetField(sparm->mex, 0, "lossFn") ;
500 | if (! fn_array) {
501 | mexErrMsgTxt("Field PARM.LOSSFN not found") ;
502 | }
503 | if (! mxGetClassID(fn_array) == mxFUNCTION_CLASS) {
504 | mexErrMsgTxt("PARM.LOSSFN must be a valid function handle") ;
505 | }
506 |
507 | args[0] = fn_array ;
508 | args[1] = (mxArray*) sparm->mex ; /* model (discard conts) */
509 | args[2] = y.mex ;
510 | args[3] = ybar.mex ;
511 |
512 | status = mexCallMATLAB (1, &out, 4, args, "feval") ;
513 |
514 | if (status) {
515 | mexErrMsgTxt("Error while executing PARM.LOSSFN") ;
516 | }
517 | if (! uIsRealScalar(out)) {
518 | mexErrMsgTxt("PARM.LOSSFN must reutrn a scalar") ;
519 | }
520 |
521 | loss_value = *mxGetPr(out) ;
522 | mxDestroyArray(out) ;
523 |
524 | return (loss_value) ;
525 | }
526 |
527 | /** ------------------------------------------------------------------
528 | ** This function is called just before the end of each cutting plane
529 | ** iteration. ceps is the amount by which the most violated
530 | ** constraint found in the current iteration was
531 | ** violated. cached_constraint is true if the added constraint was
532 | ** constructed from the cache. If the return value is FALSE, then the
533 | ** algorithm is allowed to terminate. If it is TRUE, the algorithm
534 | ** will keep iterating even if the desired precision sparm->epsilon
535 | ** is already reached.
536 | **/
537 |
538 | int
539 | finalize_iteration (double ceps, int cached_constraint,
540 | SAMPLE sample, STRUCTMODEL *sm,
541 | CONSTSET cset, double *alpha,
542 | STRUCT_LEARN_PARM *sparm)
543 | {
544 | mxArray* fn_array ;
545 | mxArray* model_array ;
546 | mxArray* out ;
547 | mxArray* args [3] ;
548 | int status ;
549 | int result = 0 ;
550 |
551 | fn_array = mxGetField(sparm->mex, 0, "endIterationFn") ;
552 |
553 | if (! fn_array) return 0 ;
554 | if (! mxGetClassID(fn_array) == mxFUNCTION_CLASS) {
555 | mexErrMsgTxt("PARM.ENDITERATIONFN must be a valid function handle") ;
556 | }
557 |
558 | /* encapsulate sm->w into a Matlab array */
559 | model_array = newMxArrayEncapsulatingSmodel (sm) ;
560 |
561 | args[0] = fn_array ;
562 | args[1] = (mxArray*) sparm->mex ; /* model (discard conts) */
563 | args[2] = model_array ;
564 |
565 | status = mexCallMATLAB (1, &out, 3, args, "feval") ;
566 |
567 | destroyMxArrayEncapsulatingSmodel (model_array) ;
568 |
569 | if (status) {
570 | mexErrMsgTxt("Error while executing PARM.ENDITERATIONFN") ;
571 | }
572 |
573 | if (! uIsLogicalScalar(out)) {
574 | mexErrMsgTxt("PARM.ENDITERATIONFN must reutrn nothing or a scalar") ;
575 | }
576 | result = (int) (*mxGetLogicals(out)) ;
577 | mxDestroyArray(out) ;
578 | return result ;
579 | }
580 |
581 | /** ------------------------------------------------------------------
582 | ** This function is called after training and allows final touches to
583 | ** the model sm. But primarly it allows computing and printing any
584 | ** kind of statistic (e.g. training error) you might want.
585 | **/
586 |
587 | void
588 | print_struct_learning_stats (SAMPLE sample, STRUCTMODEL *sm,
589 | CONSTSET cset, double *alpha,
590 | STRUCT_LEARN_PARM *sparm)
591 | {
592 |
593 | }
594 |
595 | /** ------------------------------------------------------------------
596 | ** This function is called after making all test predictions in
597 | ** svm_struct_classify and allows computing and printing any kind of
598 | ** evaluation (e.g. precision/recall) you might want. You can use the
599 | ** function eval_prediction to accumulate the necessary statistics for
600 | ** each prediction.
601 | **/
602 |
603 | void
604 | print_struct_testing_stats (SAMPLE sample, STRUCTMODEL *sm,
605 | STRUCT_LEARN_PARM *sparm,
606 | STRUCT_TEST_STATS *teststats)
607 | {
608 |
609 | }
610 |
611 | /** ------------------------------------------------------------------
612 | ** This function allows you to accumlate statistic for how well the
613 | ** predicition matches the labeled example. It is called from
614 | ** svm_struct_classify. See also the function
615 | ** print_struct_testing_stats.
616 | **/
617 |
618 | void
619 | eval_prediction (long exnum, EXAMPLE ex, LABEL ypred,
620 | STRUCTMODEL *sm, STRUCT_LEARN_PARM *sparm,
621 | STRUCT_TEST_STATS *teststats)
622 | {
623 | if(exnum == 0) { /* this is the first time the function is
624 | called. So initialize the teststats */
625 | }
626 | }
627 |
628 | /** ------------------------------------------------------------------
629 | ** Frees the memory of x.
630 | **/
631 |
632 | void
633 | free_pattern (PATTERN x)
634 | { }
635 |
636 | /** ------------------------------------------------------------------
637 | ** Frees the memory of y.
638 | **/
639 |
640 | void
641 | free_label (LABEL y)
642 | {
643 | if (y.isOwner && y.mex) {
644 | mxDestroyArray(y.mex) ;
645 | }
646 | }
647 |
648 | /** ------------------------------------------------------------------
649 | ** Frees the memory of model.
650 | **/
651 |
652 | void
653 | free_struct_model (STRUCTMODEL sm)
654 | {
655 | if(sm.svm_model) free_model(sm.svm_model, 1 );
656 | /* add free calls for user defined data here */
657 | }
658 |
659 | /** ------------------------------------------------------------------
660 | ** Frees the memory of a sample.
661 | **/
662 |
663 | void
664 | free_struct_sample (SAMPLE s)
665 | {
666 | int i;
667 | for(i=0;i custom parameters that can be adapted for struct\n");
683 | printf(" learning. The * can be replaced by any character\n");
684 | printf(" and there can be multiple options starting with --.\n");
685 | }
686 |
687 | /** ------------------------------------------------------------------
688 | ** Parses the command line parameters that start with --
689 | **/
690 |
691 | void
692 | parse_struct_parameters(STRUCT_LEARN_PARM *sparm)
693 | {
694 |
695 | int i;
696 |
697 | for(i=0;(icustom_argc) && ((sparm->custom_argv[i])[0] == '-');i++) {
698 | switch ((sparm->custom_argv[i])[2]) {
699 | case 'a': i++; /* strcpy(learn_parm->alphafile,argv[i]); */ break;
700 | case 'e': i++; /* sparm->epsilon=atof(sparm->custom_argv[i]); */ break;
701 | case 'k': i++; /* sparm->newconstretrain=atol(sparm->custom_argv[i]); */ break;
702 | default: printf("\nUnrecognized option %s!\n\n",sparm->custom_argv[i]);
703 | exit(0);
704 | }
705 | }
706 | }
707 |
708 | /** ------------------------------------------------------------------
709 | ** Prints a help text that is appended to the common help text of
710 | ** svm_struct_classify.
711 | **/
712 |
713 | void
714 | print_struct_help_classify()
715 | {
716 | printf(" --* string -> custom parameters that can be adapted for struct\n");
717 | printf(" learning. The * can be replaced by any character\n");
718 | printf(" and there can be multiple options starting with --.\n");
719 | }
720 |
721 | /** ------------------------------------------------------------------
722 | ** Parses the command line parameters that start with -- for the
723 | ** classification module.
724 | **/
725 |
726 | void
727 | parse_struct_parameters_classify (STRUCT_LEARN_PARM *sparm)
728 | {
729 | int i;
730 |
731 | for(i=0;(icustom_argc) && ((sparm->custom_argv[i])[0] == '-');i++) {
732 | switch ((sparm->custom_argv[i])[2]) {
733 | /* case 'x': i++; strcpy(xvalue,sparm->custom_argv[i]); break; */
734 | default: printf("\nUnrecognized option %s!\n\n",sparm->custom_argv[i]);
735 | exit(0);
736 | }
737 | }
738 | }
739 |
740 |
--------------------------------------------------------------------------------
/svm_light/svm_hideo.c:
--------------------------------------------------------------------------------
1 | /***********************************************************************/
2 | /* */
3 | /* svm_hideo.c */
4 | /* */
5 | /* The Hildreth and D'Espo solver specialized for SVMs. */
6 | /* */
7 | /* Author: Thorsten Joachims */
8 | /* Date: 02.07.02 */
9 | /* */
10 | /* Copyright (c) 2002 Thorsten Joachims - All rights reserved */
11 | /* */
12 | /* This software is available for non-commercial use only. It must */
13 | /* not be modified and distributed without prior permission of the */
14 | /* author. The author is not responsible for implications from the */
15 | /* use of this software. */
16 | /* */
17 | /***********************************************************************/
18 |
19 | # include
20 | # include "svm_common.h"
21 |
22 | /*
23 | solve the quadratic programming problem
24 |
25 | minimize g0 * x + 1/2 x' * G * x
26 | subject to ce*x - ce0 = 0
27 | l <= x <= u
28 |
29 | The linear constraint vector ce can only have -1/+1 as entries
30 | */
31 |
32 | /* Common Block Declarations */
33 |
34 | /* long verbosity; */
35 |
36 | # define PRIMAL_OPTIMAL 1
37 | # define DUAL_OPTIMAL 2
38 | # define MAXITER_EXCEEDED 3
39 | # define NAN_SOLUTION 4
40 | # define ONLY_ONE_VARIABLE 5
41 |
42 | # define LARGEROUND 0
43 | # define SMALLROUND 1
44 |
45 | /* /////////////////////////////////////////////////////////////// */
46 |
47 | # define DEF_PRECISION 1E-5
48 | # define DEF_MAX_ITERATIONS 200
49 | # define DEF_LINDEP_SENSITIVITY 1E-8
50 | # define EPSILON_HIDEO 1E-20
51 | # define EPSILON_EQ 1E-5
52 |
53 | double *optimize_qp(QP *, double *, long, double *, LEARN_PARM *);
54 | double *primal=0,*dual=0;
55 | long precision_violations=0;
56 | double opt_precision=DEF_PRECISION;
57 | long maxiter=DEF_MAX_ITERATIONS;
58 | double lindep_sensitivity=DEF_LINDEP_SENSITIVITY;
59 | double *buffer;
60 | long *nonoptimal;
61 |
62 | long smallroundcount=0;
63 | long roundnumber=0;
64 |
65 | /* /////////////////////////////////////////////////////////////// */
66 |
67 | void *my_malloc();
68 |
69 | int optimize_hildreth_despo(long,long,double,double,double,long,long,long,double,double *,
70 | double *,double *,double *,double *,double *,
71 | double *,double *,double *,long *,double *,double *);
72 | int solve_dual(long,long,double,double,long,double *,double *,double *,
73 | double *,double *,double *,double *,double *,double *,
74 | double *,double *,double *,double *,long);
75 |
76 | void linvert_matrix(double *, long, double *, double, long *);
77 | void lprint_matrix(double *, long);
78 | void ladd_matrix(double *, long, double);
79 | void lcopy_matrix(double *, long, double *);
80 | void lswitch_rows_matrix(double *, long, long, long);
81 | void lswitchrk_matrix(double *, long, long, long);
82 |
83 | double calculate_qp_objective(long, double *, double *, double *);
84 |
85 |
86 | void init_qp_solver()
87 | {
88 | primal = 0 ;
89 | dual = 0 ;
90 | precision_violations = 0 ;
91 | opt_precision = DEF_PRECISION ;
92 | maxiter = DEF_MAX_ITERATIONS ;
93 | lindep_sensitivity = DEF_LINDEP_SENSITIVITY ;
94 | buffer = 0 ;
95 | nonoptimal = 0 ;
96 | smallroundcount = 0 ;
97 | roundnumber = 0 ;
98 | }
99 |
100 | void free_qp_solver()
101 | {
102 | if(buffer) {free(buffer) ; buffer = 0 ;}
103 | if(nonoptimal) {free(nonoptimal) ; nonoptimal = 0; }
104 | if(dual) {free(dual) ; dual = 0 ;}
105 | if(primal) {free(primal) ; primal = 0;}
106 | }
107 |
108 | double *optimize_qp(qp,epsilon_crit,nx,threshold,learn_parm)
109 | QP *qp;
110 | double *epsilon_crit;
111 | long nx; /* Maximum number of variables in QP */
112 | double *threshold;
113 | LEARN_PARM *learn_parm;
114 | /* start the optimizer and return the optimal values */
115 | /* The HIDEO optimizer does not necessarily fully solve the problem. */
116 | /* Since it requires a strictly positive definite hessian, the solution */
117 | /* is restricted to a linear independent subset in case the matrix is */
118 | /* only semi-definite. */
119 | {
120 | long i,j;
121 | int result;
122 | double eq,progress;
123 |
124 | roundnumber++;
125 |
126 | if(!primal) { /* allocate memory at first call */
127 | primal=(double *)my_malloc(sizeof(double)*nx);
128 | dual=(double *)my_malloc(sizeof(double)*((nx+1)*2));
129 | nonoptimal=(long *)my_malloc(sizeof(long)*(nx));
130 | buffer=(double *)my_malloc(sizeof(double)*((nx+1)*2*(nx+1)*2+
131 | nx*nx+2*(nx+1)*2+2*nx+1+2*nx+
132 | nx+nx+nx*nx));
133 | (*threshold)=0;
134 | for(i=0;i=4) { /* really verbose */
140 | printf("\n\n");
141 | eq=qp->opt_ce0[0];
142 | for(i=0;iopt_n;i++) {
143 | eq+=qp->opt_xinit[i]*qp->opt_ce[i];
144 | printf("%f: ",qp->opt_g0[i]);
145 | for(j=0;jopt_n;j++) {
146 | printf("%f ",qp->opt_g[i*qp->opt_n+j]);
147 | }
148 | printf(": a=%.10f < %f",qp->opt_xinit[i],qp->opt_up[i]);
149 | printf(": y=%f\n",qp->opt_ce[i]);
150 | }
151 | if(qp->opt_m) {
152 | printf("EQ: %f*x0",qp->opt_ce[0]);
153 | for(i=1;iopt_n;i++) {
154 | printf(" + %f*x%ld",qp->opt_ce[i],i);
155 | }
156 | printf(" = %f\n\n",-qp->opt_ce0[0]);
157 | }
158 | }
159 |
160 | result=optimize_hildreth_despo(qp->opt_n,qp->opt_m,
161 | opt_precision,(*epsilon_crit),
162 | learn_parm->epsilon_a,maxiter,
163 | /* (long)PRIMAL_OPTIMAL, */
164 | (long)0, (long)0,
165 | lindep_sensitivity,
166 | qp->opt_g,qp->opt_g0,qp->opt_ce,qp->opt_ce0,
167 | qp->opt_low,qp->opt_up,primal,qp->opt_xinit,
168 | dual,nonoptimal,buffer,&progress);
169 | if(verbosity>=3) {
170 | printf("return(%d)...",result);
171 | }
172 |
173 | if(learn_parm->totwords < learn_parm->svm_maxqpsize) {
174 | /* larger working sets will be linear dependent anyway */
175 | learn_parm->svm_maxqpsize=maxl(learn_parm->totwords,(long)2);
176 | }
177 |
178 | if(result == NAN_SOLUTION) {
179 | lindep_sensitivity*=2; /* throw out linear dependent examples more */
180 | /* generously */
181 | if(learn_parm->svm_maxqpsize>2) {
182 | learn_parm->svm_maxqpsize--; /* decrease size of qp-subproblems */
183 | }
184 | precision_violations++;
185 | }
186 |
187 | /* take one round of only two variable to get unstuck */
188 | if((result != PRIMAL_OPTIMAL) || (!(roundnumber % 31)) || (progress <= 0)) {
189 |
190 | smallroundcount++;
191 |
192 | result=optimize_hildreth_despo(qp->opt_n,qp->opt_m,
193 | opt_precision,(*epsilon_crit),
194 | learn_parm->epsilon_a,(long)maxiter,
195 | (long)PRIMAL_OPTIMAL,(long)SMALLROUND,
196 | lindep_sensitivity,
197 | qp->opt_g,qp->opt_g0,qp->opt_ce,qp->opt_ce0,
198 | qp->opt_low,qp->opt_up,primal,qp->opt_xinit,
199 | dual,nonoptimal,buffer,&progress);
200 | if(verbosity>=3) {
201 | printf("return_srd(%d)...",result);
202 | }
203 |
204 | if(result != PRIMAL_OPTIMAL) {
205 | if(result != ONLY_ONE_VARIABLE)
206 | precision_violations++;
207 | if(result == MAXITER_EXCEEDED)
208 | maxiter+=100;
209 | if(result == NAN_SOLUTION) {
210 | lindep_sensitivity*=2; /* throw out linear dependent examples more */
211 | /* generously */
212 | /* results not valid, so return inital values */
213 | for(i=0;iopt_n;i++) {
214 | primal[i]=qp->opt_xinit[i];
215 | }
216 | }
217 | }
218 | }
219 |
220 |
221 | if(precision_violations > 50) {
222 | precision_violations=0;
223 | (*epsilon_crit)*=10.0;
224 | if(verbosity>=1) {
225 | printf("\nWARNING: Relaxing epsilon on KT-Conditions (%f).\n",
226 | (*epsilon_crit));
227 | }
228 | }
229 |
230 | if((qp->opt_m>0) && (result != NAN_SOLUTION) && (!isnan(dual[1]-dual[0])))
231 | (*threshold)=dual[1]-dual[0];
232 | else
233 | (*threshold)=0;
234 |
235 | if(verbosity>=4) { /* really verbose */
236 | printf("\n\n");
237 | eq=qp->opt_ce0[0];
238 | for(i=0;iopt_n;i++) {
239 | eq+=primal[i]*qp->opt_ce[i];
240 | printf("%f: ",qp->opt_g0[i]);
241 | for(j=0;jopt_n;j++) {
242 | printf("%f ",qp->opt_g[i*qp->opt_n+j]);
243 | }
244 | printf(": a=%.30f",primal[i]);
245 | printf(": nonopti=%ld",nonoptimal[i]);
246 | printf(": y=%f\n",qp->opt_ce[i]);
247 | }
248 | printf("eq-constraint=%.30f\n",eq);
249 | printf("b=%f\n",(*threshold));
250 | printf(" smallroundcount=%ld ",smallroundcount);
251 | }
252 |
253 | return(primal);
254 | }
255 |
256 |
257 |
258 | int optimize_hildreth_despo(n,m,precision,epsilon_crit,epsilon_a,maxiter,goal,
259 | smallround,lindep_sensitivity,g,g0,ce,ce0,low,up,
260 | primal,init,dual,lin_dependent,buffer,progress)
261 | long n; /* number of variables */
262 | long m; /* number of linear equality constraints [0,1] */
263 | double precision; /* solve at least to this dual precision */
264 | double epsilon_crit; /* stop, if KT-Conditions approx fulfilled */
265 | double epsilon_a; /* precision of alphas at bounds */
266 | long maxiter; /* stop after this many iterations */
267 | long goal; /* keep going until goal fulfilled */
268 | long smallround; /* use only two variables of steepest descent */
269 | double lindep_sensitivity; /* epsilon for detecting linear dependent ex */
270 | double *g; /* hessian of objective */
271 | double *g0; /* linear part of objective */
272 | double *ce,*ce0; /* linear equality constraints */
273 | double *low,*up; /* box constraints */
274 | double *primal; /* primal variables */
275 | double *init; /* initial values of primal */
276 | double *dual; /* dual variables */
277 | long *lin_dependent;
278 | double *buffer;
279 | double *progress; /* delta in the objective function between
280 | before and after */
281 | {
282 | long i,j,k,from,to,n_indep,changed;
283 | double sum,bmin=0,bmax=0;
284 | double *d,*d0,*ig,*dual_old,*temp,*start;
285 | double *g0_new,*g_new,*ce_new,*ce0_new,*low_new,*up_new;
286 | double add,t;
287 | int result;
288 | double obj_before,obj_after;
289 | long b1,b2;
290 | double g0_b1,g0_b2,ce0_b;
291 |
292 | g0_new=&(buffer[0]); /* claim regions of buffer */
293 | d=&(buffer[n]);
294 | d0=&(buffer[n+(n+m)*2*(n+m)*2]);
295 | ce_new=&(buffer[n+(n+m)*2*(n+m)*2+(n+m)*2]);
296 | ce0_new=&(buffer[n+(n+m)*2*(n+m)*2+(n+m)*2+n]);
297 | ig=&(buffer[n+(n+m)*2*(n+m)*2+(n+m)*2+n+m]);
298 | dual_old=&(buffer[n+(n+m)*2*(n+m)*2+(n+m)*2+n+m+n*n]);
299 | low_new=&(buffer[n+(n+m)*2*(n+m)*2+(n+m)*2+n+m+n*n+(n+m)*2]);
300 | up_new=&(buffer[n+(n+m)*2*(n+m)*2+(n+m)*2+n+m+n*n+(n+m)*2+n]);
301 | start=&(buffer[n+(n+m)*2*(n+m)*2+(n+m)*2+n+m+n*n+(n+m)*2+n+n]);
302 | g_new=&(buffer[n+(n+m)*2*(n+m)*2+(n+m)*2+n+m+n*n+(n+m)*2+n+n+n]);
303 | temp=&(buffer[n+(n+m)*2*(n+m)*2+(n+m)*2+n+m+n*n+(n+m)*2+n+n+n+n*n]);
304 |
305 | b1=-1;
306 | b2=-1;
307 | for(i=0;i=( up[i]-epsilon_a)) && (ce[i]>0.0)))
315 | ) {
316 | bmin=sum;
317 | b1=i;
318 | }
319 | if(((b2==-1) || (sum>=bmax))
320 | && (!((init[i]<=(low[i]+epsilon_a)) && (ce[i]>0.0)))
321 | && (!((init[i]>=( up[i]-epsilon_a)) && (ce[i]<0.0)))
322 | ) {
323 | bmax=sum;
324 | b2=i;
325 | }
326 | }
327 | /* in case of unbiased hyperplane, the previous projection on */
328 | /* equality constraint can lead to b1 or b2 being -1. */
329 | if((b1 == -1) || (b2 == -1)) {
330 | b1=maxl(b1,b2);
331 | b2=maxl(b1,b2);
332 | }
333 |
334 | for(i=0;i g0_b2) { /* set b2 to upper bound */
375 | /* printf("case +=>\n"); */
376 | changed=1;
377 | t=up[b2]-init[b2];
378 | if((init[b1]-low[b1]) < t) {
379 | t=init[b1]-low[b1];
380 | }
381 | start[b1]=init[b1]-t;
382 | start[b2]=init[b2]+t;
383 | }
384 | }
385 | else if(((g[b1*n+b1]>0) || (g[b2*n+b2]>0))) { /* (ce[b1] != ce[b2]) */
386 | /* printf("case +!\n"); */
387 | t=((ce[b2]/ce[b1])*g0[b1]-g0[b2]+ce0[0]*(g[b1*n+b1]*ce[b2]/ce[b1]-g[b1*n+b2]/ce[b1]))/((ce[b2]*ce[b2]/(ce[b1]*ce[b1]))*g[b1*n+b1]+g[b2*n+b2]-2*(g[b1*n+b2]*ce[b2]/ce[b1]))-init[b2];
388 | changed=1;
389 | if((up[b2]-init[b2]) < t) {
390 | t=up[b2]-init[b2];
391 | }
392 | if((init[b2]-low[b2]) < -t) {
393 | t=-(init[b2]-low[b2]);
394 | }
395 | if((up[b1]-init[b1]) < t) {
396 | t=(up[b1]-init[b1]);
397 | }
398 | if((init[b1]-low[b1]) < -t) {
399 | t=-(init[b1]-low[b1]);
400 | }
401 | start[b1]=init[b1]+t;
402 | start[b2]=init[b2]+t;
403 | }
404 | }
405 | if((-g[b1*n+b2] == g[b1*n+b1]) && (-g[b1*n+b2] == g[b2*n+b2])) {
406 | /* printf("diffeuqal\n"); */
407 | if(ce[b1] != ce[b2]) {
408 | if((g0_b1+g0_b2) < 0) { /* set b1 and b2 to upper bound */
409 | /* printf("case -!<\n"); */
410 | changed=1;
411 | t=up[b1]-init[b1];
412 | if((up[b2]-init[b2]) < t) {
413 | t=up[b2]-init[b2];
414 | }
415 | start[b1]=init[b1]+t;
416 | start[b2]=init[b2]+t;
417 | }
418 | else if((g0_b1+g0_b2) >= 0) { /* set b1 and b2 to lower bound */
419 | /* printf("case -!>\n"); */
420 | changed=1;
421 | t=init[b1]-low[b1];
422 | if((init[b2]-low[b2]) < t) {
423 | t=init[b2]-low[b2];
424 | }
425 | start[b1]=init[b1]-t;
426 | start[b2]=init[b2]-t;
427 | }
428 | }
429 | else if(((g[b1*n+b1]>0) || (g[b2*n+b2]>0))) { /* (ce[b1]==ce[b2]) */
430 | /* printf("case -=\n"); */
431 | t=((ce[b2]/ce[b1])*g0[b1]-g0[b2]+ce0[0]*(g[b1*n+b1]*ce[b2]/ce[b1]-g[b1*n+b2]/ce[b1]))/((ce[b2]*ce[b2]/(ce[b1]*ce[b1]))*g[b1*n+b1]+g[b2*n+b2]-2*(g[b1*n+b2]*ce[b2]/ce[b1]))-init[b2];
432 | changed=1;
433 | if((up[b2]-init[b2]) < t) {
434 | t=up[b2]-init[b2];
435 | }
436 | if((init[b2]-low[b2]) < -t) {
437 | t=-(init[b2]-low[b2]);
438 | }
439 | if((up[b1]-init[b1]) < -t) {
440 | t=-(up[b1]-init[b1]);
441 | }
442 | if((init[b1]-low[b1]) < t) {
443 | t=init[b1]-low[b1];
444 | }
445 | start[b1]=init[b1]-t;
446 | start[b2]=init[b2]+t;
447 | }
448 | }
449 | }
450 | /* if we have a biased hyperplane, then adding a constant to the */
451 | /* hessian does not change the solution. So that is done for examples */
452 | /* with zero diagonal entry, since HIDEO cannot handle them. */
453 | if((m>0)
454 | && ((fabs(g[b1*n+b1]) < lindep_sensitivity)
455 | || (fabs(g[b2*n+b2]) < lindep_sensitivity))) {
456 | /* printf("Case 0\n"); */
457 | add+=0.093274;
458 | }
459 | /* in case both examples are linear dependent */
460 | else if((m>0)
461 | && (g[b1*n+b2] != 0 && g[b2*n+b2] != 0)
462 | && (fabs(g[b1*n+b1]/g[b1*n+b2] - g[b1*n+b2]/g[b2*n+b2])
463 | < lindep_sensitivity)) {
464 | /* printf("Case lindep\n"); */
465 | add+=0.078274;
466 | }
467 |
468 | /* special case for zero diagonal entry on unbiased hyperplane */
469 | if((m==0) && (b1>=0)) {
470 | if(fabs(g[b1*n+b1]) < lindep_sensitivity) {
471 | /* printf("Case 0b1\n"); */
472 | for(i=0;i=0)
487 | start[b1]=low[b1];
488 | }
489 | }
490 | if((m==0) && (b2>=0)) {
491 | if(fabs(g[b2*n+b2]) < lindep_sensitivity) {
492 | /* printf("Case 0b2\n"); */
493 | for(i=0;i=0)
508 | start[b2]=low[b2];
509 | }
510 | }
511 |
512 | /* printf("b1=%ld,b2=%ld\n",b1,b2); */
513 |
514 | lcopy_matrix(g,n,d);
515 | if((m==1) && (add>0.0)) {
516 | for(j=0;j2) { /* switch, so that variables are better mixed */
527 | lswitchrk_matrix(d,n,b1,(long)0);
528 | if(b2 == 0)
529 | lswitchrk_matrix(d,n,b1,(long)1);
530 | else
531 | lswitchrk_matrix(d,n,b2,(long)1);
532 | }
533 | if(smallround == SMALLROUND) {
534 | for(i=2;i0) { /* for biased hyperplane, pick two variables */
538 | lin_dependent[0]=0;
539 | lin_dependent[1]=0;
540 | }
541 | else { /* for unbiased hyperplane, pick only one variable */
542 | lin_dependent[0]=smallroundcount % 2;
543 | lin_dependent[1]=(smallroundcount+1) % 2;
544 | }
545 | }
546 | else {
547 | for(i=0;i2) { /* now switch back */
553 | if(b2 == 0) {
554 | lswitchrk_matrix(ig,n,b1,(long)1);
555 | i=lin_dependent[1];
556 | lin_dependent[1]=lin_dependent[b1];
557 | lin_dependent[b1]=i;
558 | }
559 | else {
560 | lswitchrk_matrix(ig,n,b2,(long)1);
561 | i=lin_dependent[1];
562 | lin_dependent[1]=lin_dependent[b2];
563 | lin_dependent[b2]=i;
564 | }
565 | lswitchrk_matrix(ig,n,b1,(long)0);
566 | i=lin_dependent[0];
567 | lin_dependent[0]=lin_dependent[b1];
568 | lin_dependent[b1]=i;
569 | }
570 | /* lprint_matrix(d,n); */
571 | /* lprint_matrix(ig,n); */
572 |
573 | lcopy_matrix(g,n,g_new); /* restore g_new matrix */
574 | if(add>0)
575 | for(j=0;j0) ce0_new[0]=-ce0[0];
585 | for(i=0;i0) ce0_new[0]-=(start[i]*ce[i]);
593 | }
594 | }
595 | from=0; /* remove linear dependent vectors */
596 | to=0;
597 | n_indep=0;
598 | for(i=0;i=3) {
618 | printf("real_qp_size(%ld)...",n_indep);
619 | }
620 |
621 | /* cannot optimize with only one variable */
622 | if((n_indep<=1) && (m>0) && (!changed)) {
623 | for(i=n-1;i>=0;i--) {
624 | primal[i]=init[i];
625 | }
626 | return((int)ONLY_ONE_VARIABLE);
627 | }
628 |
629 | if((!changed) || (n_indep>1)) {
630 | result=solve_dual(n_indep,m,precision,epsilon_crit,maxiter,g_new,g0_new,
631 | ce_new,ce0_new,low_new,up_new,primal,d,d0,ig,
632 | dual,dual_old,temp,goal);
633 | }
634 | else {
635 | result=PRIMAL_OPTIMAL;
636 | }
637 |
638 | j=n_indep;
639 | for(i=n-1;i>=0;i--) {
640 | if(!lin_dependent[i]) {
641 | j--;
642 | primal[i]=primal[j];
643 | }
644 | else {
645 | primal[i]=start[i]; /* leave as is */
646 | }
647 | temp[i]=primal[i];
648 | }
649 |
650 | obj_before=calculate_qp_objective(n,g,g0,init);
651 | obj_after=calculate_qp_objective(n,g,g0,primal);
652 | (*progress)=obj_before-obj_after;
653 | if(verbosity>=3) {
654 | printf("before(%.30f)...after(%.30f)...result_sd(%d)...",
655 | obj_before,obj_after,result);
656 | }
657 |
658 | return((int)result);
659 | }
660 |
661 |
662 | int solve_dual(n,m,precision,epsilon_crit,maxiter,g,g0,ce,ce0,low,up,primal,
663 | d,d0,ig,dual,dual_old,temp,goal)
664 | /* Solves the dual using the method of Hildreth and D'Espo. */
665 | /* Can only handle problems with zero or exactly one */
666 | /* equality constraints. */
667 |
668 | long n; /* number of variables */
669 | long m; /* number of linear equality constraints */
670 | double precision; /* solve at least to this dual precision */
671 | double epsilon_crit; /* stop, if KT-Conditions approx fulfilled */
672 | long maxiter; /* stop after that many iterations */
673 | double *g;
674 | double *g0; /* linear part of objective */
675 | double *ce,*ce0; /* linear equality constraints */
676 | double *low,*up; /* box constraints */
677 | double *primal; /* variables (with initial values) */
678 | double *d,*d0,*ig,*dual,*dual_old,*temp; /* buffer */
679 | long goal;
680 | {
681 | long i,j,k,iter;
682 | double sum,w,maxviol,viol,temp1,temp2,isnantest;
683 | double model_b,dist;
684 | long retrain,maxfaktor,primal_optimal=0,at_bound,scalemaxiter;
685 | double epsilon_a=1E-15,epsilon_hideo;
686 | double eq;
687 |
688 | if((m<0) || (m>1))
689 | perror("SOLVE DUAL: inappropriate number of eq-constrains!");
690 |
691 | /*
692 | printf("\n");
693 | for(i=0;i0) {
715 | sum=0; /* dual hessian for eq constraints */
716 | for(j=0;j0) {
751 | sum=0; /* dual linear component for eq constraints */
752 | for(j=0;j 0) && (iter < (scalemaxiter*maxfaktor))) {
767 | iter++;
768 |
769 | while((maxviol > precision) && (iter < (scalemaxiter*maxfaktor))) {
770 | iter++;
771 | maxviol=0;
772 | for(i=0;i<2*(n+m);i++) {
773 | sum=d0[i];
774 | for(j=0;j<2*(n+m);j++) {
775 | sum+=d[i*2*(n+m)+j]*dual_old[j];
776 | }
777 | sum-=d[i*2*(n+m)+i]*dual_old[i];
778 | dual[i]=-sum/d[i*2*(n+m)+i];
779 | if(dual[i]<0) dual[i]=0;
780 |
781 | viol=fabs(dual[i]-dual_old[i]);
782 | if(viol>maxviol)
783 | maxviol=viol;
784 | dual_old[i]=dual[i];
785 | }
786 | /*
787 | printf("%d) maxviol=%20f precision=%f\n",iter,maxviol,precision);
788 | */
789 | }
790 |
791 | if(m>0) {
792 | for(i=0;i=(up[i])) {
811 | primal[i]=up[i];
812 | }
813 | }
814 |
815 | if(m>0)
816 | model_b=dual[n+n+1]-dual[n+n];
817 | else
818 | model_b=0;
819 |
820 | epsilon_hideo=EPSILON_HIDEO;
821 | for(i=0;i(low[i]+epsilon_hideo)) &&(dist>(1.0+epsilon_crit))) {
834 | epsilon_hideo=(primal[i]-low[i])*2.0;
835 | }
836 | }
837 | /* printf("\nEPSILON_HIDEO=%.30f\n",epsilon_hideo); */
838 |
839 | for(i=0;i=(up[i]-epsilon_hideo)) {
844 | primal[i]=up[i];
845 | }
846 | }
847 |
848 | retrain=0;
849 | primal_optimal=1;
850 | at_bound=0;
851 | for(i=0;(i(low[i]+epsilon_a)) && (dist > (1.0+epsilon_crit))) {
865 | retrain=1;
866 | primal_optimal=0;
867 | }
868 | if((primal[i]<=(low[i]+epsilon_a)) || (primal[i]>=(up[i]-epsilon_a))) {
869 | at_bound++;
870 | }
871 | /* printf("HIDEOtemp: a[%ld]=%.30f, dist=%.6f, b=%f, at_bound=%ld\n",i,primal[i],dist,model_b,at_bound); */
872 | }
873 | if(m>0) {
874 | eq=-ce0[0]; /* check precision of eq-constraint */
875 | for(i=0;i=(up[i]-epsilon_a)) {
909 | primal[i]=up[i];
910 | }
911 | }
912 | }
913 |
914 | isnantest=0;
915 | for(i=0;i0) {
920 | temp1=dual[n+n+1]; /* copy the dual variables for the eq */
921 | temp2=dual[n+n]; /* constraints to a handier location */
922 | for(i=n+n+1;i>=2;i--) {
923 | dual[i]=dual[i-2];
924 | }
925 | dual[0]=temp2;
926 | dual[1]=temp1;
927 | isnantest+=temp1+temp2;
928 | }
929 |
930 | if(isnan(isnantest)) {
931 | return((int)NAN_SOLUTION);
932 | }
933 | else if(primal_optimal) {
934 | return((int)PRIMAL_OPTIMAL);
935 | }
936 | else if(maxviol == 0.0) {
937 | return((int)DUAL_OPTIMAL);
938 | }
939 | else {
940 | return((int)MAXITER_EXCEEDED);
941 | }
942 | }
943 |
944 |
945 | void linvert_matrix(matrix,depth,inverse,lindep_sensitivity,lin_dependent)
946 | double *matrix;
947 | long depth;
948 | double *inverse,lindep_sensitivity;
949 | long *lin_dependent; /* indicates the active parts of matrix on
950 | input and output*/
951 | {
952 | long i,j,k;
953 | double factor;
954 |
955 | for(i=0;i=0;i--) {
979 | if(!lin_dependent[i]) {
980 | factor=1/matrix[i*depth+i];
981 | for(k=0;k=0;j--) {
986 | factor=matrix[j*depth+i];
987 | matrix[j*depth+i]=0;
988 | for(k=0;k