learn_fast_tree.cc

Go to the documentation of this file.
00001 /*
00002 
00003     This file is part of the FAST-ER machine learning system.
00004     Copyright (C) 2008  Edward Rosten and Los Alamos National Laboratory
00005 
00006     This program is free software; you can redistribute it and/or modify
00007     it under the terms of the GNU General Public License as published by
00008     the Free Software Foundation; either version 2 of the License, or
00009     (at your option) any later version.
00010 
00011     This program is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014     GNU General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License along
00017     with this program; if not, write to the Free Software Foundation, Inc.,
00018     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00019 */
00020 /**
00021     \file learn_fast_tree.cc Main file for the \p learn_fast_tree executable.  
00022 
00023     <tt> learn_fast_tree [--weight.</tt><i>x  weight</i><tt> ] ... < </tt> \e infile \p > \e outfile
00024     
00025     \p learn_fast_tree used ID3 to learn a ternary decision tree for corner
00026     detection. The data is read from the standard input, and the tree is written
00027     to the standard output. This is designed to learn FAST feature detectors,
00028     and does not allow for the possibility ambbiguity in the input data.
00029 
00030     \section lfInput Input data
00031 
00032     The input data has the following format:
00033 
00034 \verbatim
00035 
00036 5
00037 [-1 -1] [1 1] [3 4] [5 6] [-3 4]
00038 bbbbb 1     0
00039 bsdsb 1000  1
00040 .
00041 .
00042 .
00043 \endverbatim
00044     
00045     The first row is the number of features. The second row is the the list of
00046     offsets assosciated with each feature. This list has no effect on the
00047     learning of the tree, but it is passed through to the outpur for
00048     convinience.
00049 
00050     The remaining rows contain the data. The first field is the ternary feature
00051     vector. The three characters "b", "d" and "s" are the correspond to
00052     brighter, darker and similar respectively, with the first feature being
00053     stored in the first character and so on.
00054 
00055     The next field is the number of instances of the particular feature.
00056     The third field is the class, with 1 for corner, and 0 for background.
00057 
00058 
00059 
00060 \subsection f9Generate Generating input data
00061     
00062     Ideally, input data will be generated from some sample images. The 
00063     program FIXME can be used to do this.
00064 
00065     Additionally, a the program fast_N_features can be used to generate all 
00066     possible feature combinations for FAST-N features. When run without
00067     arguments, it generates data for FAST-9 features, otherwise the argument can
00068     be used to specify N.
00069 
00070 \section lfGen Output data
00071     
00072     The program does not generate source code directly, rather it generates an
00073     easily parsabel representation of a decision tree which can be turned in to
00074     source code.
00075 
00076     The structure of the tree is described in detail in ::print_tree.
00077     
00078 */
00079 
00080 ///\cond never
00081 #ifndef DOXYGEN_IGNORE
00082 #include <iostream>
00083 #include <sstream>
00084 #include <cstdlib>
00085 #include <list>
00086 #include <map>
00087 #include <vector>
00088 #include <cassert>
00089 #include <bitset>
00090 #include <algorithm>
00091 #include <string>
00092 #include <tr1/memory>
00093 
00094 #include <stdint.h>
00095 
00096 #include <tag/tuple.h>
00097 #include <tag/printf.h>
00098 #include <tag/stdpp.h>
00099 #include <tag/fn.h>
00100 
00101 #include <cvd/image_ref.h>
00102 
00103 #include <gvars3/instances.h>
00104 #endif
00105 
00106 using namespace std;
00107 using namespace tr1;
00108 using namespace tag;
00109 using namespace CVD;
00110 using namespace GVars3;
00111 ///\endcond 
00112 
00113 ///Representations of ternary digits.
00114 enum Ternary
00115 {
00116     Brighter='b',
00117     Darker  ='d',
00118     Similar ='s'
00119 };
00120 
00121 ///Print an error message and the exit
00122 ///@param E Error code
00123 ///@param S Format string
00124 ///@ingroup gUtility
00125 #define fatal(E, S, ...) vfatal((E), (S), (tag::Fmt,## __VA_ARGS__))
00126 ///Print an error message and the exit, using Tuple stype VARARGS
00127 ///@param err Error code
00128 ///@param s Format string
00129 ///@param list Argument list
00130 ///@ingroup gUtility
00131 template<class C> void vfatal(int err, const string& s, const C& list)
00132 {
00133     vfPrintf(cerr, s + "\n", list);
00134     exit(err);
00135 }
00136 
00137 /**This structure represents a datapoint. A datapoint is a group of pixels with
00138 ternary values (much brighter than the centre, much darker than the centre or
00139 similar to the centre pixel). In addition to the feature descriptor, the class
00140 and number of instances is also stored.
00141 
00142 The maximum feature vector size is determined by the template parameter. This
00143 allows the ternary vector to be stored in a bitset. This keeps the struct a
00144 fixed size and removes the need for dynamic allocation.
00145 */
00146 template<int FEATURE_SIZE> struct datapoint
00147 {
00148     ///Construct a datapoint 
00149     ///@param s The feature vector in string form 
00150     ///@param c The number of instances
00151     ///@param is The class
00152     datapoint(const string& s, unsigned long c, bool is)
00153     :count(c),is_a_corner(is)
00154     {
00155         pack_trits(s);
00156     }
00157     
00158     ///Default constructor allows for storage in a
00159     ///std::vector.
00160     datapoint()
00161     {}
00162 
00163     unsigned long count; ///< Number of instances
00164     bool is_a_corner;   ///< Class
00165 
00166     static const unsigned int max_size = FEATURE_SIZE; ///< Maximum number of features representable.
00167     
00168 
00169     ///Extract a trit (ternary bit) from the feture vector.
00170     ///@param tnum Number of the bit to extract
00171     ///@return  The trit.
00172     Ternary get_trit(unsigned int tnum) const
00173     {
00174         assert(tnum < size);
00175         if(tests[tnum] == 1)
00176             return Brighter;
00177         else if(tests[tnum + max_size] == 1)
00178             return Darker;
00179         else
00180             return Similar;
00181     }
00182 
00183     private:
00184 
00185         bitset<max_size*2> tests; ///<Used to store the ternary vector
00186                                   ///Ternary bits are stored using 3 out of the
00187                                   ///4 values storable by two bits.
00188                                   ///Trit \e n is stored using the bits \e n and
00189                                   ///\e n + \e max_size, with bit \e n being the
00190                                   ///most significant bit.
00191                                   ///
00192                                   ///The values are
00193                                   ///- 3 unused
00194                                   ///- 2 Brighter
00195                                   ///- 1 Darker
00196                                   ///- 0 Similar
00197 
00198         ///This code reads a stringified representation of the feature vector
00199         ///and converts it in to the internal representation. 
00200         ///The string represents one feature per character, using "b", "d" and
00201         ///"s".
00202         ///@param unpacked String to parse.
00203         void pack_trits(const string& unpacked)
00204         {
00205             tests = 0;
00206             for(unsigned int i=0;i < unpacked.size(); i++)
00207             {
00208                 if(unpacked[i] == 'b')
00209                     set_trit(i, Brighter);
00210                 else if(unpacked[i] == 'd')
00211                     set_trit(i, Darker);
00212                 else if(unpacked[i] == 's')
00213                     set_trit(i, Similar);
00214                 else
00215                     fatal(2, "Bad char while packing datapoint: %s", unpacked);
00216             }
00217         }
00218         
00219         ///Set a ternary digit.
00220         ///@param tnum Digit to set
00221         ///@param val Value to set it to.
00222         void set_trit(unsigned int tnum, Ternary val)
00223         {
00224             assert(val == Brighter || val == Darker || val == Similar);
00225             assert(tnum < max_size);
00226 
00227             if(val == Brighter)
00228                 tests[tnum] = 1;
00229             else if(val == Darker)
00230                 tests[tnum + max_size] = 1;
00231         }
00232 };
00233 
00234 /**
00235 This function loads as many datapoints from the standard input as 
00236 possible. Datapoints consist of a feature vector (a string containing the
00237 characters "b", "d" and "s"), a number of instances and a class.
00238 
00239 See datapoint::pack_trits for a more complete description of the feature vector.
00240 
00241 The tokens are whitespace separated.
00242 
00243 @param nfeats Number of features in a feature vector. Used to spot errors.
00244 @return Loaded datapoints and total number of instances.
00245 */
00246 template<int S> typename V_tuple<shared_ptr<vector<datapoint<S> > >, uint64_t >::type load_features(unsigned int nfeats)
00247 {
00248     shared_ptr<vector<datapoint<S> > > ret(new vector<datapoint<S> >);
00249 
00250 
00251     string unpacked_feature;
00252     
00253     uint64_t total_num = 0;
00254 
00255     uint64_t line_num=2;
00256 
00257     for(;;)
00258     {
00259         uint64_t count;
00260         bool is;
00261 
00262         cin >> unpacked_feature >> count >> is;
00263 
00264         if(!cin)
00265             break;
00266 
00267         line_num++;
00268 
00269         if(unpacked_feature.size() != nfeats)
00270             fatal(1, "Feature string length is %i, not %i on line %i", unpacked_feature.size(), nfeats, line_num);
00271 
00272         if(count == 0)
00273             fatal(4, "Zero count is invalid");
00274 
00275         ret->push_back(datapoint<S>(unpacked_feature, count, is));
00276 
00277         total_num += count;
00278     }
00279 
00280     cerr << "Num features: " << total_num << endl
00281          << "Num distinct: " << ret->size() << endl;
00282 
00283     return make_vtuple(ret, total_num);
00284 }
00285 
00286 
00287 ///Compute the entropy of a set with binary annotations.
00288 ///@param n Number of elements in the set
00289 ///@param c1 Number of elements in class 1
00290 ///@return The set entropy.
00291 double entropy(uint64_t n, uint64_t c1)
00292 {
00293     assert(c1 <= n);
00294     //n is total number, c1 in num in class 1
00295     if(n == 0)
00296         return 0;
00297     else if(c1 == 0 || c1 == n)
00298         return 0;
00299     else
00300     {
00301         double p1 = (double)c1 / n;
00302         double p2 = 1-p1;
00303 
00304         return -(double)n*(p1*log(p1) + p2*log(p2)) / log(2.f);
00305     }
00306 }
00307 
00308 ///Find the feature that has the highest weighted entropy change.
00309 ///@param fs datapoints to split in to three subsets.
00310 ///@param weights weights on features
00311 ///@param nfeats Number of features in use.
00312 ///@return best feature.
00313 template<int S> int find_best_split(const vector<datapoint<S> >& fs, const vector<double>& weights, unsigned int nfeats)
00314 {
00315     assert(nfeats == weights.size());
00316     uint64_t num_total = 0, num_corners=0;
00317 
00318     for(typename vector<datapoint<S> >::const_iterator i=fs.begin(); i != fs.end(); i++)
00319     {
00320         num_total += i->count;
00321         if(i->is_a_corner)
00322             num_corners += i->count;
00323     }
00324 
00325     double total_entropy = entropy(num_total, num_corners);
00326     
00327     double biggest_delta = 0;
00328     int   feature_num = -1;
00329 
00330     for(unsigned int i=0; i < nfeats; i++)
00331     {
00332         uint64_t num_bri = 0, num_dar = 0, num_sim = 0;
00333         uint64_t cor_bri = 0, cor_dar = 0, cor_sim = 0;
00334 
00335         for(typename vector<datapoint<S> >::const_iterator f=fs.begin(); f != fs.end(); f++)
00336         {
00337             switch(f->get_trit(i))
00338             {
00339                 case Brighter:
00340                     num_bri += f->count;
00341                     if(f->is_a_corner)
00342                         cor_bri += f->count;
00343                     break;
00344 
00345                 case Darker:
00346                     num_dar += f->count;
00347                     if(f->is_a_corner)
00348                         cor_dar += f->count;
00349                     break;
00350 
00351                 case Similar:
00352                     num_sim += f->count;
00353                     if(f->is_a_corner)
00354                         cor_sim += f->count;
00355                     break;
00356             }
00357         }
00358 
00359         double delta_e = total_entropy - (entropy(num_bri, cor_bri) + entropy(num_dar, cor_dar) + entropy(num_sim, cor_sim));
00360 
00361         delta_e *= weights[i];
00362 
00363         if(delta_e > biggest_delta)
00364         {       
00365             biggest_delta = delta_e;
00366             feature_num = i;
00367         }   
00368     }
00369 
00370     if(feature_num == -1)
00371         fatal(3, "Couldn't find a split.");
00372 
00373     return feature_num;
00374 }
00375 
00376 
00377 ////////////////////////////////////////////////////////////////////////////////
00378 //
00379 // Tree buliding
00380 //
00381 
00382 ///This class represents a decision tree.
00383 ///Each leaf node contains a class, being Corner or NonCorner.
00384 ///Each decision node contains a feature about which to make a ternary decision.
00385 ///Additionally, each node records how many datapoints were tested.
00386 ///The generated tree structure is not mutable.
00387 struct tree{
00388     ///The class of the leaf, and a sentinal to indacate that the node is
00389     ///not a leaf. Now that I come back to this, it looks suspiciously like
00390     ///an instance of http://thedailywtf.com/Articles/What_Is_Truth_0x3f_.aspx
00391     ///Oh well.
00392     enum IsCorner
00393     {
00394         Corner,
00395         NonCorner,
00396         NonTerminal
00397     };
00398 
00399     const shared_ptr<tree> brighter;                  ///<Subtrees
00400     const shared_ptr<tree> darker;                    ///<Subtrees
00401     const shared_ptr<tree> similar;                   ///<Subtrees
00402     const IsCorner is_a_corner;                       ///<Class of this node (if its a leaf)
00403     const int feature_to_test;                        ///<Feature (ie pixel) to test if this  is a non-leaf.
00404     const uint64_t num_datapoints;                    ///<Number of datapoints passing through this node.
00405 
00406     ///Convert the tree to a simple string representation.
00407     ///This is allows comparison of two trees to see if they are the same.
00408     ///It's probably rather inefficient to hammer the string class compared
00409     ///to using an ostringstream, but this is not the slowest part of the program.
00410     ///@return a stringified tree representation
00411     string stringify()
00412     {
00413         if(is_a_corner == NonTerminal)
00414             return "(" + brighter->stringify() + darker->stringify() + similar->stringify() + ")";
00415         else
00416             return string("(") + (is_a_corner == Corner?"1":"0")  +  ")";
00417     }
00418 
00419     ///Create a leaf node which is a corner
00420     ///This special constructor function makes it impossible to 
00421     ///construct a leaf with the NonTerminal class.
00422     ///@param n number of datapoints reaching this node.
00423     static shared_ptr<tree> CornerLeaf(uint64_t n)
00424     {
00425         return shared_ptr<tree>(new tree(Corner, n));
00426     }
00427     
00428     ///Creat a leaf node which is a non-corner
00429     ///This special constructor function makes it impossible to 
00430     ///construct a leaf with the NonTerminal class.
00431     ///@param n number of datapoints reaching this node.
00432     static shared_ptr<tree> NonCornerLeaf(uint64_t n)
00433     {
00434         return shared_ptr<tree>(new tree(NonCorner, n));
00435     }
00436     
00437     ///Create a non-leaf node
00438     ///@param b The brighter subtree
00439     ///@param d The darker subtree
00440     ///@param s The similar subtree
00441     ///@param n Feature number to test
00442     ///@param num Number of datapoints reaching this node.
00443     tree(shared_ptr<tree> b, shared_ptr<tree> d, shared_ptr<tree> s, int n, uint64_t num)
00444     :brighter(b), darker(d), similar(s), is_a_corner(NonTerminal), feature_to_test(n), num_datapoints(num)
00445     {}
00446 
00447     private:
00448     ///The leaf node constructor is private to prevent a tree
00449     ///being constructed with invalid values.
00450     ///see also CornerLeaf and NonCornerLeaf.
00451     ///@param c Class of the node
00452     ///@param n Number of datapoints which this node represents
00453     tree(IsCorner c, uint64_t n)
00454     :is_a_corner(c),feature_to_test(-1),num_datapoints(n)
00455     {}
00456 };
00457 
00458 
00459 ///This function uses ID3 to construct a decision tree. The entropy changes
00460 ///are weighted by the list of weights, to allow bias towards certain features.
00461 ///This function assumes that the class is an exact function of the data. If 
00462 ///there datapoints with different classes share the same feature vector, the program
00463 ///will crash with error code 3.
00464 ///@param corners Datapoints in this part of the subtree to classify
00465 ///@param weights Weights on the features
00466 ///@param nfeats Number of features actually used
00467 ///@return The tree required to classify corners
00468 template<int S> shared_ptr<tree> build_tree(vector<datapoint<S> >& corners, const vector<double>& weights, int nfeats)
00469 {
00470     //Find the split
00471     int f = find_best_split<S>(corners, weights, nfeats);
00472 
00473     //Split corners in to the three chunks, based on the result of find_best_split.
00474     //Also, count how many of each class ends up in each of the three bins.
00475     //It may apper to be inefficient to use a vector here instead of a list, in terms
00476     //of memory, but the per-element storage overhead of the list is such that it uses
00477     //considerably more memory and is much slower.
00478     vector<datapoint<S> > brighter, darker, similar;
00479     uint64_t num_bri=0, cor_bri=0, num_dar=0, cor_dar=0, num_sim=0, cor_sim=0;
00480 
00481     for(size_t i=0; i < corners.size(); i++)
00482     {
00483         switch(corners[i].get_trit(f))
00484         {
00485             case Brighter:
00486                 brighter.push_back(corners[i]);
00487                 num_bri += corners[i].count;
00488                 if(corners[i].is_a_corner)
00489                     cor_bri += corners[i].count;
00490                 break;
00491 
00492             case Darker:
00493                 darker.push_back(corners[i]);
00494                 num_dar += corners[i].count;
00495                 if(corners[i].is_a_corner)
00496                     cor_dar += corners[i].count;
00497                 break;
00498 
00499             case Similar:
00500                 similar.push_back(corners[i]);
00501                 num_sim += corners[i].count;
00502                 if(corners[i].is_a_corner)
00503                     cor_sim += corners[i].count;
00504                 break;
00505         }
00506     }
00507     
00508     //Deallocate the memory now it's no longer needed.
00509     corners.clear();
00510     
00511     //This is not the same as corners.size(), since the corners (datapoints)
00512     //have a count assosciated with them.
00513     uint64_t num_tests =  num_bri + num_dar + num_sim;
00514 
00515     
00516     //Build the subtrees
00517     shared_ptr<tree> b_tree, d_tree, s_tree;
00518 
00519     
00520     //If the sublist contains a single class, then instantiate a leaf,
00521     //otherwise recursively build the tree.
00522     if(cor_bri == 0)
00523         b_tree = tree::NonCornerLeaf(num_bri);
00524     else if(cor_bri == num_bri)
00525         b_tree = tree::CornerLeaf(num_bri);
00526     else
00527         b_tree = build_tree<S>(brighter, weights, nfeats);
00528     
00529 
00530     if(cor_dar == 0)
00531         d_tree = tree::NonCornerLeaf(num_dar);
00532     else if(cor_dar == num_dar)
00533         d_tree = tree::CornerLeaf(num_dar);
00534     else
00535         d_tree = build_tree<S>(darker, weights, nfeats);
00536 
00537 
00538     if(cor_sim == 0)
00539         s_tree = tree::NonCornerLeaf(num_sim);
00540     else if(cor_sim == num_sim)
00541         s_tree = tree::CornerLeaf(num_sim);
00542     else
00543         s_tree = build_tree<S>(similar, weights, nfeats);
00544     
00545     return shared_ptr<tree>(new tree(b_tree, d_tree, s_tree, f, num_tests));
00546 }
00547 
00548 
00549 /**This function traverses the tree and produces a textual representation of it.
00550 Additionally, if any of the subtrees are the same, then a single subtree is produced
00551 and the test is removed.
00552 
00553 A subtree has the following format:
00554 \verbatim 
00555     subtree= lead | node;
00556     
00557     leaf = "corner" | "background" ;
00558 
00559     node = node2 | node3;
00560 
00561     node3 = "if_brighter" feature_number n1 n2 n3
00562                 subtree
00563             "elsf_darker" feature_number
00564                 subtree
00565             "else"
00566                 subtree
00567             "end";
00568 
00569      node2= if_statement feature_number n1 n2
00570                 subtree
00571             "else"
00572                 subtree
00573             "end";
00574 
00575     if_statement = "if_brighter" | "if_darker" | "if_either";
00576     feature_number ==integer;
00577     n1 = integer;
00578     n2 = integer;
00579     n3 = integer;
00580 \endverbatim
00581 
00582 \e feature_number refers to the index of the feature that the test is performed on.
00583 
00584 In \e node3, a 3 way test is performed. \e n1, \e n2 and \e n3 refer to the
00585 number of training examples landing in the \e if block, the \e elfs block and
00586 the \e else block respectivly.
00587 
00588 In a \e node2 node, one of the tests has been removed. \e n1 and  \e n2refer to
00589 the number of training examples landing in the \e if block and the \e else
00590 block respectivly.
00591 
00592 Although not mentioned in the grammar, the indenting is kept very strict.
00593 
00594 This representation has been designed to be parsed very easily with simple
00595 regular expressions, hence the use if "elsf" as opposed to "elif" or "elseif".
00596 
00597 @param node (sub)tree to serialize
00598 @param o Stream to serialize to.
00599 @param i Indent to print before each line of the serialized tree.
00600 */
00601 void print_tree(const tree* node, ostream& o, const string& i="")
00602 {
00603     if(node->is_a_corner == tree::Corner)
00604         o << i << "corner" << endl;
00605     else if(node->is_a_corner == tree::NonCorner)
00606         o << i << "background" << endl;
00607     else
00608     {
00609         string b = node->brighter->stringify();
00610         string d = node->darker->stringify();
00611         string s = node->similar->stringify();
00612 
00613         const tree * bt = node->brighter.get();
00614         const tree * dt = node->darker.get();
00615         const tree * st = node->similar.get();
00616         string ii = i + " ";
00617 
00618         int f = node->feature_to_test;
00619     
00620         if(b == d && d == s) //All the same
00621         {
00622             //o << i << "if " << f << " is whatever\n";
00623             print_tree(st, o, i);
00624         }
00625         else if(d == s)  //Bright is different
00626         {
00627             o << i << "if_brighter " << f << " " << bt->num_datapoints << " " << dt->num_datapoints+st->num_datapoints << endl;
00628                 print_tree(bt, o, ii);
00629             o << i << "else" << endl;
00630                 print_tree(st, o, ii);
00631             o << i << "end" << endl;
00632 
00633         }
00634         else if(b == s) //Dark is different
00635         {   
00636             o << i << "if_darker " << f << " " << dt->num_datapoints << " " << bt->num_datapoints + st->num_datapoints << endl;
00637                 print_tree(dt, o, ii);
00638             o << i << "else" << endl;
00639                 print_tree(st, o, ii);
00640             o << i << "end" << endl;
00641         }
00642         else if(b == d) //Similar is different
00643         {
00644             o << i << "if_either " << f << " " <<  bt->num_datapoints + dt->num_datapoints  << " " << st->num_datapoints << endl;
00645                 print_tree(bt, o, ii);
00646             o << i << "else" << endl;
00647                 print_tree(st, o, ii);
00648             o << i << "end" << endl;
00649         }
00650         else //All different
00651         {
00652             o << i << "if_brighter " << f << " "  <<  bt->num_datapoints << " " << dt->num_datapoints  << " " << st->num_datapoints << endl;
00653                 print_tree(bt, o, ii);
00654             o << i << "elsf_darker " << f << endl;
00655                 print_tree(dt, o, ii);
00656             o << i << "else" << endl;
00657                 print_tree(st, o, ii);
00658             o << i << "end" << endl;
00659         }
00660     }
00661 }
00662 
00663 ///This function loads data and builds a tree. It is templated because datapoint
00664 ///is templated, for reasons of memory efficiency.
00665 ///@param num_features Number of features used
00666 ///@param weights Weights on each feature. 
00667 ///@return The learned tree, and number of datapoints.
00668 template<int S> V_tuple<shared_ptr<tree>, uint64_t>::type load_and_build_tree(unsigned int num_features, const vector<double>& weights)
00669 {
00670     assert(weights.size() == num_features);
00671 
00672     shared_ptr<vector<datapoint<S> > > l;
00673     uint64_t num_datapoints;
00674     
00675     //Load the data
00676     make_rtuple(l, num_datapoints) = load_features<S>(num_features);
00677     
00678     cerr << "Loaded.\n";
00679     
00680     //Build the tree
00681     shared_ptr<tree> tree;
00682     tree  = build_tree<S>(*l, weights, num_features);
00683 
00684     return make_vtuple(tree, num_datapoints);
00685 }
00686 
00687 
00688 
00689 ///The main program
00690 ///@param argc Number of commandline arguments
00691 ///@param argv Commandline arguments
00692 int main(int argc, char** argv)
00693 {
00694     //Set up default arguments
00695     GUI.parseArguments(argc, argv);
00696 
00697     cin.sync_with_stdio(false);
00698     cout.sync_with_stdio(false);
00699 
00700     
00701     ///////////////////
00702     //read file
00703     
00704     //Read number of features
00705     unsigned int num_features;
00706     cin >> num_features;
00707     if(!cin.good() || cin.eof())
00708         fatal(6, "Error reading number of features.");
00709 
00710     //Read offset list
00711     vector<ImageRef> offsets(num_features);
00712     for(unsigned int i=0; i < num_features; i++)
00713         cin >> offsets[i];
00714     if(!cin.good() || cin.eof())
00715         fatal(7, "Error reading offset list.");
00716 
00717     //Read weights for the various offsets
00718     vector<double> weights(offsets.size());
00719     for(unsigned int i=0; i < weights.size(); i++)
00720         weights[i] = GV3::get<double>(sPrintf("weights.%i", i), 1, 1);
00721 
00722 
00723     shared_ptr<tree> tree;
00724     uint64_t num_datapoints;
00725 
00726     ///Each feature takes up 2 bits. Since GCC doesn't pack any finer
00727     ///then 32 bits for hetrogenous structs, there is no point in having
00728     ///granularity finer than 16 features.
00729     if(num_features <= 16)
00730         make_rtuple(tree, num_datapoints) = load_and_build_tree<16>(num_features, weights);
00731     else if(num_features <= 32)
00732         make_rtuple(tree, num_datapoints) = load_and_build_tree<32>(num_features, weights);
00733     else if(num_features <= 48)
00734         make_rtuple(tree, num_datapoints) = load_and_build_tree<48>(num_features, weights);
00735     else if(num_features <= 64)
00736         make_rtuple(tree, num_datapoints) = load_and_build_tree<64>(num_features, weights);
00737     else
00738         fatal(8, "Too many feratures (%i). To learn from this, see %s, line %i.", num_features, __FILE__, __LINE__);
00739 
00740     
00741     cout << num_features << endl;
00742     copy(offsets.begin(), offsets.end(), ostream_iterator<ImageRef>(cout, " "));
00743     cout << endl;
00744     print_tree(tree.get(), cout);
00745 }

Generated on Mon Mar 2 12:47:12 2009 for FAST-ER by  doxygen 1.5.3