ParameterCombination.cpp

Go to the documentation of this file.
00001 /*
00002  * This program is free software; you can redistribute it and/or modify
00003  * it under the terms of the GNU General Public License as published by
00004  * the Free Software Foundation; either version 3 of the License, or
00005  * (at your option) any later version.
00006  *
00007  * Written (W) 2011-2012 Heiko Strathmann
00008  * Written (W) 2012 Jacob Walker
00009  *
00010  * Copyright (C) 2011 Berlin Institute of Technology and Max-Planck-Society
00011  */
00012 
00013 #include <shogun/modelselection/ParameterCombination.h>
00014 #include <shogun/base/Parameter.h>
00015 #include <shogun/machine/Machine.h>
00016 #include <set>
00017 #include <string>
00018 
00019 using namespace shogun;
00020 using namespace std;
00021 
00022 CParameterCombination::CParameterCombination()
00023 {
00024     init();
00025 }
00026 
00027 CParameterCombination::CParameterCombination(Parameter* param)
00028 {
00029     init();
00030 
00031     m_param=param;
00032 }
00033 
00034 void CParameterCombination::init()
00035 {
00036     m_param=NULL;
00037     m_child_nodes=new CDynamicObjectArray();
00038     SG_REF(m_child_nodes);
00039 
00040     SG_ADD((CSGObject**)&m_child_nodes, "child_nodes",
00041             "children of this node", MS_NOT_AVAILABLE);
00042 }
00043 
00044 CParameterCombination::~CParameterCombination()
00045 {
00046     delete m_param;
00047     SG_UNREF(m_child_nodes);
00048 }
00049 
00050 void CParameterCombination::append_child(CParameterCombination* child)
00051 {
00052     m_child_nodes->append_element(child);
00053 }
00054 
00055 
00056 
00057 bool CParameterCombination::set_parameter_helper(
00058         const char* name, bool value, index_t index)
00059 {
00060     if (m_param)
00061     {
00062         for (index_t i = 0; i < m_param->get_num_parameters(); ++i)
00063         {
00064             void* param = m_param->get_parameter(i)->m_parameter;
00065 
00066             if (!strcmp(m_param->get_parameter(i)->m_name, name))
00067             {
00068                 if (m_param->get_parameter(i)->m_datatype.m_ptype
00069                         != PT_BOOL)
00070                     SG_ERROR("Parameter %s not a boolean parameter", name);
00071 
00072                 if (index < 0)
00073                     *((bool*)(param)) = value;
00074 
00075                 else
00076                     (*((bool**)(param)))[index] = value;
00077 
00078                 return true;
00079             }
00080         }
00081 
00082     }
00083 
00084     return false;
00085 }
00086 
00087 bool CParameterCombination::set_parameter_helper(
00088         const char* name, int32_t value, index_t index)
00089 {
00090     if (m_param)
00091     {
00092         for (index_t i = 0; i < m_param->get_num_parameters(); ++i)
00093         {
00094             void* param = m_param->get_parameter(i)->m_parameter;
00095 
00096             if (!strcmp(m_param->get_parameter(i)->m_name, name))
00097             {
00098                 if (m_param->get_parameter(i)->m_datatype.m_ptype
00099                         != PT_INT32)
00100                     SG_ERROR("Parameter %s not a integer parameter", name);
00101 
00102                 if (index < 0)
00103                     *((int32_t*)(param)) = value;
00104 
00105                 else
00106                     (*((int32_t**)(param)))[index] = value;
00107 
00108                 return true;
00109             }
00110         }
00111     }
00112 
00113     return false;
00114 }
00115 
00116 bool CParameterCombination::set_parameter_helper(
00117         const char* name, float64_t value, index_t index)
00118 {
00119     if (m_param)
00120     {
00121         for (index_t i = 0; i < m_param->get_num_parameters(); ++i)
00122         {
00123             void* param = m_param->get_parameter(i)->m_parameter;
00124 
00125             if (!strcmp(m_param->get_parameter(i)->m_name, name))
00126             {
00127                 if (m_param->get_parameter(i)->m_datatype.m_ptype
00128                         != PT_FLOAT64)
00129                     SG_ERROR("Parameter %s not a double parameter", name);
00130 
00131                 if (index < 0)
00132                     *((float64_t*)(param)) = value;
00133 
00134                 else
00135                     (*((float64_t**)(param)))[index] = value;
00136 
00137                 return true;
00138             }
00139         }
00140 
00141     }
00142 
00143     return false;
00144 }
00145 
00146 
00147 TParameter* CParameterCombination::get_parameter_helper(const char* name)
00148 {
00149     if (m_param)
00150     {
00151         for (index_t i = 0; i < m_param->get_num_parameters(); i++)
00152         {
00153             if (!strcmp(m_param->get_parameter(i)->m_name, name))
00154                     return m_param->get_parameter(i);
00155         }
00156 
00157     }
00158 
00159     return NULL;
00160 }
00161 
00162 
00163 TParameter* CParameterCombination::get_parameter(const char* name,
00164         CSGObject* parent)
00165 {
00166     bool match = false;
00167 
00168     if (m_param)
00169     {
00170         for (index_t i = 0; i < m_param->get_num_parameters(); i++)
00171         {
00172             if (m_param->get_parameter(i)->m_datatype.m_ptype==PT_SGOBJECT)
00173             {
00174                 CSGObject* obj =
00175                         (*((CSGObject**)m_param->get_parameter(i)->m_parameter));
00176                 if (parent == obj)
00177                     match = true;
00178             }
00179         }
00180 
00181     }
00182 
00183     for (index_t i = 0; i < m_child_nodes->get_num_elements(); ++i)
00184     {
00185         CParameterCombination* child = (CParameterCombination*)
00186                 m_child_nodes->get_element(i);
00187 
00188         TParameter* p;
00189 
00190         if (!match)
00191              p = child->get_parameter(name, parent);
00192 
00193         else
00194              p = child->get_parameter_helper(name);
00195 
00196         if (p)
00197         {
00198             SG_UNREF(child);
00199             return p;
00200         }
00201 
00202         SG_UNREF(child);
00203     }
00204 
00205     return NULL;
00206 }
00207 
00208 
00209 void CParameterCombination::merge_with(CParameterCombination* node)
00210 {
00211     for (index_t i=0; i<node->m_child_nodes->get_num_elements(); ++i)
00212     {
00213         CParameterCombination* child=
00214                 (CParameterCombination*)node->m_child_nodes->get_element(i);
00215         append_child(child->copy_tree());
00216         SG_UNREF(child);
00217     }
00218 }
00219 
00220 void CParameterCombination::print_tree(int prefix_num) const
00221 {
00222     /* prefix is enlarged */
00223     char* prefix=SG_MALLOC(char, prefix_num+1);
00224     for (index_t i=0; i<prefix_num; ++i)
00225         prefix[i]='\t';
00226 
00227     prefix[prefix_num]='\0';
00228 
00229     /* cases:
00230      * -node with a Parameter instance and a possible children
00231      * -root node with children
00232      */
00233 
00234     if (m_param)
00235     {
00236         SG_SPRINT("%s", prefix);
00237         for (index_t i=0; i<m_param->get_num_parameters(); ++i)
00238         {
00239             /* distinction between sgobject and values */
00240             if (m_param->get_parameter(i)->m_datatype.m_ptype==PT_SGOBJECT)
00241             {
00242                 TParameter* param=m_param->get_parameter(i);
00243                 CSGObject* current_sgobject=*((CSGObject**) param->m_parameter);
00244                 SG_SPRINT("\"%s\":%s at %p ", param->m_name,
00245                         current_sgobject->get_name(), current_sgobject);
00246             }
00247 
00248             else if (m_param->get_parameter(i)->m_datatype.m_ctype == CT_SGVECTOR)
00249             {
00250                 SG_SPRINT("\"%s\"=", m_param->get_parameter(i)->m_name);
00251                 float64_t** param = (float64_t**)(m_param->
00252                         get_parameter(i)->m_parameter);
00253                 if (!m_param->get_parameter(i)->m_datatype.m_length_y)
00254                 {
00255                     SG_ERROR("Parameter vector %s has no length\n",
00256                             m_param->get_parameter(i)->m_name);
00257                 }
00258 
00259                 index_t length = *(m_param->get_parameter(i)->m_datatype.m_length_y);
00260 
00261                 for (index_t j = 0; j < length; j++)
00262                     SG_SPRINT("%f ", (*param)[j]);
00263             }
00264 
00265             else
00266             {
00267                 SG_SPRINT("\"%s\"=", m_param->get_parameter(i)->m_name);
00268                 void* param=m_param->get_parameter(i)->m_parameter;
00269 
00270                 if (m_param->get_parameter(i)->m_datatype.m_ptype==PT_FLOAT64)
00271                     SG_SPRINT("%f ", *((float64_t*)param));
00272                 else if (m_param->get_parameter(i)->m_datatype.m_ptype==PT_INT32)
00273                     SG_SPRINT("%i ", *((int32_t*)param));
00274                 else if (m_param->get_parameter(i)->m_datatype.m_ptype==PT_BOOL)
00275                     SG_SPRINT("%s ", *((bool*)param ? "true" : "false"));
00276                 else
00277                     SG_NOTIMPLEMENTED;
00278             }
00279 
00280         }
00281 
00282     }
00283     else
00284         SG_SPRINT("%sroot", prefix);
00285 
00286     SG_SPRINT("\n");
00287 
00288     for (index_t i=0; i<m_child_nodes->get_num_elements(); ++i)
00289     {
00290         CParameterCombination* child=(CParameterCombination*)
00291                 m_child_nodes->get_element(i);
00292         child->print_tree(prefix_num+1);
00293         SG_UNREF(child);
00294     }
00295 
00296     SG_FREE(prefix);
00297 }
00298 
00299 DynArray<Parameter*>* CParameterCombination::parameter_set_multiplication(
00300         const DynArray<Parameter*>& set_1, const DynArray<Parameter*>& set_2)
00301 {
00302     SG_SDEBUG("entering CParameterCombination::parameter_set_multiplication()\n");
00303 
00304     SG_SDEBUG("set 1:\n");
00305     for (index_t i=0; i<set_1.get_num_elements(); ++i)
00306     {
00307         for (index_t j=0; j<set_1.get_element(i)->get_num_parameters(); ++j)
00308             SG_SDEBUG("\t%s\n", set_1.get_element(i)->get_parameter(j)->m_name);
00309     }
00310 
00311     SG_SDEBUG("set 2:\n");
00312     for (index_t i=0; i<set_2.get_num_elements(); ++i)
00313     {
00314         for (index_t j=0; j<set_2.get_element(i)->get_num_parameters(); ++j)
00315             SG_SDEBUG("\t%s\n", set_2.get_element(i)->get_parameter(j)->m_name);
00316     }
00317 
00318     DynArray<Parameter*>* result=new DynArray<Parameter*>();
00319 
00320     for (index_t i=0; i<set_1.get_num_elements(); ++i)
00321     {
00322         for (index_t j=0; j<set_2.get_num_elements(); ++j)
00323         {
00324             Parameter* p=new Parameter();
00325             p->add_parameters(set_1[i]);
00326             p->add_parameters(set_2[j]);
00327             result->append_element(p);
00328         }
00329     }
00330 
00331     SG_SDEBUG("leaving CParameterCombination::parameter_set_multiplication()\n");
00332     return result;
00333 }
00334 
00335 CDynamicObjectArray* CParameterCombination::leaf_sets_multiplication(
00336         const CDynamicObjectArray& sets, const CParameterCombination* new_root)
00337 {
00338     CDynamicObjectArray* result=new CDynamicObjectArray();
00339 
00340     /* check marginal cases */
00341     if (sets.get_num_elements()==1)
00342     {
00343         CDynamicObjectArray* current_set=
00344                 (CDynamicObjectArray*)sets.get_element(0);
00345 
00346         /* just use the only element into result array.
00347          * put root node before all combinations*/
00348         *result=*current_set;
00349 
00350         SG_UNREF(current_set);
00351 
00352         for (index_t i=0; i<result->get_num_elements(); ++i)
00353         {
00354             /* put new root as root into the tree and replace tree */
00355             CParameterCombination* current=(CParameterCombination*)
00356                     result->get_element(i);
00357             CParameterCombination* root=new_root->copy_tree();
00358             root->append_child(current);
00359             result->set_element(root, i);
00360             SG_UNREF(current);
00361         }
00362     }
00363     else if (sets.get_num_elements()>1)
00364     {
00365         /* now the case where at least two sets are given */
00366 
00367         /* first, extract Parameter instances of given sets */
00368         DynArray<DynArray<Parameter*>*> param_sets;
00369 
00370         for (index_t set_nr=0; set_nr<sets.get_num_elements(); ++set_nr)
00371         {
00372             CDynamicObjectArray* current_set=(CDynamicObjectArray*)
00373                     sets.get_element(set_nr);
00374             DynArray<Parameter*>* new_param_set=new DynArray<Parameter*> ();
00375             param_sets.append_element(new_param_set);
00376 
00377             for (index_t i=0; i<current_set->get_num_elements(); ++i)
00378             {
00379                 CParameterCombination* current_node=(CParameterCombination*)
00380                         current_set->get_element(i);
00381 
00382                 if (current_node->m_child_nodes->get_num_elements())
00383                 {
00384                     SG_SERROR("leaf sets multiplication only possible if all "
00385                             "trees are leafs");
00386                 }
00387 
00388                 Parameter* current_param=current_node->m_param;
00389 
00390                 if (current_param)
00391                     new_param_set->append_element(current_param);
00392                 else
00393                 {
00394                     SG_SERROR("leaf sets multiplication only possible if all "
00395                             "leafs have non-NULL Parameter instances\n");
00396                 }
00397 
00398                 SG_UNREF(current_node);
00399             }
00400 
00401             SG_UNREF(current_set);
00402         }
00403 
00404         /* second, build products of all parameter sets */
00405         DynArray<Parameter*>* param_product=parameter_set_multiplication(
00406                 *param_sets[0], *param_sets[1]);
00407 
00408         delete param_sets[0];
00409         delete param_sets[1];
00410 
00411         /* build product of all remaining sets and collect results. delete all
00412          * parameter instances of interim products*/
00413         for (index_t i=2; i<param_sets.get_num_elements(); ++i)
00414         {
00415             DynArray<Parameter*>* old_temp_result=param_product;
00416             param_product=parameter_set_multiplication(*param_product,
00417                     *param_sets[i]);
00418 
00419             /* delete interim result parameter instances */
00420             for (index_t j=0; j<old_temp_result->get_num_elements(); ++j)
00421                 delete old_temp_result->get_element(j);
00422 
00423             /* and dyn arrays of interim result and of param_sets */
00424             delete old_temp_result;
00425             delete param_sets[i];
00426         }
00427 
00428         /* at this point there is only one DynArray instance remaining:
00429          * param_product. contains all combinations of parameters of all given
00430          * sets */
00431 
00432         /* third, build tree sets with the given root and the parameter product
00433          * elements */
00434         for (index_t i=0; i<param_product->get_num_elements(); ++i)
00435         {
00436             /* build parameter node from parameter product to append to root */
00437             CParameterCombination* param_node=new CParameterCombination(
00438                     param_product->get_element(i));
00439 
00440             /* copy new root node, has to be a new one each time */
00441             CParameterCombination* root=new_root->copy_tree();
00442 
00443             /* append both and add them to result set */
00444             root->append_child(param_node);
00445             result->append_element(root);
00446         }
00447 
00448         /* this is not needed anymore, because the Parameter instances are now
00449          * in the resulting tree sets */
00450         delete param_product;
00451     }
00452 
00453     return result;
00454 }
00455 
00456 CDynamicObjectArray* CParameterCombination::non_value_tree_multiplication(
00457                 const CDynamicObjectArray* sets,
00458                 const CParameterCombination* new_root)
00459 {
00460     SG_SDEBUG("entering CParameterCombination::non_value_tree_multiplication()\n");
00461     CDynamicObjectArray* result=new CDynamicObjectArray();
00462 
00463     /* first step: get all names in the sets */
00464     set<string> names;
00465 
00466     for (index_t j=0;
00467             j<sets->get_num_elements(); ++j)
00468     {
00469         CDynamicObjectArray* current_set=
00470                 (CDynamicObjectArray*)
00471                 sets->get_element(j);
00472 
00473         for (index_t k=0; k
00474                 <current_set->get_num_elements(); ++k)
00475         {
00476             CParameterCombination* current_tree=(CParameterCombination*)
00477                     current_set->get_element(k);
00478 
00479             names.insert(string(current_tree->m_param->get_parameter(0)->m_name));
00480 
00481             SG_UNREF(current_tree);
00482         }
00483 
00484         SG_UNREF(current_set);
00485     }
00486 
00487     SG_SDEBUG("all names\n");
00488     for (set<string>::iterator it=names.begin(); it!=names.end(); ++it)
00489         SG_SDEBUG("\"%s\"\n", (*it).c_str());
00490 
00491     /* only do stuff if there are names */
00492     if (!names.empty())
00493     {
00494         /* next step, build temporary structure where all elements with first
00495          * name are put. Elements of that structure will be extend iteratively
00496          * per name */
00497 
00498 
00499         /* extract all trees with first name */
00500         const char* first_name=(*(names.begin())).c_str();
00501         CDynamicObjectArray* trees=
00502                 CParameterCombination::extract_trees_with_name(sets, first_name);
00503 
00504         SG_SDEBUG("adding trees for first name \"%s\":\n", first_name);
00505         for (index_t i=0; i<trees->get_num_elements(); ++i)
00506         {
00507             CParameterCombination* current_tree=
00508                     (CParameterCombination*)trees->get_element(i);
00509 
00510             CParameterCombination* current_root=new_root->copy_tree();
00511             current_root->append_child(current_tree);
00512             result->append_element(current_root);
00513 
00514 //          current_tree->print_tree(1);
00515             SG_UNREF(current_tree);
00516         }
00517         SG_UNREF(trees);
00518 
00519         /* now iterate over the remaining names and build products */
00520         SG_SDEBUG("building products with remaining trees:\n");
00521         set<string>::iterator it=names.begin();
00522         for (++it; it!=names.end(); ++it)
00523         {
00524             SG_SDEBUG("processing \"%s\"\n", (*it).c_str());
00525 
00526             /* extract all trees with current name */
00527             const char* current_name=(*it).c_str();
00528             trees=CParameterCombination::extract_trees_with_name(sets,
00529                     current_name);
00530 
00531             /* create new set of trees where each element is put once for each
00532              * of the just generated trees */
00533             CDynamicObjectArray* new_result=new CDynamicObjectArray();
00534             for (index_t i=0; i<result->get_num_elements(); ++i)
00535             {
00536                 for (index_t j=0; j<trees->get_num_elements(); ++j)
00537                 {
00538                     CParameterCombination* to_copy=
00539                             (CParameterCombination*)result->get_element(i);
00540 
00541                     /* create a copy of current element */
00542                     CParameterCombination* new_element=to_copy->copy_tree();
00543                     SG_UNREF(to_copy);
00544 
00545                     CParameterCombination* to_add=
00546                             (CParameterCombination*)trees->get_element(j);
00547                     new_element->append_child(to_add);
00548                     SG_UNREF(to_add);
00549                     new_result->append_element(new_element);
00550 //                  SG_SDEBUG("added:\n");
00551 //                  new_element->print_tree();
00552                 }
00553             }
00554 
00555             /* clean up */
00556             SG_UNREF(trees);
00557 
00558             /* replace result by new_result */
00559             SG_UNREF(result);
00560             result=new_result;
00561         }
00562     }
00563 
00564     SG_SDEBUG("leaving CParameterCombination::non_value_tree_multiplication()\n");
00565     return result;
00566 }
00567 
00568 CDynamicObjectArray* CParameterCombination::extract_trees_with_name(
00569         const CDynamicObjectArray* sets, const char* desired_name)
00570 {
00571     CDynamicObjectArray* result=new CDynamicObjectArray();
00572 
00573     for (index_t j=0;
00574             j<sets->get_num_elements(); ++j)
00575     {
00576         CDynamicObjectArray* current_set=
00577                 (CDynamicObjectArray*) sets->get_element(j);
00578 
00579         for (index_t k=0; k<current_set->get_num_elements(); ++k)
00580         {
00581             CParameterCombination* current_tree=(CParameterCombination*)
00582                     current_set->get_element(k);
00583 
00584             char* current_name=current_tree->m_param->get_parameter(0)->m_name;
00585 
00586             if (!strcmp(current_name, desired_name))
00587                 result->append_element(current_tree);
00588 
00589             SG_UNREF(current_tree);
00590         }
00591 
00592         SG_UNREF(current_set);
00593     }
00594 
00595     return result;
00596 }
00597 
00598 CParameterCombination* CParameterCombination::copy_tree() const
00599 {
00600     CParameterCombination* copy=new CParameterCombination();
00601 
00602     /* but build new Parameter instance */
00603 
00604     /* only call add_parameters() argument is non-null */
00605     if (m_param)
00606     {
00607         copy->m_param=new Parameter();
00608         copy->m_param->add_parameters(m_param);
00609     } else
00610         copy->m_param=NULL;
00611 
00612     /* recursively copy all children */
00613     for (index_t i=0; i<m_child_nodes->get_num_elements(); ++i)
00614     {
00615         CParameterCombination* child=(CParameterCombination*)
00616                 m_child_nodes->get_element(i);
00617         copy->m_child_nodes->append_element(child->copy_tree());
00618         SG_UNREF(child);
00619     }
00620 
00621     return copy;
00622 }
00623 
00624 void CParameterCombination::apply_to_machine(CMachine* machine) const
00625 {
00626     apply_to_modsel_parameter(machine->m_model_selection_parameters);
00627 }
00628 
00629 void CParameterCombination::apply_to_modsel_parameter(
00630         Parameter* parameter) const
00631 {
00632     /* case root node */
00633     if (!m_param)
00634     {
00635         /* iterate over all children and recursively set parameters from
00636          * their values to the current parameter input (its just handed one
00637          * recursion level downwards) */
00638         for (index_t i=0; i<m_child_nodes->get_num_elements(); ++i)
00639         {
00640             CParameterCombination* child=(CParameterCombination*)
00641                     m_child_nodes->get_element(i);
00642             child->apply_to_modsel_parameter(parameter);
00643             SG_UNREF(child);
00644         }
00645     }
00646     /* case parameter node */
00647     else if (m_param)
00648     {
00649         /* set parameters */
00650         parameter->set_from_parameters(m_param);
00651 
00652         /* does this node has sub parameters? */
00653         if (has_children())
00654         {
00655             /* if a parameter node has children, it has to have ONE CSGObject as
00656              * parameter */
00657             if (m_param->get_num_parameters()>1 ||
00658                     m_param->get_parameter(0)->m_datatype.m_ptype!=PT_SGOBJECT)
00659             {
00660                 SG_SERROR("invalid CParameterCombination node type, has children"
00661                         " and more than one parameter or is not a "
00662                         "CSGObject.\n");
00663             }
00664 
00665             /* cast is now safe */
00666             CSGObject* current_sgobject=
00667                     *((CSGObject**)(m_param->get_parameter(0)->m_parameter));
00668 
00669             /* iterate over all children and recursively set parameters from
00670              * their values */
00671             for (index_t i=0; i<m_child_nodes->get_num_elements(); ++i)
00672             {
00673                 CParameterCombination* child=(CParameterCombination*)
00674                         m_child_nodes->get_element(i);
00675                 child->apply_to_modsel_parameter(
00676                         current_sgobject->m_model_selection_parameters);
00677                 SG_UNREF(child);
00678             }
00679         }
00680     }
00681     else
00682         SG_SERROR("CParameterCombination node has illegal type.\n");
00683 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

SHOGUN Machine Learning Toolbox - Documentation