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/ModelSelectionParameters.h> 00014 #include <shogun/modelselection/ParameterCombination.h> 00015 #include <shogun/lib/DataType.h> 00016 #include <shogun/base/Parameter.h> 00017 #include <shogun/base/DynArray.h> 00018 #include <shogun/lib/Set.h> 00019 00020 using namespace shogun; 00021 00022 CModelSelectionParameters::CModelSelectionParameters() 00023 { 00024 init(); 00025 } 00026 00027 CModelSelectionParameters::CModelSelectionParameters(const char* node_name) 00028 { 00029 init(); 00030 00031 m_node_name=node_name; 00032 } 00033 00034 CModelSelectionParameters::CModelSelectionParameters(const char* node_name, 00035 CSGObject* sgobject) 00036 { 00037 init(); 00038 00039 m_node_name=node_name; 00040 m_sgobject=sgobject; 00041 SG_REF(sgobject); 00042 } 00043 00044 void CModelSelectionParameters::init() 00045 { 00046 m_node_name=NULL; 00047 m_sgobject=NULL; 00048 m_child_nodes=new CDynamicObjectArray(); 00049 SG_REF(m_child_nodes); 00050 m_value_type=MSPT_NONE; 00051 m_values=NULL; 00052 m_values_length=0; 00053 00054 /* no parameter registering. These parameter nodes will not be serialized */ 00055 } 00056 00057 CModelSelectionParameters::~CModelSelectionParameters() 00058 { 00059 SG_UNREF(m_child_nodes); 00060 SG_UNREF(m_sgobject); 00061 00062 delete_values(); 00063 } 00064 00065 void CModelSelectionParameters::append_child(CModelSelectionParameters* child) 00066 { 00067 /* only possible if there are no values set */ 00068 if (m_values) 00069 SG_ERROR("not possible to append child: there already is a range\n"); 00070 00071 /* do a basic check if the add is possible */ 00072 if (m_sgobject) 00073 { 00074 /* (does this node's CSGObject contain a parameter with the name of the 00075 * child?) to prevent problems when trying to set parameters that do not 00076 * exist */ 00077 if (child->m_node_name) 00078 { 00079 if (!m_sgobject->m_parameters->contains_parameter(child->m_node_name)) 00080 { 00081 SG_ERROR("Not possible to add child, node with CSGObject \"%s\"" 00082 " does not contain a parameter called \"%s\"\n", 00083 m_sgobject->get_name(), child->m_node_name); 00084 } 00085 } 00086 else 00087 { 00088 SG_ERROR("Not possible to add child which has no name.\n"); 00089 } 00090 } 00091 00092 m_child_nodes->append_element(child); 00093 } 00094 00095 template <class T> 00096 void CModelSelectionParameters::set_values(const SGVector<T>& values, 00097 EMSParamType value_type) 00098 { 00099 /* possibly delete old range values */ 00100 delete_values(); 00101 m_values=values.vector; 00102 m_values_length=values.vlen; 00103 m_value_type=value_type; 00104 } 00105 00106 void CModelSelectionParameters::build_values(float64_t min, float64_t max, 00107 ERangeType type, float64_t step, float64_t type_base) 00108 { 00109 build_values(MSPT_FLOAT64, (void*)&min, (void*)&max, type, (void*)&step, 00110 (void*)&type_base); 00111 } 00112 00113 void CModelSelectionParameters::build_values_vector(float64_t min, float64_t max, 00114 ERangeType type, void* vector, index_t* size, float64_t step, float64_t type_base) 00115 { 00116 build_values(MSPT_FLOAT64_VECTOR, (void*)&min, (void*)&max, type, (void*)&step, 00117 (void*)&type_base); 00118 m_vector_length = size; 00119 m_vector = vector; 00120 } 00121 00122 void CModelSelectionParameters::build_values_sgvector(float64_t min, float64_t max, 00123 ERangeType type, void* vector, float64_t step, float64_t type_base) 00124 { 00125 build_values(MSPT_FLOAT64_SGVECTOR, (void*)&min, (void*)&max, type, (void*)&step, 00126 (void*)&type_base); 00127 m_vector = vector; 00128 } 00129 00130 void CModelSelectionParameters::build_values(int32_t min, int32_t max, 00131 ERangeType type, int32_t step, int32_t type_base) 00132 { 00133 build_values(MSPT_INT32, (void*)&min, (void*)&max, type, (void*)&step, 00134 (void*)&type_base); 00135 } 00136 00137 void CModelSelectionParameters::build_values_vector(int32_t min, int32_t max, 00138 ERangeType type, void* vector, index_t* size, int32_t step, int32_t type_base) 00139 { 00140 build_values(MSPT_INT32_VECTOR, (void*)&min, (void*)&max, type, (void*)&step, 00141 (void*)&type_base); 00142 m_vector_length = size; 00143 m_vector = vector; 00144 } 00145 00146 void CModelSelectionParameters::build_values_sgvector(int32_t min, int32_t max, 00147 ERangeType type, void* vector, int32_t step, int32_t type_base) 00148 { 00149 build_values(MSPT_INT32_SGVECTOR, (void*)&min, (void*)&max, type, (void*)&step, 00150 (void*)&type_base); 00151 m_vector = vector; 00152 } 00153 00154 void CModelSelectionParameters::build_values(EMSParamType value_type, void* min, 00155 void* max, ERangeType type, void* step, void* type_base) 00156 { 00157 if (m_sgobject || has_children()) 00158 { 00159 SG_ERROR("unable to set range for an CSGObject model selection " 00160 "parameter\n"); 00161 } 00162 00163 /* possibly delete old range values */ 00164 delete_values(); 00165 00166 /* save new type */ 00167 m_value_type=value_type; 00168 00169 if (value_type==MSPT_FLOAT64 || 00170 value_type==MSPT_FLOAT64_VECTOR 00171 || value_type==MSPT_FLOAT64_SGVECTOR) 00172 { 00173 SGVector<float64_t> values=create_range_array<float64_t>( 00174 *((float64_t*)min), 00175 *((float64_t*)max), 00176 type, 00177 *((float64_t*)step), 00178 *((float64_t*)type_base)); 00179 00180 m_values=values.vector; 00181 m_values_length=values.vlen; 00182 } 00183 else if (value_type==MSPT_INT32 || 00184 value_type==MSPT_INT32_VECTOR 00185 || value_type==MSPT_INT32_SGVECTOR) 00186 { 00187 SGVector<int32_t> values=create_range_array<int32_t>( 00188 *((int32_t*)min), 00189 *((int32_t*)max), 00190 type, 00191 *((int32_t*)step), 00192 *((int32_t*)type_base)); 00193 00194 m_values=values.vector; 00195 m_values_length=values.vlen; 00196 } 00197 else if (value_type==MSPT_NONE) 00198 { 00199 SG_ERROR("Value node has no type!\n"); 00200 } 00201 else 00202 { 00203 SG_ERROR("Unknown type for model selection parameter!\n"); 00204 } 00205 } 00206 00207 CParameterCombination* CModelSelectionParameters::get_single_combination( 00208 bool is_rand) 00209 { 00210 /* If this is a value node, then randomly pick a value from the built 00211 * range */ 00212 if (m_values) 00213 { 00214 00215 index_t i = 0; 00216 00217 if (is_rand) 00218 i = CMath::random(0, m_values_length-1); 00219 00220 Parameter* p=new Parameter(); 00221 00222 switch (m_value_type) 00223 { 00224 case MSPT_FLOAT64_SGVECTOR: 00225 { 00226 SGVector<float64_t>* param_vect = (SGVector<float64_t>*)m_vector; 00227 00228 for (index_t j = 0; j < param_vect->vlen; j++) 00229 { 00230 if (is_rand) 00231 i = CMath::random(0, m_values_length-1); 00232 (*param_vect)[j] = ((float64_t*)m_values)[i]; 00233 } 00234 p->add(param_vect, m_node_name); 00235 break; 00236 } 00237 case MSPT_FLOAT64_VECTOR: 00238 { 00239 float64_t* param_vect = (float64_t*)m_vector; 00240 00241 for (index_t j = 0; j < *m_vector_length; j++) 00242 { 00243 if (is_rand) 00244 i = CMath::random(0, m_values_length-1); 00245 (param_vect)[j] = ((float64_t*)m_values)[i]; 00246 } 00247 p->add_vector(¶m_vect, m_vector_length, m_node_name); 00248 break; 00249 } 00250 case MSPT_INT32_SGVECTOR: 00251 { 00252 SGVector<int32_t>* param_vect = (SGVector<int32_t>*)m_vector; 00253 00254 for (index_t j = 0; j < param_vect->vlen; j++) 00255 { 00256 if (is_rand) 00257 i = CMath::random(0, m_values_length-1); 00258 (*param_vect)[j] = ((int32_t*)m_values)[i]; 00259 } 00260 p->add(param_vect, m_node_name); 00261 break; 00262 } 00263 case MSPT_INT32_VECTOR: 00264 { 00265 int32_t* param_vect = (int32_t*)m_vector; 00266 00267 for (index_t j = 0; j < *m_vector_length; j++) 00268 { 00269 if (is_rand) 00270 i = CMath::random(0, m_values_length-1); 00271 (param_vect)[j] = ((int32_t*)m_values)[i]; 00272 } 00273 p->add_vector(¶m_vect, m_vector_length, m_node_name); 00274 break; 00275 } 00276 case MSPT_FLOAT64: 00277 p->add(&((float64_t*)m_values)[i], m_node_name); 00278 break; 00279 case MSPT_INT32: 00280 p->add(&((int32_t*)m_values)[i], m_node_name);; 00281 break; 00282 case MSPT_NONE: 00283 SG_ERROR("Value node has no type!\n"); 00284 break; 00285 default: 00286 SG_ERROR("Unknown type for model selection parameter!\n"); 00287 break; 00288 } 00289 00290 return new CParameterCombination(p); 00291 } 00292 00293 CParameterCombination* new_root=NULL; 00294 00295 /*Complain if we have a bad node*/ 00296 if (!((m_sgobject && m_node_name) || (!m_node_name && !m_sgobject))) 00297 SG_ERROR("Illegal CModelSelectionParameters node type.\n"); 00298 00299 /* Incorporate SGObject and root nodes with children*/ 00300 if (m_child_nodes->get_num_elements()) 00301 { 00302 00303 if (m_sgobject) 00304 { 00305 Parameter* p=new Parameter(); 00306 p->add(&m_sgobject, m_node_name); 00307 new_root = new CParameterCombination(p); 00308 } 00309 00310 else 00311 new_root = new CParameterCombination(); 00312 00313 for (index_t i = 0; i < m_child_nodes->get_num_elements(); ++i) 00314 { 00315 CModelSelectionParameters* current = 00316 (CModelSelectionParameters*)m_child_nodes->get_element(i); 00317 00318 CParameterCombination* c = current->get_single_combination(is_rand); 00319 00320 new_root->append_child(c); 00321 00322 SG_UNREF(current); 00323 } 00324 00325 return new_root; 00326 } 00327 00328 /*Incorporate childless nodes*/ 00329 else 00330 { 00331 00332 if (m_sgobject) 00333 { 00334 Parameter* p = new Parameter(); 00335 p->add(&m_sgobject, m_node_name); 00336 return new CParameterCombination(p); 00337 } 00338 00339 else 00340 { 00341 new_root = new CParameterCombination(); 00342 return new_root; 00343 } 00344 } 00345 00346 } 00347 00348 00349 00350 CDynamicObjectArray* CModelSelectionParameters::get_combinations( 00351 index_t num_prefix) 00352 { 00353 char* prefix=SG_MALLOC(char, num_prefix+1); 00354 prefix[num_prefix]='\0'; 00355 for (index_t i=0; i<num_prefix; ++i) 00356 prefix[i]='\t'; 00357 00358 SG_DEBUG("%s------>entering CModelSelectionParameters::get_combinations() " 00359 "for \"%s\"\n", prefix, m_node_name ? m_node_name : "root"); 00360 CDynamicObjectArray* result=new CDynamicObjectArray(); 00361 00362 /* value case: node with values and no children. 00363 * build trees of Parameter instances which each contain one value 00364 */ 00365 00366 if (m_values) 00367 { 00368 for (index_t i=0; i<m_values_length; ++i) 00369 { 00370 // create tree with only one parameter element // 00371 Parameter* p=new Parameter(); 00372 00373 switch (m_value_type) 00374 { 00375 case MSPT_FLOAT64: 00376 p->add(&((float64_t*)m_values)[i], m_node_name); 00377 break; 00378 case MSPT_INT32: 00379 p->add(&((int32_t*)m_values)[i], m_node_name);; 00380 break; 00381 case MSPT_NONE: 00382 SG_ERROR("%sValue node has no type!\n", prefix); 00383 break; 00384 default: 00385 SG_ERROR("%sUnknown type for model selection parameter!\n", 00386 prefix); 00387 break; 00388 } 00389 00390 result->append_element(new CParameterCombination(p)); 00391 } 00392 00393 SG_DEBUG("%s------>leaving CModelSelectionParameters::get_combinations()" 00394 "for \"%s\"\n", prefix, m_node_name ? m_node_name : "root"); 00395 00396 SG_FREE(prefix); 00397 return result; 00398 } 00399 00400 00401 /* two cases here, similar 00402 * -case CSGObject: 00403 * -case root node (no name, no values, but children 00404 * build all permutations of the result trees of children with values and 00405 * combine them iteratively children which are something different 00406 */ 00407 if (!((m_sgobject && m_node_name) || (!m_node_name && !m_sgobject))) 00408 SG_ERROR("%sIllegal CModelSelectionParameters node type.\n", prefix); 00409 00410 /* only consider combinations if this node has children */ 00411 if (m_child_nodes->get_num_elements()) 00412 { 00413 /* split value and non-value child combinations */ 00414 CDynamicObjectArray value_children; 00415 CDynamicObjectArray non_value_children; 00416 00417 for (index_t i=0; i<m_child_nodes->get_num_elements(); ++i) 00418 { 00419 CModelSelectionParameters* current= 00420 (CModelSelectionParameters*)m_child_nodes->get_element(i); 00421 00422 /* split children with values and children with other */ 00423 if (current->m_values) 00424 value_children.append_element(current); 00425 else 00426 non_value_children.append_element(current); 00427 00428 SG_UNREF(current); 00429 } 00430 00431 /* extract all tree sets of all value children */ 00432 CDynamicObjectArray value_node_sets; 00433 for (index_t i=0; i<value_children.get_num_elements(); ++i) 00434 { 00435 /* recursively get all combinations in a new array */ 00436 CModelSelectionParameters* value_child= 00437 (CModelSelectionParameters*)value_children.get_element(i); 00438 value_node_sets.append_element(value_child->get_combinations( 00439 num_prefix+1)); 00440 SG_UNREF(value_child); 00441 } 00442 00443 /* build product of all these tree sets */ 00444 00445 /* new root node is needed for new trees, depends on current case */ 00446 CParameterCombination* new_root=NULL; 00447 if (m_sgobject) 00448 { 00449 Parameter* p=new Parameter(); 00450 p->add(&m_sgobject, m_node_name); 00451 new_root=new CParameterCombination(p); 00452 } 00453 else 00454 new_root=new CParameterCombination(); 00455 00456 SG_REF(new_root); 00457 00458 CDynamicObjectArray* value_combinations= 00459 CParameterCombination::leaf_sets_multiplication(value_node_sets, 00460 new_root); 00461 00462 SG_UNREF(new_root); 00463 00464 if (!non_value_children.get_num_elements()) 00465 *result=*value_combinations; 00466 /* in the other case, the non-values have also to be treated, but 00467 * combined iteratively */ 00468 else 00469 { 00470 /* extract all tree sets of non-value nodes */ 00471 // SG_PRINT("%sextracting combinations of non-value nodes\n", prefix); 00472 CDynamicObjectArray* non_value_combinations= 00473 new CDynamicObjectArray(); 00474 for (index_t i=0; i<non_value_children.get_num_elements(); ++i) 00475 { 00476 /* recursively get all combinations in a new array */ 00477 CModelSelectionParameters* non_value_child= 00478 (CModelSelectionParameters*) 00479 non_value_children.get_element(i); 00480 00481 // SG_PRINT("%s\tcurrent non-value child\n", prefix); 00482 // non_value_child->print_tree(num_prefix+1); 00483 00484 CDynamicObjectArray* current_combination= 00485 non_value_child->get_combinations(num_prefix+2); 00486 non_value_combinations->append_element(current_combination); 00487 SG_UNREF(non_value_child); 00488 00489 // SG_PRINT("%s\tcombinations of non-value nodes:\n", prefix); 00490 // for (index_t j=0; j<current_combination->get_num_elements(); ++j) 00491 // { 00492 // CParameterCombination* c=(CParameterCombination*) 00493 // current_combination->get_element(j); 00494 // c->print_tree(num_prefix+2); 00495 // SG_UNREF(c); 00496 // } 00497 } 00498 // SG_PRINT("%sdone extracting combinations of non-value nodes\n", 00499 // prefix); 00500 00501 /* Now, combine combinations of value and non-value nodes */ 00502 00503 /* if there are only non-value children, nothing is combined */ 00504 if (!value_combinations->get_num_elements()) 00505 { 00506 /* non-value children have to be multipied first, then, all 00507 * these products are just appended */ 00508 00509 /* temporary new root is needed to put fron all product trees */ 00510 if (m_sgobject) 00511 { 00512 Parameter* p=new Parameter(); 00513 p->add(&m_sgobject, m_node_name); 00514 new_root=new CParameterCombination(p); 00515 } 00516 else 00517 new_root=new CParameterCombination(); 00518 00519 CDynamicObjectArray* non_value_products= 00520 CParameterCombination::non_value_tree_multiplication( 00521 non_value_combinations, new_root); 00522 00523 SG_UNREF(new_root); 00524 00525 SG_UNREF(non_value_combinations); 00526 non_value_combinations=non_value_products; 00527 00528 /* append all non-value combinations to result */ 00529 for (index_t i=0; i<non_value_combinations->get_num_elements(); ++i) 00530 { 00531 CParameterCombination* current=(CParameterCombination*) 00532 non_value_combinations->get_element(i); 00533 result->append_element(current); 00534 SG_UNREF(current); 00535 } 00536 } 00537 else 00538 { 00539 /* before combinations are built, produce products of non-value 00540 * combinations. new root is temporarily needed to put front 00541 * all new trees */ 00542 if (m_sgobject) 00543 { 00544 Parameter* p=new Parameter(); 00545 p->add(&m_sgobject, m_node_name); 00546 new_root=new CParameterCombination(p); 00547 } 00548 else 00549 new_root=new CParameterCombination(); 00550 00551 CDynamicObjectArray* non_value_products= 00552 CParameterCombination::non_value_tree_multiplication( 00553 non_value_combinations, new_root); 00554 00555 SG_UNREF(new_root); 00556 00557 SG_UNREF(non_value_combinations); 00558 non_value_combinations=non_value_products; 00559 00560 for (index_t i=0; i<value_combinations->get_num_elements(); ++i) 00561 { 00562 CParameterCombination* current_value_tree= 00563 (CParameterCombination*) 00564 value_combinations->get_element(i); 00565 00566 for (index_t j=0; j 00567 <non_value_combinations->get_num_elements(); ++j) 00568 { 00569 CParameterCombination* current_non_value_tree= 00570 (CParameterCombination*) 00571 non_value_combinations->get_element(j); 00572 00573 /* copy current value tree and add all childs of non- 00574 * value combination. Then add new node to result */ 00575 CParameterCombination* value_copy= 00576 current_value_tree->copy_tree(); 00577 00578 value_copy->merge_with(current_non_value_tree); 00579 result->append_element(value_copy); 00580 00581 SG_UNREF(current_non_value_tree); 00582 } 00583 00584 SG_UNREF(current_value_tree); 00585 } 00586 } 00587 00588 /* clean up*/ 00589 SG_UNREF(non_value_combinations); 00590 } 00591 00592 SG_UNREF(value_combinations); 00593 } 00594 else 00595 { 00596 /* if there are no children of a sgobject or root node, result is 00597 * only one element (sgobject node) or empty (root node) 00598 */ 00599 if (m_sgobject) 00600 { 00601 Parameter* p=new Parameter(); 00602 p->add(&m_sgobject, m_node_name); 00603 result->append_element(new CParameterCombination(p)); 00604 } 00605 } 00606 00607 // SG_PRINT("%sresult is a set of %d elements:\n", prefix, 00608 // result->get_num_elements()); 00609 // for (index_t i=0; i<result->get_num_elements(); ++i) 00610 // { 00611 // CParameterCombination* current=(CParameterCombination*) 00612 // result->get_element(i); 00613 // current->print_tree(num_prefix+1); 00614 // SG_UNREF(current); 00615 // } 00616 00617 SG_DEBUG("%s------>leaving CModelSelectionParameters::get_combinations()" 00618 "for \"%s\"\n", prefix, m_node_name ? m_node_name : "root"); 00619 SG_FREE(prefix); 00620 return result; 00621 } 00622 00623 void CModelSelectionParameters::print_tree(int prefix_num) 00624 { 00625 /* prefix is enlarged */ 00626 char* prefix=SG_MALLOC(char, prefix_num+1); 00627 for (index_t i=0; i<prefix_num; ++i) 00628 prefix[i]='\t'; 00629 00630 prefix[prefix_num]='\0'; 00631 00632 if (has_children()) 00633 { 00634 if (m_sgobject) 00635 SG_PRINT("%s%s:\"%s\"\n", prefix, m_node_name, m_sgobject->get_name()); 00636 else 00637 SG_PRINT("%s%s with\n", prefix, m_node_name ? m_node_name : "root"); 00638 00639 /* now recursively print successors */ 00640 00641 /* cast safe because only CModelSelectionParameters are added to list */ 00642 for (index_t i=0; i<m_child_nodes->get_num_elements(); ++i) 00643 { 00644 CModelSelectionParameters* child= 00645 (CModelSelectionParameters*)m_child_nodes->get_element(i); 00646 child->print_tree(prefix_num+1); 00647 SG_UNREF(child); 00648 } 00649 } 00650 else 00651 { 00652 /* has to be a node with name and a numeric range or a single sg_object 00653 * without children*/ 00654 if (m_sgobject) 00655 { 00656 SG_PRINT("%s%s:\"%s\"\n", prefix, m_node_name, m_sgobject->get_name()); 00657 } 00658 else 00659 { 00660 if (m_values) 00661 { 00662 // value node 00663 SG_PRINT("%s%s with values: ", prefix, m_node_name); 00664 00665 switch (m_value_type) 00666 { 00667 case MSPT_FLOAT64: case MSPT_FLOAT64_VECTOR: 00668 case MSPT_FLOAT64_SGVECTOR: 00669 00670 SGVector<float64_t>::display_vector((float64_t*)m_values, 00671 m_values_length); 00672 break; 00673 case MSPT_INT32: case MSPT_INT32_VECTOR: 00674 case MSPT_INT32_SGVECTOR: 00675 00676 SGVector<int32_t>::display_vector((int32_t*)m_values, 00677 m_values_length);; 00678 break; 00679 case MSPT_NONE: 00680 SG_ERROR("Value node has no type!\n"); 00681 break; 00682 default: 00683 SG_ERROR("Unknown type for model selection parameter!\n"); 00684 break; 00685 } 00686 } 00687 else 00688 SG_PRINT("root\n"); 00689 } 00690 } 00691 00692 SG_FREE(prefix); 00693 } 00694 00695 void CModelSelectionParameters::delete_values() 00696 { 00697 if (m_values) 00698 { 00699 switch (m_value_type) 00700 { 00701 case MSPT_FLOAT64: case MSPT_FLOAT64_VECTOR: 00702 case MSPT_FLOAT64_SGVECTOR: 00703 00704 SG_FREE((float64_t*)m_values); 00705 break; 00706 case MSPT_INT32: case MSPT_INT32_VECTOR: 00707 case MSPT_INT32_SGVECTOR: 00708 00709 SG_FREE((int32_t*)m_values); 00710 break; 00711 case MSPT_NONE: 00712 SG_ERROR("Value node has no type!\n"); 00713 break; 00714 default: 00715 SG_ERROR("Unknown type for model selection parameter!\n"); 00716 break; 00717 } 00718 } 00719 }