From a4a99ae997fa27400e271285826c715fe6966cbd Mon Sep 17 00:00:00 2001 From: Araq Date: Wed, 4 Apr 2012 16:01:28 +0200 Subject: [PATCH] added libsvm wrapper --- doc/lib.txt | 6 ++ lib/pure/endians.nim | 46 +++++++++++++ lib/pure/oids.nim | 81 +++++++++++++++++++++++ lib/wrappers/libsvm.nim | 116 +++++++++++++++++++++++++++++++++ lib/wrappers/opengl/opengl.nim | 2 + web/news.txt | 1 + web/nimrod.ini | 1 + 7 files changed, 253 insertions(+) create mode 100644 lib/pure/endians.nim create mode 100644 lib/pure/oids.nim create mode 100644 lib/wrappers/libsvm.nim diff --git a/doc/lib.txt b/doc/lib.txt index 3916bf8926..f65ba9954b 100755 --- a/doc/lib.txt +++ b/doc/lib.txt @@ -584,3 +584,9 @@ Data Compression and Archiving Interface to the `lib zip `_ library by Dieter Baron and Thomas Klausner. + +Scientific computing +-------------------- + +* `libsvm `_ + Low level wrapper for `libsvm `_. diff --git a/lib/pure/endians.nim b/lib/pure/endians.nim new file mode 100644 index 0000000000..94eb41cf68 --- /dev/null +++ b/lib/pure/endians.nim @@ -0,0 +1,46 @@ +# +# +# Nimrod's Runtime Library +# (c) Copyright 2012 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module contains helpers that deal with `endian`:idx: changes. + +proc swapEndian64*(outp, inp: pointer) = + ## copies `inp` to `outp` swapping bytes. Both buffers are supposed to + ## contain at least 8 bytes. + var i = cast[cstring](inp) + var o = cast[cstring](outp) + o[0] = i[7] + o[1] = i[6] + o[2] = i[5] + o[3] = i[4] + o[4] = i[3] + o[5] = i[2] + o[6] = i[1] + o[7] = i[0] + +proc swapEndian32*(outp, inp: pointer) = + ## copies `inp` to `outp` swapping bytes. Both buffers are supposed to + ## contain at least 4 bytes. + var i = cast[cstring](inp) + var o = cast[cstring](outp) + o[0] = i[3] + o[1] = i[2] + o[2] = i[1] + o[3] = i[0] + +when system.cpuEndian == bigEndian: + proc littleEndian64*(outp, inp: pointer) {.inline.} = swapEndian64(outp, inp) + proc littleEndian32*(outp, inp: pointer) {.inline.} = swapEndian32(outp, inp) + proc bigEndian64*(outp, inp: pointer) {.inline.} = copyMem(outp, inp, 8) + proc bigEndian32*(outp, inp: pointer) {.inline.} = copyMem(outp, inp, 4) +else: + proc littleEndian64*(outp, inp: pointer) {.inline.} = copyMem(outp, inp, 8) + proc littleEndian32*(outp, inp: pointer) {.inline.} = copyMem(outp, inp, 4) + proc bigEndian64*(outp, inp: pointer) {.inline.} = swapEndian64(outp, inp) + proc bigEndian32*(outp, inp: pointer) {.inline.} = swapEndian32(outp, inp) + diff --git a/lib/pure/oids.nim b/lib/pure/oids.nim new file mode 100644 index 0000000000..584dba33ee --- /dev/null +++ b/lib/pure/oids.nim @@ -0,0 +1,81 @@ +# +# +# Nimrod's Runtime Library +# (c) Copyright 2012 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Nimrod OID support. An OID consists of a timestamp, a unique counter +## and a random value. This combination should suffice to produce a globally +## distributed unique ID. This implementation was extracted from the +## Mongodb interface. This calls ``math.randomize()`` for the first call of +## ``genOid``. + +import times, endians + +type + Toid* {.pure, final.} = object ## an OID + time: int32 ## + fuzz: int32 ## + count: int32 ## + +proc hexbyte*(hex: char): int = + case hex + of '0'..'9': result = (ord(hex) - ord('0')) + of 'a'..'f': result = (ord(hex) - ord('a') + 10) + of 'A'..'F': result = (ord(hex) - ord('A') + 10) + else: nil + +proc parseOid*(str: cstring): TOid = + ## parses an OID. + var bytes = cast[cstring](addr(result.time)) + var i = 0 + while i < 12: + bytes[i] = chr((hexbyte(str[2 * i]) shl 4) or hexbyte(str[2 * i + 1])) + inc(i) + +proc oidToString*(oid: TOid, str: cstring) = + const hex = "0123456789abcdef" + # work around a compiler bug: + var str = str + var o = oid + var bytes = cast[cstring](addr(o)) + var i = 0 + while i < 12: + let b = bytes[i].ord + str[2 * i] = hex[(b and 0xF0) shr 4] + str[2 * i + 1] = hex[b and 0xF] + inc(i) + str[24] = '\0' + +var + incr, fuzz: int + +proc genOid*(): TOid = + ## generates a new OID. + proc rand(): cint {.importc: "rand", nodecl.} + proc gettime(dummy: ptr cint): cint {.importc: "time", header: "".} + proc srand(seed: cint) {.importc: "srand", nodecl.} + + var t = gettime(nil) + + var i = int32(incr) + atomicInc(incr) + + if fuzz == 0: + # racy, but fine semantically: + srand(t) + fuzz = rand() + bigEndian32(addr result.time, addr(t)) + result.fuzz = fuzz + bigEndian32(addr result.count, addr(i)) + +proc generatedTime*(oid: TOid): TTime = + ## returns the generated timestamp of the OID. + var tmp: int32 + var dummy = oid.time + bigEndian32(addr(tmp), addr(dummy)) + result = TTime(tmp) + diff --git a/lib/wrappers/libsvm.nim b/lib/wrappers/libsvm.nim new file mode 100644 index 0000000000..8dec05bcf6 --- /dev/null +++ b/lib/wrappers/libsvm.nim @@ -0,0 +1,116 @@ +# +# +# Nimrod's Runtime Library +# (c) Copyright 2012 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module is a low level wrapper for `libsvm`:idx:. + +{.deadCodeElim: on.} +const + LIBSVM_VERSION* = 312 + +when defined(windows): + const svmdll* = "libsvm.dll" +elif defined(macosx): + const svmdll* = "libsvm.dylib" +else: + const svmdll* = "libsvm.so" + +type + Tnode*{.pure, final.} = object + index*: cint + value*: cdouble + + Tproblem*{.pure, final.} = object + L*: cint + y*: ptr cdouble + x*: ptr ptr Tnode + + Ttype*{.size: sizeof(cint).} = enum + C_SVC, NU_SVC, ONE_CLASS, EPSILON_SVR, NU_SVR + + TKernelType*{.size: sizeof(cint).} = enum + LINEAR, POLY, RBF, SIGMOID, PRECOMPUTED + + Tparameter*{.pure, final.} = object + typ*: TType + kernelType*: TKernelType + degree*: cint # for poly + gamma*: cdouble # for poly/rbf/sigmoid + coef0*: cdouble # for poly/sigmoid + # these are for training only + cache_size*: cdouble # in MB + eps*: cdouble # stopping criteria + C*: cdouble # for C_SVC, EPSILON_SVR and NU_SVR + nr_weight*: cint # for C_SVC + weight_label*: ptr cint # for C_SVC + weight*: ptr cdouble # for C_SVC + nu*: cdouble # for NU_SVC, ONE_CLASS, and NU_SVR + p*: cdouble # for EPSILON_SVR + shrinking*: cint # use the shrinking heuristics + probability*: cint # do probability estimates + + +# +# svm_model +# + +type + TModel*{.pure, final.} = object + param*: Tparameter # parameter + nr_class*: cint # number of classes, = 2 in regression/one class svm + L*: cint # total #SV + SV*: ptr ptr Tnode # SVs (SV[l]) + sv_coef*: ptr ptr cdouble # coefficients for SVs in decision functions (sv_coef[k-1][l]) + rho*: ptr cdouble # constants in decision functions (rho[k*(k-1)/2]) + probA*: ptr cdouble # pariwise probability information + probB*: ptr cdouble # for classification only + label*: ptr cint # label of each class (label[k]) + nSV*: ptr cint # number of SVs for each class (nSV[k]) + # nSV[0] + nSV[1] + ... + nSV[k-1] = l + # XXX + free_sv*: cint # 1 if svm_model is created by svm_load_model + # 0 if svm_model is created by svm_train + + +proc train*(prob: ptr Tproblem, param: ptr Tparameter): ptr Tmodel{.cdecl, + importc: "svm_train", dynlib: svmdll.} +proc cross_validation*(prob: ptr Tproblem, param: ptr Tparameter, nr_fold: cint, + target: ptr cdouble){.cdecl, + importc: "svm_cross_validation", dynlib: svmdll.} +proc save_model*(model_file_name: cstring, model: ptr Tmodel): cint{.cdecl, + importc: "svm_save_model", dynlib: svmdll.} +proc load_model*(model_file_name: cstring): ptr Tmodel{.cdecl, + importc: "svm_load_model", dynlib: svmdll.} +proc get_svm_type*(model: ptr Tmodel): cint{.cdecl, importc: "svm_get_svm_type", + dynlib: svmdll.} +proc get_nr_class*(model: ptr Tmodel): cint{.cdecl, importc: "svm_get_nr_class", + dynlib: svmdll.} +proc get_labels*(model: ptr Tmodel, label: ptr cint){.cdecl, + importc: "svm_get_labels", dynlib: svmdll.} +proc get_svr_probability*(model: ptr Tmodel): cdouble{.cdecl, + importc: "svm_get_svr_probability", dynlib: svmdll.} +proc predict_values*(model: ptr Tmodel, x: ptr Tnode, dec_values: ptr cdouble): cdouble{. + cdecl, importc: "svm_predict_values", dynlib: svmdll.} +proc predict*(model: ptr Tmodel, x: ptr Tnode): cdouble{.cdecl, + importc: "svm_predict", dynlib: svmdll.} +proc predict_probability*(model: ptr Tmodel, x: ptr Tnode, + prob_estimates: ptr cdouble): cdouble{.cdecl, + importc: "svm_predict_probability", dynlib: svmdll.} +proc free_model_content*(model_ptr: ptr Tmodel){.cdecl, + importc: "svm_free_model_content", dynlib: svmdll.} +proc free_and_destroy_model*(model_ptr_ptr: ptr ptr Tmodel){.cdecl, + importc: "svm_free_and_destroy_model", dynlib: svmdll.} +proc destroy_param*(param: ptr Tparameter){.cdecl, importc: "svm_destroy_param", + dynlib: svmdll.} +proc check_parameter*(prob: ptr Tproblem, param: ptr Tparameter): cstring{. + cdecl, importc: "svm_check_parameter", dynlib: svmdll.} +proc check_probability_model*(model: ptr Tmodel): cint{.cdecl, + importc: "svm_check_probability_model", dynlib: svmdll.} + +proc set_print_string_function*(print_func: proc (arg: cstring) {.cdecl.}){. + cdecl, importc: "svm_set_print_string_function", dynlib: svmdll.} diff --git a/lib/wrappers/opengl/opengl.nim b/lib/wrappers/opengl/opengl.nim index d243146ed6..baef69276c 100644 --- a/lib/wrappers/opengl/opengl.nim +++ b/lib/wrappers/opengl/opengl.nim @@ -371,6 +371,8 @@ # to keep it up to date #============================================================================== +{.deadCodeElim: on.} + when defined(LINUX): import X, XLib, XUtil diff --git a/web/news.txt b/web/news.txt index 4fd874d0df..c5cfa66d6d 100755 --- a/web/news.txt +++ b/web/news.txt @@ -29,6 +29,7 @@ Library Additions - The stdlib can now be avoided to a point where C code generation for 16bit micro controllers is feasible. - Added a new OpenGL wrapper that supports OpenGL up to version 4.2. +- Added a wrapper for ``libsvm``. Changes affecting backwards compatibility diff --git a/web/nimrod.ini b/web/nimrod.ini index 4d8875c1c9..d2dcb8b695 100755 --- a/web/nimrod.ini +++ b/web/nimrod.ini @@ -55,6 +55,7 @@ webdoc: "posix/posix;wrappers/odbcsql;impure/dialogs" webdoc: "wrappers/zip/zlib;wrappers/zip/libzip" webdoc: "wrappers/cairo" webdoc: "wrappers/gtk" +webdoc: "wrappers/libsvm.nim" webdoc: "windows" webdoc: "wrappers/x11;wrappers/opengl;wrappers/sdl;wrappers/lua" webdoc: "wrappers/readline/readline;wrappers/readline/history"