| <!-- HTML header for doxygen 1.8.4--> |
| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
| <html xmlns="http://www.w3.org/1999/xhtml"> |
| <head> |
| <meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/> |
| <meta http-equiv="X-UA-Compatible" content="IE=9"/> |
| <meta name="generator" content="Doxygen 1.8.4"/> |
| <meta name="keywords" content="madlib,postgres,greenplum,machine learning,data mining,deep learning,ensemble methods,data science,market basket analysis,affinity analysis,pca,lda,regression,elastic net,huber white,proportional hazards,k-means,latent dirichlet allocation,bayes,support vector machines,svm"/> |
| <title>MADlib: Support Vector Machines</title> |
| <link href="tabs.css" rel="stylesheet" type="text/css"/> |
| <script type="text/javascript" src="jquery.js"></script> |
| <script type="text/javascript" src="dynsections.js"></script> |
| <link href="navtree.css" rel="stylesheet" type="text/css"/> |
| <script type="text/javascript" src="resize.js"></script> |
| <script type="text/javascript" src="navtree.js"></script> |
| <script type="text/javascript"> |
| $(document).ready(initResizable); |
| $(window).load(resizeHeight); |
| </script> |
| <link href="search/search.css" rel="stylesheet" type="text/css"/> |
| <script type="text/javascript" src="search/search.js"></script> |
| <script type="text/javascript"> |
| $(document).ready(function() { searchBox.OnSelectItem(0); }); |
| </script> |
| <script type="text/x-mathjax-config"> |
| MathJax.Hub.Config({ |
| extensions: ["tex2jax.js", "TeX/AMSmath.js", "TeX/AMSsymbols.js"], |
| jax: ["input/TeX","output/HTML-CSS"], |
| }); |
| </script><script src="../mathjax/MathJax.js"></script> |
| <link href="doxygen.css" rel="stylesheet" type="text/css" /> |
| <link href="madlib_extra.css" rel="stylesheet" type="text/css"/> |
| <!-- google analytics --> |
| <script> |
| (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ |
| (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), |
| m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) |
| })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); |
| ga('create', 'UA-45382226-1', 'auto'); |
| ga('send', 'pageview'); |
| </script> |
| </head> |
| <body> |
| <div id="top"><!-- do not remove this div, it is closed by doxygen! --> |
| <div id="titlearea"> |
| <table cellspacing="0" cellpadding="0"> |
| <tbody> |
| <tr style="height: 56px;"> |
| <td style="padding-left: 0.5em;"> |
| <div id="projectname">MADlib |
|  <span id="projectnumber">1.3</span> <span style="font-size:10pt; font-style:italic"><a href="../latest/./group__grp__kernmach.html"> A newer version is available</a></span> |
| </div> |
| <div id="projectbrief">User Documentation</div> |
| </td> |
| <td> <div id="MSearchBox" class="MSearchBoxInactive"> |
| <span class="left"> |
| <img id="MSearchSelect" src="search/mag_sel.png" |
| onmouseover="return searchBox.OnSearchSelectShow()" |
| onmouseout="return searchBox.OnSearchSelectHide()" |
| alt=""/> |
| <input type="text" id="MSearchField" value="Search" accesskey="S" |
| onfocus="searchBox.OnSearchFieldFocus(true)" |
| onblur="searchBox.OnSearchFieldFocus(false)" |
| onkeyup="searchBox.OnSearchFieldChange(event)"/> |
| </span><span class="right"> |
| <a id="MSearchClose" href="javascript:searchBox.CloseResultsWindow()"><img id="MSearchCloseImg" border="0" src="search/close.png" alt=""/></a> |
| </span> |
| </div> |
| </td> |
| </tr> |
| </tbody> |
| </table> |
| </div> |
| <!-- end header part --> |
| <!-- Generated by Doxygen 1.8.4 --> |
| <script type="text/javascript"> |
| var searchBox = new SearchBox("searchBox", "search",false,'Search'); |
| </script> |
| </div><!-- top --> |
| <div id="side-nav" class="ui-resizable side-nav-resizable"> |
| <div id="nav-tree"> |
| <div id="nav-tree-contents"> |
| <div id="nav-sync" class="sync"></div> |
| </div> |
| </div> |
| <div id="splitbar" style="-moz-user-select:none;" |
| class="ui-resizable-handle"> |
| </div> |
| </div> |
| <script type="text/javascript"> |
| $(document).ready(function(){initNavTree('group__grp__kernmach.html','');}); |
| </script> |
| <div id="doc-content"> |
| <!-- window showing the filter options --> |
| <div id="MSearchSelectWindow" |
| onmouseover="return searchBox.OnSearchSelectShow()" |
| onmouseout="return searchBox.OnSearchSelectHide()" |
| onkeydown="return searchBox.OnSearchSelectKey(event)"> |
| <a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(0)"><span class="SelectionMark"> </span>All</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(1)"><span class="SelectionMark"> </span>Files</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(2)"><span class="SelectionMark"> </span>Functions</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(3)"><span class="SelectionMark"> </span>Variables</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(4)"><span class="SelectionMark"> </span>Groups</a></div> |
| |
| <!-- iframe showing the search results (closed by default) --> |
| <div id="MSearchResultsWindow"> |
| <iframe src="javascript:void(0)" frameborder="0" |
| name="MSearchResults" id="MSearchResults"> |
| </iframe> |
| </div> |
| |
| <div class="header"> |
| <div class="headertitle"> |
| <div class="title">Support Vector Machines<div class="ingroups"><a class="el" href="group__grp__early__stage.html">Early Stage Development</a></div></div> </div> |
| </div><!--header--> |
| <div class="contents"> |
| <div class="toc"><b>Contents</b> </p> |
| <ul> |
| <li> |
| <a href="#learn">Regression Learning Function</a> </li> |
| <li> |
| <a href="#classify">Classification Learning Function</a> </li> |
| <li> |
| <a href="#novelty">Novelty Detection Functions</a> </li> |
| <li> |
| <a href="#predict">Prediction Functions</a> </li> |
| <li> |
| <a href="#notes">Notes</a> </li> |
| <li> |
| <a href="#examples">Examples</a> </li> |
| <li> |
| <a href="#literature">Literature</a> </li> |
| <li> |
| <a href="#related">Related Topics</a> </li> |
| </ul> |
| </div><dl class="section warning"><dt>Warning</dt><dd><em> This MADlib method is still in early stage development. There may be some issues that will be addressed in a future version. Interface and implementation is subject to change. </em></dd></dl> |
| <p>Support vector machines (SVMs) and related kernel methods have been one of the most popular and well-studied machine learning techniques of the past 15 years, with an amazing number of innovations and applications.</p> |
| <p>In a nutshell, an SVM model \(f(x)\) takes the form of </p> |
| <p class="formulaDsp"> |
| \[ f(x) = \sum_i \alpha_i k(x_i,x), \] |
| </p> |
| <p> where each \( \alpha_i \) is a real number, each \( \boldsymbol x_i \) is a data point from the training set (called a support vector), and \( k(\cdot, \cdot) \) is a kernel function that measures how "similar" two objects are. In regression, \( f(\boldsymbol x) \) is the regression function we seek. In classification, \( f(\boldsymbol x) \) serves as the decision boundary; so for example in binary classification, the predictor can output class 1 for object \(x\) if \( f(\boldsymbol x) \geq 0 \), and class 2 otherwise.</p> |
| <p>In the case when the kernel function \( k(\cdot, \cdot) \) is the standard inner product on vectors, \( f(\boldsymbol x) \) is just an alternative way of writing a linear function </p> |
| <p class="formulaDsp"> |
| \[ f'(\boldsymbol x) = \langle \boldsymbol w, \boldsymbol x \rangle, \] |
| </p> |
| <p> where \( \boldsymbol w \) is a weight vector having the same dimension as \( \boldsymbol x \). One of the key points of SVMs is that we can use more fancy kernel functions to efficiently learn linear models in high-dimensional feature spaces, since \( k(\boldsymbol x_i, \boldsymbol x_j) \) can be understood as an efficient way of computing an inner product in the feature space: </p> |
| <p class="formulaDsp"> |
| \[ k(\boldsymbol x_i, \boldsymbol x_j) = \langle \phi(\boldsymbol x_i), \phi(\boldsymbol x_j) \rangle, \] |
| </p> |
| <p> where \( \phi(\boldsymbol x) \) projects \( \boldsymbol x \) into a (possibly infinite-dimensional) feature space.</p> |
| <p>There are many algorithms for learning kernel machines. This module implements the class of online learning with kernels algorithms described in Kivinen et al. [1]. It also includes the Stochastic Gradient Descent (SGD) method [3] for learning linear SVMs with the Hinge loss \(l(z) = \max(0, 1-z)\). See also the book Scholkopf and Smola [2] for much more details.</p> |
| <p>The SGD implementation is based on Léon Bottou's SGD package (<a href="http://leon.bottou.org/projects/sgd">http://leon.bottou.org/projects/sgd</a>). The methods introduced in [1] are implemented according to their original descriptions, except that we only update the support vector model when we make a significant error. The original algorithms in [1] update the support vector model at every step, even when no error was made, in the name of regularisation. For practical purposes, and this is verified empirically to a certain degree, updating only when necessary is both faster and better from a learning-theoretic point of view, at least in the i.i.d. setting.</p> |
| <p>Methods for classification, regression and novelty detection are available. Multiple instances of the algorithms can be executed in parallel on different subsets of the training data. The resultant support vector models can then be combined using standard techniques like averaging or majority voting.</p> |
| <p>Training data points are accessed via a table or a view. The support vector models can also be stored in tables for fast execution.</p> |
| <p><a class="anchor" id="learn"></a></p> |
| <dl class="section user"><dt>Regression Learning Function</dt><dd></dd></dl> |
| <p>Regression learning is achieved through the following function: </p> |
| <pre class="syntax"> |
| svm_regression( |
| input_table, model_table, parallel, kernel_func, |
| verbose DEFAULT false, eta DEFAULT 0.1, nu DEFAULT 0.005, slambda DEFAULT 0.05 |
| );</pre><p>For classification and regression, the training table/view is expected to be of the following form (the array size of <em>ind</em> must not be greater than 102,400.):<br/> |
| </p> |
| <pre>{TABLE|VIEW} input_table ( |
| ... |
| id INT, |
| ind FLOAT8[], |
| label FLOAT8, |
| ... |
| )</pre><p>For novelty detection, the label field is not required.</p> |
| <p><a class="anchor" id="classify"></a></p> |
| <dl class="section user"><dt>Classification Learning Function</dt><dd></dd></dl> |
| <p>Classification learning is achieved through the following two functions:</p> |
| <ul> |
| <li>Learn linear SVM(s) using SGD [3]. <pre class="syntax"> |
| lsvm_classification( input_table, |
| model_table, |
| parallel, |
| verbose DEFAULT false, |
| eta DEFAULT 0.1, |
| reg DEFAULT 0.001 |
| ) |
| </pre></li> |
| <li>Learn linear or non-linear SVM(s) using the method described in [1]. <pre class="syntax"> |
| svm_classification( input_table, |
| model_table, |
| parallel, |
| kernel_func, |
| verbose DEFAULT false, |
| eta DEFAULT 0.1, |
| nu DEFAULT 0.005 |
| ) |
| </pre></li> |
| </ul> |
| <p><a class="anchor" id="novelty"></a></p> |
| <dl class="section user"><dt>Novelty Detection Function</dt><dd></dd></dl> |
| <p>Novelty detection is achieved through the following function: </p> |
| <pre class="syntax"> |
| svm_novelty_detection( input_table, |
| model_table, |
| parallel, |
| kernel_func, |
| verbose DEFAULT false, |
| eta DEFAULT 0.1, |
| nu DEFAULT 0.005 |
| ) |
| </pre><p>Assuming the model_table parameter takes on value 'model', each learning function will produce two tables as output: 'model' and 'model_param'. The first contains the support vectors of the model(s) learned. The second contains the parameters of the model(s) learned, which include information like the kernel function used and the value of the intercept, if there is one.</p> |
| <p><a class="anchor" id="predict"></a></p> |
| <dl class="section user"><dt>Prediction Functions</dt><dd><ul> |
| <li>To make predictions on a single data point x using a single model learned previously, we use the function <pre class="syntax"> |
| svm_predict( model_table, |
| x |
| ) |
| </pre></li> |
| <li>If the model is produced by the <a class="el" href="online__sv_8sql__in.html#a75d126981ae4bf2e6641627501f0a2a5" title="This is the linear support vector classification function. ">lsvm_classification()</a> function, use the following prediction function instead. <pre class="syntax"> |
| lsvm_predict( model_table, |
| x |
| ) |
| </pre></li> |
| <li>To make predictions on new data points using multiple models learned in parallel, use the following function: <pre class="syntax"> |
| svm_predict_combo( model_table, |
| x |
| ) |
| </pre></li> |
| <li>If the models are produced by the <a class="el" href="online__sv_8sql__in.html#a75d126981ae4bf2e6641627501f0a2a5" title="This is the linear support vector classification function. ">lsvm_classification()</a> function, use the following prediction function instead: <pre class="syntax"> |
| lsvm_predict_combo( model_table, |
| x) |
| </pre></li> |
| <li>Note that, at the moment, we cannot use madlib.svm_predict() and madlib.svm_predict_combo() on multiple data points. For example, something like the following will fail: <pre class="example"> |
| SELECT svm_predict( model_table, |
| x |
| ) |
| FROM data_table; |
| </pre> Instead, to make predictions on new data points stored in a table using previously learned models, we use the function: <pre class="syntax"> |
| svm_predict_batch( input_table, |
| data_col, |
| id_col, |
| model_table, |
| output_table, |
| parallel |
| ); |
| </pre> The output_table is created during the function call; an existing table with the same name will be dropped. If the <code>parallel</code> parameter is true, then each data point in the input table will have multiple predicted values corresponding to the number of models learned in parallel.</li> |
| <li>Similarly, use the following function for batch prediction if the model(s) is produced by the <a class="el" href="online__sv_8sql__in.html#a75d126981ae4bf2e6641627501f0a2a5" title="This is the linear support vector classification function. ">lsvm_classification()</a> function: <pre class="syntax"> |
| lsvm_predict_batch( input_table, |
| data_col, |
| id_col, |
| model_table, |
| output_table, |
| parallel |
| ); |
| </pre></li> |
| </ul> |
| </dd></dl> |
| <p><a class="anchor" id="notes"></a></p> |
| <dl class="section user"><dt>Notes</dt><dd></dd></dl> |
| <p>Currently, three kernel functions have been implemented: dot product (<a class="el" href="online__sv_8sql__in.html#acc2d778a8eb48ab775ff9c1dff4a3141">svm_dot</a>), polynomial (<a class="el" href="online__sv_8sql__in.html#a1ac76fdf9623e0a4db47665f2a80be90">svm_polynomial</a>) and Gaussian (<a class="el" href="online__sv_8sql__in.html#a9f2a96e1a241ecc66386a78b110777d3">svm_gaussian</a>) kernels. To use the dot product kernel function, simply use '<code><em>madlib.svm_dot</em></code>' as the <code>kernel_func</code> argument, which accepts any function that takes in two float[] and returns a float. To use the polynomial or Gaussian kernels, a wrapper function is needed since these kernels require additional input parameters (see <a class="el" href="online__sv_8sql__in.html" title="SQL functions for support vector machines. ">online_sv.sql_in</a> for input parameters).</p> |
| <p>For example, to use the polynomial kernel with degree 2, first create a wrapper function:</p> |
| <pre class="example"> |
| CREATE OR REPLACE FUNCTION mykernel(FLOAT[],FLOAT[]) |
| RETURNS FLOAT AS $$ |
| SELECT svm_polynomial($1,$2,2) |
| $$ language sql;</pre><p> Then call the SVM learning functions with <code>mykernel</code> as the argument to <code>kernel_func</code>. </p> |
| <pre class="example"> |
| SELECT svm_regression( 'my_schema.my_train_data', |
| 'mymodel', |
| false, |
| 'mykernel' |
| ); |
| </pre><p>To drop all tables pertaining to the model, use: </p> |
| <pre class="example"> |
| SELECT svm_drop_model( 'model_table' |
| ); |
| </pre><p><a class="anchor" id="examples"></a></p> |
| <dl class="section user"><dt>Examples</dt><dd></dd></dl> |
| <p>As a general first step, prepare and populate an input table/view with the following structure: </p> |
| <pre class="example"> |
| TABLE/VIEW my_schema.my_input_table |
| ( |
| id INT, -- point ID |
| ind FLOAT8[], -- data point |
| label FLOAT8 -- label of data point |
| ); |
| </pre><p> The label field is not required for novelty detection.</p> |
| <p><b>Example usage for regression</b>:</p> |
| <ol type="1"> |
| <li>Randomly generate 1000 5-dimensional data labelled using the simple target function. <pre class="example"> |
| t(x) = if x[5] = 10 then 50 else if x[5] = -10 then 50 else 0; |
| </pre> and store that in the my_schema.my_train_data table as follows: <pre class="example"> |
| SELECT madlib.svm_generate_reg_data( 'my_schema.my_train_data', |
| 1000, |
| 5 |
| ); |
| </pre></li> |
| <li>Learn a regression model and store the resultant model under the name 'myexp'. <pre class="example"> |
| SELECT madlib.svm_regression( 'my_schema.my_train_data', |
| 'myexp', |
| false, |
| 'madlib.svm_dot' |
| ); |
| </pre></li> |
| <li>Use the regression model to predict the labels of new data points. <pre class="example"> |
| SELECT madlib.svm_predict( 'myexp', |
| '{1,2,4,20,10}' |
| ); |
| SELECT madlib.svm_predict( 'myexp', |
| '{1,2,4,20,-10}' |
| ); |
| </pre></li> |
| <li>To learn multiple support vector models, we replace the learning step above by <pre class="example"> |
| SELECT madlib.svm_regression( 'my_schema.my_train_data', |
| 'myexp', |
| true, |
| 'madlib.svm_dot' |
| ); |
| </pre> The resultant models can be used for prediction as follows: <pre class="example"> |
| SELECT * FROM madlib.svm_predict_combo( 'myexp', |
| '{1,2,4,20,10}' |
| ); |
| </pre></li> |
| <li>We can also predict the labels of all the data points stored in a table. For example, we can execute the following: <pre class="example"> |
| CREATE TABLE madlib.svm_reg_test ( id int, ind float8[] ); |
| INSERT INTO madlib.svm_reg_test ( |
| SELECT id, ind FROM my_schema.my_train_data LIMIT 20); |
| SELECT madlib.svm_predict_batch( 'madlib.svm_reg_test', |
| 'ind', |
| 'id', |
| 'myexp', |
| 'madlib.svm_reg_output1', |
| false |
| ); |
| SELECT * FROM madlib.svm_reg_output1; |
| SELECT madlib.svm_predict_batch( 'madlib.svm_reg_test', |
| 'ind', |
| 'id, |
| 'myexp', |
| 'madlib.svm_reg_output2', |
| true |
| ); |
| SELECT * FROM madlib.svm_reg_output2; |
| </pre></li> |
| </ol> |
| <p><b>Example usage for classification:</b></p> |
| <ol type="1"> |
| <li>Randomly generate 2000 5-dimensional data labelled by the simple target function. <pre class="example"> |
| t(x) = if x[1] > 0 and x[2] < 0 then 1 else -1; |
| </pre> and store that in the my_schema.my_train_data table as follows: <pre class="example"> |
| SELECT madlib.svm_generate_cls_data( 'my_schema.my_train_data', |
| 2000, |
| 5 |
| ); |
| </pre></li> |
| <li>Learn a classification model and store the resultant model the table 'myexpc'. <pre class="example"> |
| SELECT madlib.svm_classification( 'my_schema.my_train_data', |
| 'myexpc', |
| false, |
| 'madlib.svm_dot' |
| ); |
| </pre></li> |
| <li>Start using the model to predict the labels of new data points. <pre class="example"> |
| SELECT madlib.svm_predict( 'myexpc', |
| '{10,-2,4,20,10}' |
| ); |
| </pre></li> |
| <li>To learn multiple support vector models, replace the model-building and prediction steps above. <pre class="example"> |
| SELECT madlib.svm_classification( 'my_schema.my_train_data', |
| 'myexpc', |
| true, |
| 'madlib.svm_dot' |
| ); |
| SELECT * FROM madlib.svm_predict_combo( 'myexpc', |
| '{10,-2,4,20,10}' |
| ); |
| </pre></li> |
| <li>To learn a linear support vector model using SGD, replace the model-building and prediction steps. <pre class="example"> |
| SELECT madlib.lsvm_classification( 'my_schema.my_train_data', |
| 'myexpc', |
| false |
| ); |
| SELECT madlib.lsvm_predict( 'myexpc', |
| '{10,-2,4,20,10}' |
| ); |
| </pre></li> |
| <li>To learn multiple linear support vector models using SGD, replace the model-building and prediction steps above. <pre class="example"> |
| SELECT madlib.lsvm_classification( 'my_schema.my_train_data', |
| 'myexpc', |
| true |
| ); |
| SELECT madlib.lsvm_predict_combo( 'myexpc', |
| '{10,-2,4,20,10}' |
| ); |
| </pre></li> |
| </ol> |
| <p><b>Example usage for novelty detection:</b></p> |
| <ol type="1"> |
| <li>Randomly generate 100 2-dimensional data (the normal cases) and store that in the my_schema.my_train_data table. <pre class="example"> |
| SELECT madlib.svm_generate_nd_data( 'my_schema.my_train_data', |
| 100, |
| 2 |
| ); |
| </pre></li> |
| <li>Learning and predicting using a single novelty detection model: <pre class="example"> |
| SELECT madlib.svm_novelty_detection( 'my_schema.my_train_data', |
| 'myexpnd', |
| false, |
| 'madlib.svm_dot' |
| ); |
| SELECT madlib.svm_predict( 'myexpnd', |
| '{10,-10}' |
| ); |
| SELECT madlib.svm_predict( 'myexpnd', |
| '{-1,-1}' |
| ); |
| </pre></li> |
| <li>Learning and predicting using multiple models can be done as follows: <pre class="example"> |
| SELECT madlib.svm_novelty_detection( 'my_schema.my_train_data', |
| 'myexpnd', |
| true, |
| 'madlib.svm_dot' |
| ); |
| SELECT * FROM madlib.svm_predict_combo( 'myexpnd', |
| '{-1,-1}' |
| ); |
| </pre></li> |
| </ol> |
| <p><a class="anchor" id="literature"></a></p> |
| <dl class="section user"><dt>Literature</dt><dd></dd></dl> |
| <p>[1] Jyrki Kivinen, Alexander J. Smola, and Robert C. Williamson: <em>Online Learning with Kernels</em>, IEEE Transactions on Signal Processing, 52(8), 2165-2176, 2004.</p> |
| <p>[2] Bernhard Scholkopf and Alexander J. Smola: <em>Learning with Kernels: Support Vector Machines, Regularization, Optimization, and Beyond</em>, MIT Press, 2002.</p> |
| <p>[3] Léon Bottou: <em>Large-Scale Machine Learning with Stochastic Gradient Descent</em>, Proceedings of the 19th International Conference on Computational Statistics, Springer, 2010.</p> |
| <p><a class="anchor" id="related"></a></p> |
| <dl class="section user"><dt>Related Topics</dt><dd></dd></dl> |
| <p>File <a class="el" href="online__sv_8sql__in.html" title="SQL functions for support vector machines. ">online_sv.sql_in</a> documenting the SQL functions. </p> |
| </div><!-- contents --> |
| </div><!-- doc-content --> |
| <!-- start footer part --> |
| <div id="nav-path" class="navpath"><!-- id is needed for treeview function! --> |
| <ul> |
| <li class="footer">Generated on Thu Jan 9 2014 20:27:18 for MADlib by |
| <a href="http://www.doxygen.org/index.html"> |
| <img class="footer" src="doxygen.png" alt="doxygen"/></a> 1.8.4 </li> |
| </ul> |
| </div> |
| </body> |
| </html> |