Oliver Gu avatar Oliver Gu committed 838fc8d

Version 0.8.0 release.

Comments (0)

Files changed (26)

+*.native
+*.byte
+/setup.log
+/setup.data
+/data
+/_log
+/_build
+# OASIS_START
+# DO NOT EDIT (digest: ddc21ba6ae8d18f1a32ae5ac9eb25edd)
+lib/Libsvm
+# OASIS_STOP
+(* OASIS_START *)
+(* DO NOT EDIT (digest: bba1893e6cfa30be5193ca0fbeae3d5e) *)
+Authors of libsvm-ocaml
+Oliver Gu <odietric@gmail.com>
+Dominik Brugger <dominikbrugger@fastmail.fm>
+(* OASIS_STOP *)
+2013-02-18: Complete rewrite by Oliver Gu <odietric@gmail.com>.
+
+2005-09-26: Initial release (0.1) by
+            Dominik Brugger <dominikbrugger@fastmail.fm>.
+The Library is distributed under the terms of the GNU Lesser General
+Public License version 2.1 (included below).
+
+As a special exception to the GNU Lesser General Public License, you
+may link, statically or dynamically, a "work that uses the Library"
+with a publicly distributed version of the Library to produce an
+executable file containing portions of the Library, and distribute that
+executable file under terms of your choice, without any of the additional
+requirements listed in clause 6 of the GNU Lesser General Public License.
+By "a publicly distributed version of the Library", we mean either the
+unmodified Library as distributed by the authors, or a modified version
+of the Library that is distributed under the conditions defined in clause
+3 of the GNU Lesser General Public License.  This exception does not
+however invalidate any other reasons why the executable file might be
+covered by the GNU Lesser General Public License.
+
+---------------------------------------------------------------------------
+
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+(* OASIS_START *)
+(* DO NOT EDIT (digest: f3b41f3a2e757d0e01fea16db73baf9c) *)
+This is the INSTALL file for the libsvm-ocaml distribution.
+
+This package uses OASIS to generate its build system. See section OASIS for
+full information. 
+
+Dependencies
+============
+
+In order to compile this package, you will need:
+* ocaml (>= 3.12) for all, test libsvm, doc API
+* findlib (>= 1.3.1)
+* core for library libsvm
+* lacaml for library libsvm
+* sexplib for executable svm_cli
+
+Installing
+==========
+
+1. Uncompress the source archive and go to the root of the package
+2. Run 'ocaml setup.ml -configure'
+3. Run 'ocaml setup.ml -build'
+4. Run 'ocaml setup.ml -install'
+
+Uninstalling
+============
+
+1. Go to the root of the package 
+2. Run 'ocaml setup.ml -uninstall'
+
+OASIS
+=====
+
+OASIS is a program that generates a setup.ml file using a simple '_oasis'
+configuration file. The generated setup only depends on the standard OCaml
+installation: no additional library is required.
+
+(* OASIS_STOP *)
+# OASIS_START
+# DO NOT EDIT (digest: bc1e05bfc8b39b664f29dae8dbd3ebbb)
+
+SETUP = ocaml setup.ml
+
+build: setup.data
+	$(SETUP) -build $(BUILDFLAGS)
+
+doc: setup.data build
+	$(SETUP) -doc $(DOCFLAGS)
+
+test: setup.data build
+	$(SETUP) -test $(TESTFLAGS)
+
+all: 
+	$(SETUP) -all $(ALLFLAGS)
+
+install: setup.data
+	$(SETUP) -install $(INSTALLFLAGS)
+
+uninstall: setup.data
+	$(SETUP) -uninstall $(UNINSTALLFLAGS)
+
+reinstall: setup.data
+	$(SETUP) -reinstall $(REINSTALLFLAGS)
+
+clean: 
+	$(SETUP) -clean $(CLEANFLAGS)
+
+distclean: 
+	$(SETUP) -distclean $(DISTCLEANFLAGS)
+
+setup.data:
+	$(SETUP) -configure $(CONFIGUREFLAGS)
+
+.PHONY: build doc test all install uninstall reinstall clean distclean configure
+
+# OASIS_STOP
+LIBSVM-OCaml - LIBSVM Bindings for OCaml
+========================================
+
+LIBSVM-OCaml is an [OCaml](http://www.ocaml.org) library with bindings to the
+[LIBSVM](http://www.csie.ntu.edu.tw/~cjlin/libsvm/) library.
+
+Installation
+------------
+
+To build and install libsvm-ocaml:
+
+    $ make
+    $ make install
+
+### Tests _(optionnal)_
+
+To build and execute tests:
+
+    $ ./configure --enable-tests
+    $ make test
+
+### Documentation _(optional)_
+
+To build the documentation:
+
+    $ make doc
+
+It will then be installed by `make install`.
+
+Credits
+-------
+
+  * Dominik Brugger wrote the initial release for LIBSVM 2.8.
+* more testing, in particular n-fold cross validation
+* improve documentation
+* add probability estimate support to svm_cli
+* add accessor function for support vectors in Svm.Model
+OASISFormat:       0.3
+Name:              libsvm-ocaml
+Version:           0.8
+Synopsis:          libsvm-ocaml - OCaml bindings to the LIBSVM library
+Description:       libsvm-ocaml offers an OCaml-interface to the LIBSVM library
+Authors:           Oliver Gu <odietric@gmail.com>
+                   Dominik Brugger <dominikbrugger@fastmail.fm>
+License:           LGPL-2.1+ with OCaml linking exception
+OCamlVersion:      >= 3.12
+FindlibVersion:    >= 1.3.1
+Homepage:          https://bitbucket.org/ogu/libsvm-ocaml
+
+Plugins:           META (0.3), StdFiles (0.3), DevFiles (0.3)
+XStdFilesREADME:   false
+BuildTools:        ocamldoc, ocamlbuild
+
+
+
+Library libsvm
+  Path:           lib
+  Findlibname:    libsvm
+  Modules:        Libsvm
+  CSources:       libsvm_stubs.c
+  CCOpt:          -g -O2 -fPIC -DPIC
+  CCLib:          -lsvm
+  BuildDepends:   core,lacaml
+
+# Examples
+
+Executable xor
+  Path:           examples
+  MainIs:         xor.ml
+  Install:        false
+  BuildDepends:   libsvm
+  CompiledObject: byte
+
+Executable svm_cli
+  Path:           examples
+  MainIs:         svm_cli.ml
+  Install:        false
+  BuildDepends:   libsvm,sexplib,sexplib.syntax
+  CompiledObject: byte
+
+# Executable log
+#   Path:           examples
+#   MainIs:         log.ml
+#   Install:        false
+#   BuildDepends:   libsvm,gsl,gnuplot
+#   CompiledObject: byte
+
+# Tests
+
+Executable svm_test
+  Path:           test
+  MainIs:         svm_test.ml
+  Install:        false
+  BuildDepends:   libsvm
+  CompiledObject: byte
+
+Test libsvm
+  Run$:             flag(tests)
+  Command:          env CAML_LD_LIBRARY_PATH=./_build/lib:`ocamlc -where`/../stublibs $svm_test
+  WorkingDirectory: .
+
+# Documentation
+
+Document API
+  Title:                API reference for LIBSVM-OCaml
+  Type:                 Ocamlbuild (0.3)
+  Install:              true
+  InstallDir:           $docdir/api
+  BuildTools:           ocamldoc
+  XOCamlbuildPath:      .
+  XOCamlbuildLibraries: libsvm
+true: debug,annot,thread
+<examples/svm_cli.ml{,i}>: syntax_camlp4o
+
+# OASIS_START
+# DO NOT EDIT (digest: c7487bde9da052de22383bad8e0143bc)
+# Ignore VCS directories, you can use the same kind of rule outside
+# OASIS_START/STOP if you want to exclude directories that contains
+# useless stuff for the build process
+<**/.svn>: -traverse
+<**/.svn>: not_hygienic
+".bzr": -traverse
+".bzr": not_hygienic
+".hg": -traverse
+".hg": not_hygienic
+".git": -traverse
+".git": not_hygienic
+"_darcs": -traverse
+"_darcs": not_hygienic
+# Library libsvm
+"lib/libsvm.cmxs": use_libsvm
+<lib/*.ml{,i}>: oasis_library_libsvm_ccopt
+"lib/libsvm_stubs.c": oasis_library_libsvm_ccopt
+<lib/libsvm.{cma,cmxa}>: oasis_library_libsvm_cclib
+"lib/liblibsvm_stubs.lib": oasis_library_libsvm_cclib
+"lib/dlllibsvm_stubs.dll": oasis_library_libsvm_cclib
+"lib/liblibsvm_stubs.a": oasis_library_libsvm_cclib
+"lib/dlllibsvm_stubs.so": oasis_library_libsvm_cclib
+<lib/libsvm.{cma,cmxa}>: use_liblibsvm_stubs
+<lib/*.ml{,i}>: pkg_core
+<lib/*.ml{,i}>: pkg_lacaml
+"lib/libsvm_stubs.c": pkg_core
+"lib/libsvm_stubs.c": pkg_lacaml
+# Executable xor
+"examples/xor.byte": use_libsvm
+"examples/xor.byte": pkg_core
+"examples/xor.byte": pkg_lacaml
+# Executable svm_cli
+"examples/svm_cli.byte": use_libsvm
+"examples/svm_cli.byte": pkg_sexplib
+"examples/svm_cli.byte": pkg_sexplib.syntax
+"examples/svm_cli.byte": pkg_core
+"examples/svm_cli.byte": pkg_lacaml
+<examples/*.ml{,i}>: use_libsvm
+<examples/*.ml{,i}>: pkg_sexplib
+<examples/*.ml{,i}>: pkg_sexplib.syntax
+<examples/*.ml{,i}>: pkg_core
+<examples/*.ml{,i}>: pkg_lacaml
+# Executable svm_test
+"test/svm_test.byte": use_libsvm
+"test/svm_test.byte": pkg_core
+"test/svm_test.byte": pkg_lacaml
+<test/*.ml{,i}>: use_libsvm
+<test/*.ml{,i}>: pkg_core
+<test/*.ml{,i}>: pkg_lacaml
+# OASIS_STOP
+#!/bin/sh
+
+# OASIS_START
+# DO NOT EDIT (digest: 425187ed8bfdbdd207fd76392dd243a7)
+set -e
+
+FST=true
+for i in "$@"; do 
+  if $FST; then
+    set --
+    FST=false
+  fi
+
+  case $i in
+    --*=*)
+      ARG=${i%%=*}
+      VAL=${i##*=}
+      set -- "$@" "$ARG" "$VAL"
+      ;;
+    *)
+      set -- "$@" "$i"
+      ;;
+  esac
+done
+
+ocaml setup.ml -configure "$@"
+# OASIS_STOP
+open Core.Std
+open Lacaml.D
+open Libsvm
+
+(* In order to compile this program, install the additional packages:
+   1. gsl-ocaml: https://bitbucket.org/mmottl/gsl-ocaml or type 'opam install gsl-ocaml'
+   2. ocaml-gnuplot: http://sourceforge.net/projects/ocaml-gnuplot/
+*)
+module Gp = Gnuplot.Array
+
+let red = 0xFF0000
+let green = 0x00AA00
+let blue = 0x0000FF
+
+let a = 0.1
+let b = 5.0
+let n_inputs = 99
+let sigma = 0.2
+
+let gen_data () =
+  let default_rng = Gsl.Rng.make (Gsl.Rng.default ()) in
+  let noise = Vec.init n_inputs (fun _ -> Gsl.Randist.gaussian default_rng ~sigma) in
+  let inputs = Vec.linspace a b n_inputs in
+  let targets = Vec.add (Vec.map log inputs) noise in
+  Mat.from_col_vec inputs, targets
+
+let plot g ~x ~y ~color =
+  Gp.color g color;
+  Gp.xy g (Vec.to_array x) (Vec.to_array y) ~style:Gp.Points
+
+let () =
+  let inputs, targets = gen_data () in
+  let problem = Svm.Problem.create ~x:inputs ~y:targets in
+  let model = Svm.train ~svm_type:`NU_SVR problem in
+  let preds = Svm.predict model ~x:inputs in
+  let inputs = Mat.as_vec inputs in
+  let g = Gp.init ~xsize:500. ~ysize:300. Gp.Wxt in
+  Gp.box g;
+  Gp.title g "log";
+  Gp.pen g 3;
+  Gp.pen_width g 2.;
+  Gp.color g green;
+  Gp.fx g log a b;
+  plot g ~x:inputs ~y:targets ~color:red;
+  plot g ~x:inputs ~y:preds ~color:blue;
+  Gp.close g

examples/svm_cli.ml

+open Core.Std
+open Lacaml.D
+open Libsvm
+
+module Scale_parameters = struct
+  type t =
+    { lower : float;
+      upper : float;
+      min_feats : vec;
+      max_feats : vec;
+    }
+end
+
+let read_scale_parameters file =
+  let conv_line line =
+    sscanf line "%d %g %g" (fun _index min max -> min, max)
+  in
+  In_channel.with_file file ~f:(fun ic ->
+    match In_channel.input_line ic with
+    | None -> failwith "no data"
+    | Some line ->
+      let lower, upper = sscanf line "%g %g" Tuple2.create in
+      let lines = In_channel.input_lines ic in
+      let min_feats, max_feats =
+        List.map lines ~f:conv_line
+        |! Array.of_list
+        |! Array.split
+      in
+      { Scale_parameters.
+        lower;
+        upper;
+        min_feats = Vec.of_array min_feats;
+        max_feats = Vec.of_array max_feats;
+      })
+
+let scale_cmd =
+  Command.basic ~summary:"problem scaling"
+    Command.Spec.(
+      empty
+      +> flag "-l" (optional float) ~doc:" x scaling lower limit (default -1)"
+      +> flag "-u" (optional float) ~doc:" x scaling upper limit (default +1)"
+      +> flag "-s SAVE-FILE" (optional file)
+        ~doc:" save scaling parameters to SAVE-FILE"
+      +> flag "-r RESTORE-FILE" (optional file)
+        ~doc:" restore scaling parameters from RESTORE-FILE"
+      +> anon ("DATA-FILE" %: file)
+    )
+    (fun lower upper save_file restore_file data_file () ->
+      match Result.try_with (fun () -> Svm.Problem.load data_file) with
+      | Error exn ->
+        prerr_endline (Exn.to_string exn);
+        exit 1
+      | Ok problem ->
+        let params = match restore_file with
+          | None ->
+            let (`Min min, `Max max) = Svm.Problem.min_max_feats problem in
+            { Scale_parameters.
+              lower = Option.value lower ~default:(-.1.);
+              upper = Option.value upper ~default:(1.);
+              min_feats = min;
+              max_feats = max;
+            }
+          | Some file -> read_scale_parameters file
+        in
+        let lower = params.Scale_parameters.lower in
+        let upper = params.Scale_parameters.upper in
+        let min_feats = params.Scale_parameters.min_feats in
+        let max_feats = params.Scale_parameters.max_feats in
+        Option.iter save_file ~f:(fun file ->
+          Out_channel.with_file file ~f:(fun oc ->
+            let n_feats = Svm.Problem.get_n_feats problem in
+            Out_channel.output_string oc (sprintf "%G %G\n" lower upper);
+            for i = 1 to n_feats do
+              let line = sprintf "%d %g %g\n" i min_feats.{i} max_feats.{i} in
+              Out_channel.output_string oc line
+            done));
+        let scaled_problem =
+          Svm.Problem.scale problem ~lower ~upper ~min_feats ~max_feats
+        in
+        Svm.Problem.output scaled_problem Out_channel.stdout)
+
+module Svm_type = struct
+  type t = [ `C_SVC | `NU_SVC | `ONE_CLASS | `EPSILON_SVR | `NU_SVR ] with sexp
+  let of_string x = t_of_sexp (Sexp.Atom (String.uppercase x))
+  let arg_type = Command.Spec.Arg_type.create of_string
+end
+
+module Kernel_type = struct
+  type t = [ `LINEAR | `POLY | `RBF | `SIGMOID | `PRECOMPUTED ] with sexp
+  let of_string x = t_of_sexp (Sexp.Atom (String.uppercase x))
+  let arg_type = Command.Spec.Arg_type.create of_string
+end
+
+let train_cmd =
+  Command.basic ~summary:"svm training"
+    Command.Spec.(
+      empty
+      +> flag "-s SVM-TYPE" (optional Svm_type.arg_type)
+        ~doc:" set the type of SVM (default c_svc)"
+      +> flag "-k" (optional Kernel_type.arg_type)
+        ~doc:" set the type of kernel function (default rbf)"
+      +> flag "-d DEGREE" (optional int)
+        ~doc:" set degree in kernel function (default 3)"
+      +> flag "-g GAMMA" (optional float)
+        ~doc:" set gamma in kernel function (default 1/num_features)"
+      +> flag "-r COEF0" (optional float)
+        ~doc:"set coef0 in kernel function (default 0)"
+      +> flag "-c COST" (optional float)
+        ~doc:" set the parameter C of c-svc, epsilon-svr and nu-svr (default 1)"
+      +> flag "-n NU" (optional float)
+        ~doc:" set the parameter nu of nu-svc, one-class and nu-svr (default 0.5)"
+      +> flag "-e EPSILON" (optional float)
+        ~doc:" set the epsilon in loss function of epsilon-svr (default 0.1)"
+      +> flag "-m CACHESIZE" (optional float)
+        ~doc:" set cache memory size in MB (default 100)"
+      +> flag "-t TOLERANCE" (optional float)
+        ~doc:" set the tolerance and termination criterion (default 0.001)"
+      +> flag "-h" no_arg
+        ~doc:" turn this on when shrinking heuristics should not be used"
+      +> flag "-p" no_arg
+        ~doc:" turn this on to train a svc or svr model with probability estimates"
+      +> flag "-q" no_arg
+        ~doc:" quiet mode (no ouputs)"
+      +> anon ("TRAINING-SET-FILE" %: file)
+      +> anon ("MODEL-FILE" %: file)
+    )
+    (fun svm_type kernel degree gamma coef0 c nu eps cachesize tol
+      turn_shrinking_off probability quiet training_set_file model_file () ->
+        match Result.try_with (fun () -> Svm.Problem.load training_set_file) with
+        | Error exn ->
+          prerr_endline (Exn.to_string exn);
+          exit 1
+        | Ok problem ->
+          let model = Svm.train
+            ?svm_type
+            ?kernel
+            ?degree
+            ?gamma
+            ?coef0
+            ?c
+            ?nu
+            ?eps
+            ?cachesize
+            ?tol
+            ~shrinking:(if turn_shrinking_off then `off else `on)
+            ~probability
+            ~verbose:(not quiet)
+            problem
+          in
+          Svm.Model.save model model_file)
+
+let predict_cmd =
+  Command.basic ~summary:"svm prediction"
+    Command.Spec.(
+      empty
+      (* +> flag "-b" no_arg *)
+      (*   ~doc:"wether to predict probability estimates, 0 or 1 (default 0); \\ *)
+      (*         for one-class SVM only 0 is supported" *)
+      +> anon ("TEST-SET-FILE" %: file)
+      +> anon ("MODEL-FILE" %: file)
+      +> anon ("OUTPUT-FILE" %: file)
+    )
+    (fun (* probability *) test_set_file model_file output_file () ->
+      let model = Svm.Model.load model_file in
+      match Result.try_with (fun () -> Svm.predict_from_file model test_set_file) with
+      | Error exn ->
+        prerr_endline (Exn.to_string exn);
+        exit 1
+      | Ok (`Expected expected, `Predicted predicted) ->
+        let n_samples = Vec.dim predicted in
+        Out_channel.with_file output_file ~f:(fun oc ->
+          for i = 1 to n_samples do
+            Out_channel.output_string oc (sprintf "%g\n" predicted.{i})
+          done);
+        match Svm.Model.get_svm_type model with
+        | `C_SVC | `NU_SVC | `ONE_CLASS ->
+          let n_correct = Stats.calc_n_correct ~expected ~predicted in
+          let accuracy = Float.(of_int n_correct / of_int n_samples * 100.) in
+          printf "Accuracy = %g%% (%d/%d) (classification)\n" accuracy n_correct n_samples
+        | `EPSILON_SVR | `NU_SVR ->
+          let mse = Stats.calc_mse ~expected ~predicted in
+          let scc = Stats.calc_scc ~expected ~predicted in
+          printf "Mean sqared error = %g (regression)\n" mse;
+          printf "Squared correlation coefficient = %g (regression)\n" scc)
+
+let () =
+  Exn.handle_uncaught ~exit:true (fun () ->
+    Command.run ~version:"0.8" ~build_info:"N/A"
+      (Command.group ~summary:"Command line tools for Libsvm"
+         [ "scale"  , scale_cmd
+         ; "train"  , train_cmd
+         ; "predict", predict_cmd
+         ]))

examples/svm_test.ml

+open Core.Std
+open Lacaml.D
+open Format
+open Lacaml.Io
+open Libsvm
+
+(* This program is an OCaml translation of the Python script svm_test.py which
+   is included in an earlier version of the LIBSVM package, e.g. libsvm-2.88. *)
+let () =
+  let targets = Vec.of_array [|0.; 1.; 1.; 2.|] in  (* a three-class problem *)
+  let samples = Mat.of_array [|
+    [|0.;0.|]; [|0.; 1.|]; [|1.;0.|]; [|1.; 1.|]
+  |] in
+  let inputs = Mat.transpose samples in
+  let problem = Svm.Problem.create ~x:samples ~y:targets in
+  let n_samples = Svm.Problem.get_n_samples problem in
+  let kernels = [ `LINEAR; `POLY; `RBF ] in
+  let kernel_name = function
+    | `LINEAR -> "linear"
+    | `POLY   -> "polynomial"
+    | `RBF    -> "rbf"
+    | _       -> assert false
+  in
+  let print_error_rate kernel =
+    let model = Svm.train ~kernel ~c:10. ~weights:[(1,10.);(0,1.)] problem in
+    let preds = Svm.predict model ~x:samples in
+    let errors = n_samples - Stats.calc_n_correct targets preds in
+    printf "##########################################\n";
+    printf " kernel %s: error rate = %d / %d\n" (kernel_name kernel) errors n_samples;
+    printf "##########################################\n";
+  in
+  List.iter kernels ~f:print_error_rate;
+  let model = Svm.train ~kernel:`RBF ~c:10. problem in
+  let input = Mat.col inputs 1 in
+  printf "@[##########################################@\n";
+  printf " Decision values of predicting: @[%a@]@\n" pp_rfvec input;
+  printf "##########################################@]@\n";
+  printf "Number of Classes: %d\n" (Svm.Model.get_n_classes model);
+  let dec_mat = Svm.predict_values model ~x:input in
+  let labels = Svm.Model.get_labels model in
+  List.iter (List.cartesian_product labels labels) ~f:(fun (i, j) ->
+    if j > i then printf "{%d, %d} = %f\n" i j dec_mat.(i).(j));
+  let model = Svm.train ~kernel:`RBF ~c:10. ~probability:true problem in
+  let input = Mat.col inputs 2 in
+  let pred_label, prob_estimates = Svm.predict_probability model ~x:input in
+  printf "@[##########################################@\n";
+  printf " Probability estimates of predicting: @[%a@]@\n" pp_rfvec input;
+  printf "##########################################@]@\n";
+  printf "predicted class: %d\n" (Int.of_float pred_label);
+  List.iter labels ~f:(fun i ->
+    printf "prob(label=%d) = %g\n" i prob_estimates.(i));
+  printf "\n##########################################\n";
+  printf " Precomputed kernels\n";
+  printf "##########################################\n";
+  let k = Mat.of_array [|
+    [|1.; 0.; 0.; 0.; 0.|]; [|2.; 0.; 1.; 0.; 1.|];
+    [|3.; 0.; 0.; 1.; 1.|]; [|4.; 0.; 1.; 1.; 2.|];
+  |] in
+  let problem = Svm.Problem.create ~x:k ~y:targets in
+  let model = Svm.train ~kernel:`PRECOMPUTED ~c:10.
+    ~weights:[(1,10.);(0,1.)] problem
+  in
+  let pred_labels = Svm.predict model ~x:k in
+  printf "predicted classes: @[%a@]@\n" pp_rfvec pred_labels;
+open Core.Std
+open Lacaml.D
+open Libsvm
+
+let () =
+  let x = Mat.of_array
+    [|
+      [| 0.; 0. |];
+      [| 0.; 1. |];
+      [| 1.; 0. |];
+      [| 1.; 1. |];
+    |]
+  in
+  let target = Vec.of_array [| 0.; 1.; 1.; 0. |] in
+  let problem = Svm.Problem.create ~x ~y:target in
+  let model = Svm.train problem in
+  let preds = Svm.predict model ~x in
+  Array.iter2_exn (Mat.to_array x) (Vec.to_array preds) ~f:(fun x y ->
+    printf "(%1.0f, %1.0f) -> %1.0f\n" x.(0) x.(1) y)
+# OASIS_START
+# DO NOT EDIT (digest: 5f8ff6c05f4cccc243bf0b09b4f01326)
+version = "0.8"
+description = "libsvm-ocaml - OCaml bindings to the LIBSVM library"
+requires = "core lacaml"
+archive(byte) = "libsvm.cma"
+archive(byte, plugin) = "libsvm.cma"
+archive(native) = "libsvm.cmxa"
+archive(native, plugin) = "libsvm.cmxs"
+exists_if = "libsvm.cma"
+# OASIS_STOP
+

lib/liblibsvm_stubs.clib

+# OASIS_START
+# DO NOT EDIT (digest: 03501a3df9c73293dcb2a2f5f771d6f7)
+libsvm_stubs.o
+# OASIS_STOP
+(*
+   LIBSVM-OCaml - OCaml-bindings to the LIBSVM library
+
+   Copyright (C) 2013-  Oliver Gu
+   email: odietric@gmail.com
+
+   Copyright (C) 2005  Dominik Brugger
+   email: dominikbrugger@fastmail.fm
+   WWW:   http://ocaml-libsvm.berlios.de
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*)
+
+open Core.Std
+open Lacaml.D
+open Printf
+
+module Svm = struct
+  type problem
+  type params
+  type model
+
+  type svm_type =
+  | C_SVC
+  | NU_SVC
+  | ONE_CLASS
+  | EPSILON_SVR
+  | NU_SVR
+
+  type kernel_type =
+  | LINEAR
+  | POLY
+  | RBF
+  | SIGMOID
+  | PRECOMPUTED
+
+  type svm_params = {
+    svm_type : svm_type;
+    kernel_type : kernel_type;
+    degree : int;
+    gamma : float;
+    coef0 : float;
+    c : float;
+    nu : float;
+    eps : float;
+    cachesize : float;
+    tol : float;
+    shrinking : bool;
+    probability : bool;
+    nr_weight : int;
+    weight_label : int list;
+    weight : float list;
+  }
+
+  module Stub = struct
+    type double_array
+    type svm_node
+    type svm_node_array
+    type svm_node_matrix
+
+    external double_array_create :
+      int -> double_array = "double_array_create_stub"
+    external double_array_set :
+      double_array -> int -> float -> unit = "double_array_set_stub"
+    external double_array_get :
+      double_array -> int -> float = "double_array_get_stub"
+    external svm_node_array_create :
+      int -> svm_node_array = "svm_node_array_create_stub"
+    external svm_node_array_set :
+      svm_node_array -> int -> int -> float -> unit = "svm_node_array_set_stub"
+    external svm_node_matrix_create :
+      int -> svm_node_matrix = "svm_node_matrix_create_stub"
+    external svm_node_matrix_set :
+      svm_node_matrix -> int -> svm_node_array -> unit = "svm_node_matrix_set_stub"
+    external svm_problem_create :
+      unit -> problem = "svm_problem_create_stub"
+    external svm_problem_l_set :
+      problem -> int -> unit = "svm_problem_l_set_stub"
+    external svm_problem_l_get :
+      problem -> int = "svm_problem_l_get_stub"
+    external svm_problem_y_set :
+      problem -> double_array -> unit = "svm_problem_y_set_stub"
+    external svm_problem_y_get :
+      problem -> int -> float = "svm_problem_y_get_stub"
+    external svm_problem_x_set :
+      problem -> svm_node_matrix -> unit = "svm_problem_x_set_stub"
+    external svm_problem_x_get :
+      problem -> int -> int -> (int * float) = "svm_problem_x_get_stub"
+    external svm_problem_width :
+      problem -> int -> int = "svm_problem_width_stub"
+    external svm_problem_print :
+      problem -> unit = "svm_problem_print_stub"
+    external svm_param_create : svm_params -> params = "svm_param_create_stub"
+
+    external svm_set_quiet_mode : unit -> unit = "svm_set_quiet_mode_stub"
+    external svm_train : problem -> params -> model = "svm_train_stub"
+    external svm_cross_validation :
+      problem -> params -> int -> vec = "svm_cross_validation_stub"
+
+    external svm_save_model : string -> model -> unit = "svm_save_model_stub"
+    external svm_load_model : string -> model = "svm_load_model_stub"
+
+    external svm_get_svm_type : model -> svm_type = "svm_get_svm_type_stub"
+    external svm_get_nr_class : model -> int = "svm_get_nr_class_stub"
+    external svm_get_labels : model -> int list = "svm_get_labels_stub"
+    external svm_get_svr_probability :
+      model -> float = "svm_get_svr_probability_stub"
+    external svm_check_probability_model :
+      model -> bool = "svm_check_probability_model_stub"
+
+    external svm_predict_values :
+      model -> svm_node_array -> float array = "svm_predict_values_stub"
+    external svm_predict :
+      model -> svm_node_array -> float = "svm_predict_stub"
+    external svm_predict_probability :
+      model -> svm_node_array -> float * float array = "svm_predict_probability_stub"
+  end
+
+  (* Note: This function does not create a sparse svm node, i.e. we also add
+     zero values to the node. The reason is that learning with precomputed
+     kernels requires a non-sparse node representation. *)
+  let svm_node_array_of_vec v =
+    let n = Vec.dim v in
+    let node = Stub.svm_node_array_create (n+1) in
+    Vec.iteri (fun index value ->
+      let pos = index-1 in
+      Stub.svm_node_array_set node pos pos value) v;
+    Stub.svm_node_array_set node n (-1) 0.;
+    node
+
+  let svm_node_array_of_list l ~len =
+    let size = len + 1 in
+    let node = Stub.svm_node_array_create size in
+    List.iteri l ~f:(fun pos (index, value) ->
+      Stub.svm_node_array_set node pos index value);
+    Stub.svm_node_array_set node len (-1) 0.;
+    node
+
+  let count_lines file =
+    In_channel.with_file file ~f:(fun ic ->
+      In_channel.fold_lines ic ~init:0 ~f:(fun count _line -> count + 1))
+
+  let parse_line file = stage (fun line ~pos ->
+    let result = Result.try_with (fun () ->
+      match String.rstrip line |! String.split ~on:' ' with
+      | [] -> assert false
+      | x :: xs ->
+        let target = Float.of_string x in
+        let feats = List.map xs ~f:(fun str ->
+          let index, value = String.lsplit2_exn str ~on:':' in
+          Int.of_string index, Float.of_string value)
+        in
+        target, feats)
+    in
+    match result with
+    | Ok x -> x
+    | Error exn ->
+      failwithf "%s: wrong input format at line %d: %s" file pos (Exn.to_string exn) ())
+
+  module Problem = struct
+    type t = {
+      n_samples : int;
+      n_feats : int;
+      prob : problem;
+    }
+
+    let get_n_samples t = t.n_samples
+    let get_n_feats t = t.n_feats
+
+    let create ~x ~y =
+      let n_samples = Mat.dim1 x in
+      let n_feats = Mat.dim2 x in
+      let x' = Mat.transpose x in
+      let m = Stub.svm_node_matrix_create n_samples in
+      let v = Stub.double_array_create n_samples in
+      for i = 1 to n_samples do
+        let x_row = Mat.col x' i in
+        Stub.svm_node_matrix_set m (i-1) (svm_node_array_of_vec x_row);
+        Stub.double_array_set v (i-1) y.{i}
+      done;
+      let prob = Stub.svm_problem_create () in
+      Stub.svm_problem_l_set prob n_samples;
+      Stub.svm_problem_x_set prob m;
+      Stub.svm_problem_y_set prob v;
+      { n_samples;
+        n_feats;
+        prob;
+      }
+
+    let load file =
+      let n_samples = count_lines file in
+      let n_feats = ref 0 in
+      let x = Stub.svm_node_matrix_create n_samples in
+      let y = Stub.double_array_create n_samples in
+      In_channel.with_file file ~f:(fun ic ->
+        let parse_line = unstage (parse_line file) in
+        let rec loop i =
+          match In_channel.input_line ic with
+          | None -> ()
+          | Some line ->
+            let target, feats = parse_line line ~pos:i in
+            Stub.double_array_set y (i-1) target;
+            let len = List.length feats in
+            Stub.svm_node_matrix_set x (i-1) (svm_node_array_of_list feats ~len);
+            n_feats := max !n_feats len;
+            loop (i+1)
+        in
+        loop 1);
+      let prob = Stub.svm_problem_create () in
+      Stub.svm_problem_l_set prob n_samples;
+      Stub.svm_problem_x_set prob x;
+      Stub.svm_problem_y_set prob y;
+      { n_samples;
+        n_feats = !n_feats;
+        prob;
+      }
+
+    let output t oc =
+      let buf = Buffer.create 1024 in
+      for i = 0 to t.n_samples-1 do
+        Buffer.add_string buf (sprintf "%g" (Stub.svm_problem_y_get t.prob i));
+        let width = Stub.svm_problem_width t.prob i in
+        for j = 0 to width-1 do
+          let index, value = Stub.svm_problem_x_get t.prob i j in
+          Buffer.add_string buf (sprintf " %d:%g" index value);
+        done;
+        Buffer.add_char buf '\n';
+        Out_channel.output_string oc (Buffer.contents buf);
+        Buffer.clear buf
+      done;
+      Out_channel.flush oc
+
+    let save t file = Out_channel.with_file file ~f:(fun oc -> output t oc)
+
+    let min_max_feats t =
+      let min_feats = Vec.make t.n_feats Float.infinity in
+      let max_feats = Vec.make t.n_feats Float.neg_infinity in
+      for i = 0 to t.n_samples-1 do
+        let width = Stub.svm_problem_width t.prob i in
+        for j = 0 to width-1 do
+          let index, value = Stub.svm_problem_x_get t.prob i j in
+          min_feats.{index} <- Float.min min_feats.{index} value;
+          max_feats.{index} <- Float.max max_feats.{index} value;
+        done;
+      done;
+      (`Min min_feats, `Max max_feats)
+
+    let scale ?(lower= -.1.) ?(upper=1.) t ~min_feats ~max_feats =
+      let n_samples = t.n_samples in
+      let x = Stub.svm_node_matrix_create n_samples in
+      let y = Stub.double_array_create n_samples in
+      for i = 0 to n_samples-1 do
+        let width = Stub.svm_problem_width t.prob i in
+        let node = Stub.svm_node_array_create (width+1) in
+        for j = 0 to width-1 do
+          let index, value = Stub.svm_problem_x_get t.prob i j in
+          if Float.(=.) value min_feats.{index} then
+            Stub.svm_node_array_set node j index lower
+          else if Float.(=.) value max_feats.{index} then
+            Stub.svm_node_array_set node j index upper
+          else
+            let new_value = lower +. (upper-.lower) *.
+              (value-.min_feats.{index}) /.
+              (max_feats.{index}-.min_feats.{index})
+            in
+            Stub.svm_node_array_set node j index new_value
+        done;
+        Stub.svm_node_array_set node width (-1) 0.;
+        Stub.svm_node_matrix_set x i node;
+        Stub.double_array_set y i (Stub.svm_problem_y_get t.prob i);
+      done;
+      let scaled_prob = Stub.svm_problem_create () in
+      Stub.svm_problem_l_set scaled_prob n_samples;
+      Stub.svm_problem_x_set scaled_prob x;
+      Stub.svm_problem_y_set scaled_prob y;
+      { n_samples;
+        n_feats = t.n_feats;
+        prob = scaled_prob;
+      }
+
+    let print t = Stub.svm_problem_print t.prob
+  end
+
+  module Model = struct
+    type t = model
+
+    let get_svm_type t =
+      match Stub.svm_get_svm_type t with
+      | C_SVC       -> `C_SVC
+      | NU_SVC      -> `NU_SVC
+      | ONE_CLASS   -> `ONE_CLASS
+      | EPSILON_SVR -> `EPSILON_SVR
+      | NU_SVR      -> `NU_SVR
+
+    let get_n_classes t = Stub.svm_get_nr_class t
+
+    let get_labels t =
+      match Stub.svm_get_svm_type t with
+      | NU_SVR | EPSILON_SVR | ONE_CLASS ->
+        invalid_arg "Cannot return labels for a regression or one-class model."
+      | _ -> Stub.svm_get_labels t
+
+    let get_svr_probability t =
+      match Stub.svm_get_svm_type t with
+      | EPSILON_SVR | NU_SVR -> Stub.svm_get_svr_probability t
+      | _ -> invalid_arg "The model is no regression model."
+
+    let save t filename = Stub.svm_save_model filename t
+    let load filename = Stub.svm_load_model filename
+  end
+
+  let create_params ~svm_type ~kernel ~degree ~gamma ~coef0 ~c
+      ~nu ~eps ~cachesize ~tol ~shrinking ~probability ~weights =
+    let svm_type = match svm_type with
+      | `C_SVC       -> C_SVC
+      | `NU_SVC      -> NU_SVC
+      | `ONE_CLASS   -> ONE_CLASS
+      | `EPSILON_SVR -> EPSILON_SVR
+      | `NU_SVR      -> NU_SVR
+    in
+    let kernel_type = match kernel with
+      | `LINEAR      -> LINEAR
+      | `POLY        -> POLY
+      | `RBF         -> RBF
+      | `SIGMOID     -> SIGMOID
+      | `PRECOMPUTED -> PRECOMPUTED
+    in
+    let shrinking = match shrinking with
+      | `on  -> true
+      | `off -> false
+    in
+    let weight_label, weight = List.unzip weights in
+    Stub.svm_param_create {
+      svm_type;
+      kernel_type;
+      degree;
+      gamma;
+      coef0;
+      c;
+      nu;
+      eps;
+      cachesize;
+      tol;
+      shrinking;
+      probability;
+      nr_weight = List.length weight;
+      weight_label;
+      weight;
+    }
+
+  let train
+      ?(svm_type=`C_SVC)
+      ?(kernel=`RBF)
+      ?(degree=3)
+      ?(gamma=0.)
+      ?(coef0=0.)
+      ?(c=1.)
+      ?(nu=0.5)
+      ?(eps=0.1)
+      ?(cachesize=100.)
+      ?(tol=1e-3)
+      ?(shrinking=`on)
+      ?(probability=false)
+      ?(weights=[])
+      ?(verbose=false)
+      problem =
+    let params = create_params
+      ~gamma:(1. /. float problem.Problem.n_feats)
+      ~svm_type ~kernel ~degree ~coef0 ~c ~nu ~eps
+      ~cachesize ~tol ~shrinking ~probability ~weights
+    in
+    if not verbose then Stub.svm_set_quiet_mode () else ();
+    Stub.svm_train problem.Problem.prob params
+
+  let cross_validation
+      ?(svm_type=`C_SVC)
+      ?(kernel=`RBF)
+      ?(degree=3)
+      ?(gamma=0.)
+      ?(coef0=0.)
+      ?(c=1.)
+      ?(nu=0.5)
+      ?(eps=0.1)
+      ?(cachesize=100.)
+      ?(tol=1e-3)
+      ?(shrinking=`on)
+      ?(probability=false)
+      ?(weights=[])
+      ?(verbose=false)
+      ~n_folds problem =
+    let params = create_params
+      ~gamma:(1. /. float problem.Problem.n_feats)
+      ~svm_type ~kernel ~degree ~coef0 ~c ~nu ~eps
+      ~cachesize ~tol ~shrinking ~probability ~weights
+    in
+    if not verbose then Stub.svm_set_quiet_mode () else ();
+    Stub.svm_cross_validation problem.Problem.prob params n_folds
+
+  let predict_one model ~x = Stub.svm_predict model (svm_node_array_of_vec x)
+
+  let predict model ~x =
+    let n = Mat.dim1 x in
+    let y = Vec.create n in
+    let x' = Mat.transpose x in
+    for i = 1 to n do
+      y.{i} <- predict_one model ~x:(Mat.col x' i)
+    done;
+    y
+
+  let predict_values model ~x =
+    let dec_vals = Stub.svm_predict_values model (svm_node_array_of_vec x) in
+    match Stub.svm_get_svm_type model with
+    | EPSILON_SVR | NU_SVR | ONE_CLASS ->
+      Array.make_matrix 1 1 dec_vals.(0)
+    | C_SVC | NU_SVC ->
+      let n_classes = Stub.svm_get_nr_class model in
+      let dec_mat = Array.make_matrix n_classes n_classes 0. in
+      let count = ref 0 in
+      for i = 0 to n_classes-1 do
+        for j = i+1 to n_classes-1 do
+          dec_mat.(i).(j) <-   dec_vals.(!count);
+          dec_mat.(j).(i) <- -.dec_vals.(!count);
+          incr count
+        done
+      done;
+      dec_mat
+
+  let predict_probability model ~x =
+    match Stub.svm_get_svm_type model with
+    | EPSILON_SVR | NU_SVR ->
+      invalid_arg "For probability estimates call Model.get_svr_probability."
+    | ONE_CLASS ->
+      invalid_arg "One-class problems do not support probability estimates."
+    | C_SVC | NU_SVC ->
+      if Stub.svm_check_probability_model model then
+        Stub.svm_predict_probability model (svm_node_array_of_vec x)
+      else
+        invalid_arg "Model does not support probability estimates."
+
+  let predict_from_file model file =
+    let n_samples = count_lines file in
+    let expected = Vec.create n_samples in
+    let predicted = Vec.create n_samples in
+    In_channel.with_file file ~f:(fun ic ->
+      let parse_line = unstage (parse_line file) in
+      let rec loop i =
+        match In_channel.input_line ic with
+        | None -> (`Expected expected, `Predicted predicted)
+        | Some line ->
+          let target, feats = parse_line line ~pos:i in
+          expected.{i} <- target;
+          let node = svm_node_array_of_list feats ~len:(List.length feats) in
+          predicted.{i} <- Stub.svm_predict model node;
+          loop (i+1)
+      in
+      loop 1)
+end
+
+module Stats = struct
+
+  let check_dimension x y ~location =
+    let dimx = Vec.dim x in
+    let dimy = Vec.dim y in
+    if dimx <> dimy then
+      invalid_argf "dimension mismatch in Stats.%s: %d <> %d" location dimx dimy ()
+    else ()
+
+  let calc_n_correct ~expected ~predicted =
+    check_dimension expected predicted ~location:"calc_n_correct";
+    Vec.fold (fun count x -> count + if x = 0. then 1 else 0) 0
+      (Vec.sub expected predicted)
+
+  let calc_accuracy ~expected ~predicted =
+    check_dimension expected predicted ~location:"calc_accuracy";
+    let l = Vec.dim expected in
+    let n_correct = calc_n_correct ~expected ~predicted in
+    Float.(of_int n_correct / of_int l)
+
+  let calc_mse ~expected ~predicted =
+    check_dimension expected predicted ~location:"calc_mse";
+    let l = Vec.dim expected in
+    Vec.ssqr_diff predicted expected /. float l
+
+  let calc_scc ~expected ~predicted =
+    check_dimension expected predicted ~location:"calc_scc";
+    let array_x = Vec.to_array predicted in
+    let array_y = Vec.to_array expected in   (* true values *)
+    let sum_x  = ref 0. in
+    let sum_y  = ref 0. in
+    let sum_xx = ref 0. in
+    let sum_yy = ref 0. in
+    let sum_xy = ref 0. in
+    Array.iter2_exn array_x array_y ~f:(fun x y ->
+      sum_x  := !sum_x +. x;
+      sum_y  := !sum_y +. y;
+      sum_xx := x *. x;
+      sum_yy := y *. y;
+      sum_xy := x *. y;
+    );
+    let sqr x = x *. x in
+    let l = float (Vec.dim expected) in
+    Float.(sqr (l * !sum_xy - !sum_x * !sum_y) /
+             ((l * !sum_xx - sqr !sum_x) * (l * !sum_yy - sqr !sum_y)))
+end
+(*
+   LIBSVM-OCaml - OCaml-bindings to the LIBSVM library
+
+   Copyright (C) 2013-  Oliver Gu
+   email: odietric@gmail.com
+
+   Copyright (C) 2005  Dominik Brugger
+   email: dominikbrugger@fastmail.fm
+   WWW:   http://ocaml-libsvm.berlios.de
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*)
+
+(** Interface to Libsvm *)
+
+open Core.Std
+open Lacaml.D
+
+module Svm : sig
+
+  (** {2 SVM problem and model} *)
+
+  module Problem : sig
+    type t (** Type of a SVM problem (training set). *)
+
+    (** [create x y] constructs a problem from a feature matrix [x] and target
+        vector [y]. Each row of [x] is a feature vector of a training
+        instance. *)
+    val create : x:mat -> y:vec -> t
+
+    (** [get_n_samples prob] @return the number of training samples. *)
+    val get_n_samples : t -> int
+
+    (** [get_n_feats prob] @return the number of features (attributes). *)
+    val get_n_feats : t -> int
+
+    (** [load filename] loads a problem from the file [filename].
+        @raise Failure if an error occured during parsing of [filename]. *)
+    val load : string -> t
+
+    (** [output prob oc] outputs the problem [prob] to an output channel [oc].
+        NOTE: the function does not close the output channel. *)
+    val output : t -> out_channel -> unit
+
+    (** [save prob filename] saves the problem [prob] to the file [filename]. *)
+    val save : t -> string -> unit
+
+    (** [min_max_feats prob] @return the smallest and largest feature value for
+        each column in the feature matrix. *)
+    val min_max_feats : t -> [ `Min of vec ] * [ `Max of vec ]
+
+    (** [scale ?lower ?upper prob min_feats max_feats] @return a linearly
+        scaled problem where each feature (attribute) lies in the range
+        \[[lower],[upper]\]. The default range is \[-1,1\]. *)
+    val scale :
+      ?lower:float -> ?upper:float
+      -> t
+      -> min_feats:vec -> max_feats:vec
+      -> t
+
+    (** [print prob] prints the internal representation of a problem.
+        It is mainly used for debugging purposes. *)
+    val print : t -> unit
+  end
+
+  module Model : sig
+    type t (** Type of a SVM model. *)
+
+    (** [get_svm_type model] @return the svm type that was used to train the
+        given [model]. *)
+    val get_svm_type : t -> [ `C_SVC | `NU_SVC | `ONE_CLASS | `EPSILON_SVR | `NU_SVR ]
+
+    (** [get_n_classes model] @return the number of classes for a
+        classification model or 2 for a regression or an one-class model. *)
+    val get_n_classes : t -> int
+
+    (** [get_labels model] @return the labels of a two or multi-class
+        classification problem in a list.
+        @raise Invalid_argument in the case of a regression or one-class model. *)
+    val get_labels : t -> int list
+
+    (** [get_svr_probability model] @return a positive value for a regression
+        model with probability information. In the case of no probability
+        information, 0 is returned.
+        @raise Invalid_argument for non-regression models. *)
+    val get_svr_probability : t -> float
+
+    (** [save model filename] saves a model to the file [filename]. *)
+    val save : t -> string -> unit
+
+    (** [load filename] loads a model from the file [filename].
+        @raise Failure if model could not be loaded. *)
+    val load : string -> t
+  end
+
+  (** {2 SVM training} *)
+
+  (** [train params problem] trains a SVM model on the given [problem] and
+      parameters [params]:
+      - [svm_type] - type of SVM classification/regression (default [C_SVC])
+      - [kernel] - type of the SVM kernel (default [RBF])
+      - [degree] - the exponent in the [POLY] kernel (default 3)
+      - [gamma] - parameter for [POLY], [RBF] and [SIGMOID] kernel (default 0)
+      - [coef0] - parameter for [POLY] and [SIGMOID] kernel (default 0)
+      - [c] - the cost of constraints violation in [C_SVC], [EPSILON_SVR], and
+      [NU_SVR] (default 1)
+      - [nu] - the parameter in [NU_SVM], [NU_SVR] and [ONE_CLASS] (default 0.5)
+      - [eps] - the epsilon in the epsilon-sensitive loss function of
+      [EPSILON_SVR] (default 0.1)
+      - [cachesize] - the size of the kernel cache in megabytes (default 100)
+      - [tol] - the stopping criterion (default 1e-3)
+      - [shrinking] - use [on] to conduct shrinking, otherwise [off] (default [on])
+      - [probability] - if probability = true, then a model with probability
+      information will be obtained (default false)
+      - [weights] - weights to penalize classes (default = [])
+      - [verbose] - if verbose = true, then train the SVM in verbose mode
+      (default false)
+      @return the trained model.
+      @raise Failure if parameters are not feasible. *)
+  val train :
+    ?svm_type:[ `C_SVC | `NU_SVC | `ONE_CLASS | `EPSILON_SVR | `NU_SVR ]
+    -> ?kernel:[
+    | `LINEAR       (* u'*v *)
+    | `POLY         (* (gamma*u'*v + coef0)^degree *)
+    | `RBF          (* exp(-gamma*|u-v|^2) *)
+    | `SIGMOID      (* tanh(gamma*u'*v + coef0) *)
+    | `PRECOMPUTED  (* kernel values are stored in a file *)
+    ]
+    -> ?degree:int
+    -> ?gamma:float
+    -> ?coef0:float
+    -> ?c:float
+    -> ?nu:float
+    -> ?eps:float
+    -> ?cachesize:float
+    -> ?tol:float
+    -> ?shrinking:[ `on | `off ]
+    -> ?probability:bool
+    -> ?weights: (int * float) list
+    -> ?verbose:bool
+    -> Problem.t
+    -> Model.t
+
+  (** [cross_validation params problem n_folds] conducts n-fold
+      cross-validation on the given [problem] and parameters [params].
+      The parameters [params] are the same as in [train] above.
+      @return vector with all predicted values (of all problem instances) in
+      the validation process.
+      @raise Failure if parameters are not feasible. *)
+  val cross_validation :
+    ?svm_type:[ `C_SVC | `NU_SVC | `ONE_CLASS | `EPSILON_SVR | `NU_SVR ]
+    -> ?kernel:[
+    | `LINEAR       (* u'*v *)
+    | `POLY         (* (gamma*u'*v + coef0)^degree *)
+    | `RBF          (* exp(-gamma*|u-v|^2) *)
+    | `SIGMOID      (* tanh(gamma*u'*v + coef0) *)
+    | `PRECOMPUTED  (* kernel values are stored in a file *)
+    ]
+    -> ?degree:int
+    -> ?gamma:float
+    -> ?coef0:float
+    -> ?c:float
+    -> ?nu:float
+    -> ?eps:float
+    -> ?cachesize:float
+    -> ?tol:float
+    -> ?shrinking:[ `on | `off ]
+    -> ?probability:bool
+    -> ?weights: (int * float) list
+    -> ?verbose:bool
+    -> n_folds:int
+    -> Problem.t
+    -> vec
+
+  (** {2 SVM prediction} *)
+
+  (** [predict_one model x] does classification or regression on a test vector
+      [x] given a [model].
+      For a classification model, the predicted class for [x] is returned.
+      For a regression model, the function value of [x] is returned.
+      For a one-class model, +1 or -1 is returned. *)
+  val predict_one : Model.t -> x:vec -> float
+
+  (** [predict model x] applies predict_one to each row of the matrix [x]. *)
+  val predict : Model.t -> x:mat -> vec
+
+  (** [predict_values model x] @return a matrix with decision values on a test
+      vector [x]. *)
+  val predict_values : Model.t -> x:vec -> float array array
+
+  (** [predict_probability m x] does classification or regression on a test
+      vector [x] based on a [model] with probability information.
+      @raise Invalid_argument if the model does not support probability
+      estimates. *)
+  val predict_probability : Model.t -> x:vec -> float * float array
+
+  (** [predict_from_file model filename] does classification or regression
+      on the testing data given in [filename].
+      @return a pair vectors containing the expected (true) values form the
+      test file and the predicted ones computed from the given [model].
+      @raise Failure if an error occured during parsing of [filename]. *)
+  val predict_from_file :
+    Model.t
+    -> string
+    -> ([ `Expected of vec ] * [ `Predicted of vec ])
+end
+
+module Stats : sig
+  (** These functions compute several performance measures to compare the
+      [predicted] values of a SVM model to the [expected] values of a
+      given test data set. For more details, have a look on page 8 in the
+      {{:http://www.csie.ntu.edu.tw/~cjlin/papers/libsvm.pdf } LIBSVM paper} *)
+
+  (** [calc_n_correct expected actual] @return the number of correctly
+      predicted labels.
+      @raise Invalid_argument if the vector dimensions do not match. *)
+  val calc_n_correct : expected:vec -> predicted:vec -> int
+
+  (** [calc_accuracy expected predicted] @return the ratio (in percent) of
+      correctly predicted labels to the number of all labels.
+      @raise Invalid_argument if the vector dimensions do not match. *)
+  val calc_accuracy : expected:vec -> predicted:vec -> float
+
+  (** [calc_mse expected predicted] @return the mean sum of squared errors.
+      @raise Invalid_argument if the vector dimensions do not match. *)
+  val calc_mse : expected:vec -> predicted:vec -> float
+
+  (** [calc_scc expected predicted] @return the squared correlation coefficient.
+      @raise Invalid_argument if the vector dimensions do not match. *)
+  val calc_scc : expected:vec -> predicted:vec -> float
+end
+# OASIS_START
+# DO NOT EDIT (digest: 783233159827284c6b3895901840756f)
+Libsvm
+# OASIS_STOP

lib/libsvm_stubs.c

+/*
+   LIBSVM-OCaml - OCaml-bindings to the LIBSVM library
+
+   Copyright (C) 2013-  Oliver Gu
+   email: odietric@gmail.com
+
+   Copyright (C) 2005  Dominik Brugger
+   email: dominikbrugger@fastmail.fm
+   WWW:   http://ocaml-libsvm.berlios.de
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <stdio.h>
+#include <string.h>
+
+#include <caml/mlvalues.h>
+#include <caml/custom.h>
+#include <caml/alloc.h>
+#include <caml/memory.h>
+#include <caml/fail.h>
+#include <caml/signals.h>
+#include <caml/bigarray.h>
+
+#include <libsvm/svm.h>
+
+/* Type definitions */
+
+typedef struct svm_node svm_node;
+typedef struct svm_problem svm_prob;
+typedef struct svm_parameter svm_param;
+typedef struct svm_model svm_model;
+typedef svm_node *svm_node_matrix;
+
+#define Caml_stat_alloc(type,n) (type *)caml_stat_alloc((n)*sizeof(type))
+
+/* Macros to access the wrapper structures stored in the custom blocks */
+
+#define Svm_node_matrix_val(x) ((*(svm_node_matrix **) (Data_custom_val(x))))
+#define Svm_node_array_val(x) ((*(svm_node **) (Data_custom_val(x))))
+#define Double_array_val(x) ((*(double **) (Data_custom_val(x))))
+#define Svm_problem_val(x) ((*(svm_prob **) (Data_custom_val(x))))
+#define Svm_param_val(x) ((*(svm_param **) (Data_custom_val(x))))
+#define Svm_model_val(x) ((*(svm_model **) (Data_custom_val(x))))
+
+/* Set quiet mode */
+
+void print_null(const char *s) {}
+
+CAMLprim value svm_set_quiet_mode_stub(value unit)
+{
+  CAMLparam0();
+  svm_set_print_string_function(&print_null);
+  CAMLreturn(Val_unit);
+}
+
+/* SVM Problem */
+
+void finalize_node_array_gc(value v_array)
+{
+  svm_node *array =  Svm_node_array_val(v_array);
+  caml_stat_free(array);
+}
+
+static inline value alloc_node_array(int len)
+{
+  svm_node *array = Caml_stat_alloc(svm_node,len);
+  value v_array = caml_alloc_final(2, finalize_node_array_gc, 0, 1);
+  Svm_node_array_val(v_array) = array;
+  return v_array;
+}
+
+CAMLprim value svm_node_array_create_stub(value v_size)
+{
+  CAMLparam1(v_size);
+  CAMLlocal1(v_array);
+  v_array = alloc_node_array(Int_val(v_size));
+  CAMLreturn(v_array);
+}
+
+CAMLprim value svm_node_array_set_stub(value v_array, value v_pos,
+                                       value v_idx, value v_val)
+{
+  CAMLparam4(v_array, v_pos, v_idx, v_val);
+  svm_node *array;
+  int pos;
+
+  array = Svm_node_array_val(v_array);
+  pos = Int_val(v_pos);
+
+  array[pos].index = Int_val(v_idx);
+  array[pos].value = Double_val(v_val);
+
+  CAMLreturn(Val_unit);
+}
+
+void finalize_node_matrix_gc(value v_mat)
+{
+  svm_node_matrix *mat = Svm_node_matrix_val(v_mat);
+  caml_stat_free(mat);
+}
+
+static inline value alloc_node_matrix(int size)
+{
+  svm_node_matrix *mat = Caml_stat_alloc(svm_node*,size);
+  value v_mat = caml_alloc_final(2, finalize_node_matrix_gc, 0, 1);
+  Svm_node_matrix_val(v_mat) = mat;
+  return v_mat;
+}
+
+CAMLprim value svm_node_matrix_create_stub(value v_size)
+{
+  CAMLparam1(v_size);
+  CAMLlocal1(v_mat);
+  v_mat = alloc_node_matrix(Int_val(v_size));
+  CAMLreturn(v_mat);
+}
+
+CAMLprim value svm_node_matrix_set_stub(value v_mat, value v_idx, value v_arr)
+{
+  CAMLparam3(v_mat, v_idx, v_arr);
+  svm_node_matrix *mat;
+
+  mat = Svm_node_matrix_val(v_mat);
+  mat[Int_val(v_idx)] = Svm_node_array_val(v_arr);
+
+  CAMLreturn(Val_unit);
+}
+
+void finalize_double_array_gc(value v_d)
+{
+  double *d = Double_array_val(v_d);
+  caml_stat_free(d);
+}
+
+static inline value alloc_double_array(double *d)
+{
+  value v_d = caml_alloc_final(2, finalize_double_array_gc, 1, 1000);
+  Double_array_val(v_d) = d;
+  return v_d;
+}
+
+CAMLprim value double_array_create_stub(value v_len)
+{
+  CAMLparam1(v_len);
+  double *d = Caml_stat_alloc(double,Int_val(v_len));
+  CAMLreturn(alloc_double_array(d));
+}
+
+CAMLprim value double_array_set_stub(value v_d, value v_idx, value v_val)
+{
+  CAMLparam3(v_d, v_idx, v_val);
+  Double_array_val(v_d)[Int_val(v_idx)] = Double_val(v_val);
+  CAMLreturn(Val_unit);
+}
+
+CAMLprim value double_array_get_stub(value v_d, value v_idx)
+{
+  CAMLparam2(v_d, v_idx);
+  double *d = Double_array_val(v_d);
+  CAMLreturn(d[Int_val(v_idx)]);
+}
+
+void finalize_problem_gc(value v_prob)
+{
+  svm_prob *prob = Svm_problem_val(v_prob);
+  caml_stat_free(prob->x);
+  caml_stat_free(prob->y);
+}
+
+static inline value alloc_problem(svm_prob *prob)
+{
+  value v_prob = caml_alloc_final(2, finalize_problem_gc, 1, 100);
+  Svm_problem_val(v_prob) = prob;
+  return v_prob;
+}
+
+CAMLprim value svm_problem_create_stub(value unit)
+{
+  CAMLparam1(unit);
+  svm_prob *prob = Caml_stat_alloc(svm_prob,1);
+  CAMLreturn(alloc_problem(prob));
+}
+
+CAMLprim value svm_problem_l_set_stub(value v_prob, value v_size)
+{
+  CAMLparam2(v_prob, v_size);
+  Svm_problem_val(v_prob)->l = Int_val(v_size);
+  CAMLreturn(Val_unit);
+}
+
+CAMLprim value svm_problem_l_get_stub(value v_prob)
+{
+  CAMLparam1(v_prob);
+  CAMLreturn(Val_int(Svm_problem_val(v_prob)->l));
+}
+
+CAMLprim value svm_problem_y_set_stub(value v_prob, value v_y)
+{
+  CAMLparam2(v_prob, v_y);
+  svm_prob *prob;
+  int i;
+
+  prob = Svm_problem_val(v_prob);
+  prob->y = Caml_stat_alloc(double,prob->l); // NOTE: l must be initialized
+  for (i = 0; i < prob->l; i++)
+    prob->y[i] = Double_array_val(v_y)[i];
+
+  CAMLreturn(Val_unit);
+}
+
+CAMLprim value svm_problem_y_get_stub(value v_prob, value v_idx)
+{
+  CAMLparam1(v_prob);
+  svm_prob *prob = Svm_problem_val(v_prob);
+  int i = Int_val(v_idx);
+  CAMLreturn(caml_copy_double(prob->y[i]));
+}
+
+CAMLprim value svm_problem_x_set_stub(value v_prob, value v_x)
+{
+  CAMLparam2(v_prob, v_x);
+  Svm_problem_val(v_prob)->x = Svm_node_matrix_val(v_x);
+  CAMLreturn(Val_unit);
+}
+
+CAMLprim value svm_problem_x_get_stub(value v_prob, value v_i, value v_j)
+{
+  CAMLparam3(v_prob, v_i, v_j);
+  CAMLlocal1(v_result);
+
+  svm_node_matrix *x;
+  int i, j;
+
+  x = Svm_problem_val(v_prob)->x;
+  i = Int_val(v_i);
+  j = Int_val(v_j);
+
+  v_result = caml_alloc(2, 0);
+  Store_field(v_result, 0, Val_int(x[i][j].index));
+  Store_field(v_result, 1, caml_copy_double(x[i][j].value));
+
+  CAMLreturn(v_result);
+}
+
+CAMLprim value svm_problem_width_stub(value v_prob, value v_i)
+{
+  CAMLparam2(v_prob, v_i);
+  CAMLlocal1(v_result);
+
+  svm_node_matrix *x;
+  int i, j;
+
+  i = Int_val(v_i); j = 0;
+  x = Svm_problem_val(v_prob)->x;
+  while (x[i][j++].index != -1);
+
+  CAMLreturn(Val_int(j-1));
+}
+
+CAMLprim value svm_problem_print_stub(value v_prob)
+{
+  CAMLparam1(v_prob);
+  svm_node_matrix *x;
+  double *y;
+  int i, j, l;
+
+  l = Svm_problem_val(v_prob)->l;
+  x = Svm_problem_val(v_prob)->x;
+  y = Svm_problem_val(v_prob)->y;
+
+  for (i = 0; i < l; i++)
+  {
+    j = 0;
+    printf("%g ", y[i]);
+
+    while (x[i][j].index != -1)
+    {
+      printf("(%d, %g) ", x[i][j].index, x[i][j].value);
+      j++;
+    }
+    printf("\n");
+  }
+  CAMLreturn(Val_unit);
+}
+
+/* SVM Parameters */
+
+static inline void destroy_param(svm_param *param)
+{
+  caml_stat_free(param->weight_label);
+  caml_stat_free(param->weight);
+}
+
+void finalize_param_gc(value v_param)
+{
+  svm_param *param = Svm_param_val(v_param);
+  caml_stat_free(param->weight_label);
+  caml_stat_free(param->weight);
+  caml_stat_free(param);
+}
+
+static inline value alloc_param(svm_param *param)
+{
+  value v_param = caml_alloc_final(2, finalize_param_gc, 1, 100);
+  Svm_param_val(v_param) = param;
+  return v_param;
+}
+
+CAMLprim value svm_param_create_stub(value v_param)
+{
+  CAMLparam1(v_param);
+  CAMLlocal1(v_res);
+
+  svm_param *param;
+  param = Caml_stat_alloc(svm_param,1);
+
+  param->svm_type = Long_val(Field(v_param, 0));
+  param->kernel_type = Long_val(Field(v_param, 1));
+  param->degree = Long_val(Field(v_param, 2));
+  param->gamma = Double_val(Field(v_param, 3));
+  param->coef0 = Double_val(Field(v_param, 4));
+  param->C = Double_val(Field(v_param, 5));
+  param->nu = Double_val(Field(v_param, 6));
+  param->p = Double_val(Field(v_param, 7));