SHOGUN
v2.0.0
|
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 }