SHOGUN
v1.1.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 Heiko Strathmann 00008 * Copyright (C) 2011 Berlin Institute of Technology and Max-Planck-Society 00009 */ 00010 00011 #include <shogun/modelselection/ModelSelectionParameters.h> 00012 #include <shogun/modelselection/ParameterCombination.h> 00013 #include <shogun/lib/DataType.h> 00014 #include <shogun/base/Parameter.h> 00015 #include <shogun/base/DynArray.h> 00016 00017 using namespace shogun; 00018 00019 CModelSelectionParameters::CModelSelectionParameters() 00020 { 00021 init(); 00022 } 00023 00024 CModelSelectionParameters::CModelSelectionParameters(const char* node_name) 00025 { 00026 init(); 00027 00028 m_node_name=node_name; 00029 } 00030 00031 CModelSelectionParameters::CModelSelectionParameters(const char* node_name, 00032 CSGObject* sgobject) 00033 { 00034 init(); 00035 00036 m_node_name=node_name; 00037 m_sgobject=sgobject; 00038 SG_REF(sgobject); 00039 } 00040 00041 void CModelSelectionParameters::init() 00042 { 00043 m_node_name=NULL; 00044 m_sgobject=NULL; 00045 m_child_nodes=new CDynamicObjectArray<CModelSelectionParameters>(); 00046 SG_REF(m_child_nodes); 00047 m_value_type=MSPT_NONE; 00048 00049 m_parameters->add((char*)m_node_name, "node_name", "Name of node"); 00050 m_parameters->add((CSGObject**)&m_sgobject, "sgobject", 00051 "CSGObject of this node"); 00052 m_parameters->add((CSGObject**)m_child_nodes, "child nodes", 00053 "children of this node"); 00054 // m_parameters->add(&m_value_type, "value_type", 00055 // "type of the values of this node"); 00056 } 00057 00058 CModelSelectionParameters::~CModelSelectionParameters() 00059 { 00060 SG_UNREF(m_child_nodes); 00061 SG_UNREF(m_sgobject); 00062 00063 delete_values(); 00064 } 00065 00066 void CModelSelectionParameters::append_child(CModelSelectionParameters* child) 00067 { 00068 /* only possible if there are no values set */ 00069 if (m_values.vector) 00070 SG_ERROR("not possible to append child: there already is a range\n"); 00071 00072 /* do a basic check if the add is possible */ 00073 if (m_sgobject) 00074 { 00075 /* (does this node's CSGObject contain a parameter with the name of the 00076 * child?) to prevent problems when trying to set parameters that do not 00077 * exist */ 00078 if (child->m_node_name) 00079 { 00080 if (!m_sgobject->m_parameters->contains_parameter(child->m_node_name)) 00081 { 00082 SG_ERROR("Not possible to add child, node with CSGObject \"%s\"" 00083 " does not contain a parameter called \"%s\"\n", 00084 m_sgobject->get_name(), child->m_node_name); 00085 } 00086 } 00087 else 00088 { 00089 SG_ERROR("Not possible to add child which has no name.\n"); 00090 } 00091 } 00092 00093 m_child_nodes->append_element(child); 00094 } 00095 00096 template <class T> 00097 void CModelSelectionParameters::set_values(SGVector<T> values) 00098 { 00099 /* possibly delete old range values */ 00100 delete_values(); 00101 m_values=(SGVector<char>) values; 00102 } 00103 00104 void CModelSelectionParameters::build_values(float64_t min, float64_t max, 00105 ERangeType type, float64_t step, float64_t type_base) 00106 { 00107 build_values(MSPT_FLOAT64, (void*)&min, (void*)&max, type, (void*)&step, 00108 (void*)&type_base); 00109 } 00110 00111 void CModelSelectionParameters::build_values(int32_t min, int32_t max, 00112 ERangeType type, int32_t step, int32_t type_base) 00113 { 00114 build_values(MSPT_INT32, (void*)&min, (void*)&max, type, (void*)&step, 00115 (void*)&type_base); 00116 } 00117 00118 void CModelSelectionParameters::build_values(EMSParamType value_type, void* min, 00119 void* max, ERangeType type, void* step, void* type_base) 00120 { 00121 if (m_sgobject || has_children()) 00122 { 00123 SG_ERROR("unable to set range for an CSGObject model selection " 00124 "parameter\n"); 00125 } 00126 00127 /* possibly delete old range values */ 00128 delete_values(); 00129 00130 /* save new type */ 00131 m_value_type=value_type; 00132 00133 if (value_type==MSPT_FLOAT64) 00134 { 00135 SGVector<float64_t> values=create_range_array<float64_t>( 00136 *((float64_t*)min), 00137 *((float64_t*)max), 00138 type, 00139 *((float64_t*)step), 00140 *((float64_t*)type_base)); 00141 00142 m_values.vector=(char*)values.vector; 00143 m_values.vlen=values.vlen; 00144 } 00145 else if (value_type==MSPT_INT32) 00146 { 00147 SGVector<int32_t> values=create_range_array<int32_t>( 00148 *((int32_t*)min), 00149 *((int32_t*)max), 00150 type, 00151 *((int32_t*)step), 00152 *((int32_t*)type_base)); 00153 00154 m_values.vector=(char*)values.vector; 00155 m_values.vlen=values.vlen; 00156 } 00157 else if (value_type==MSPT_NONE) 00158 { 00159 SG_ERROR("Value node has no type!\n"); 00160 } 00161 else 00162 { 00163 SG_ERROR("Unknown type for model selection parameter!\n"); 00164 } 00165 } 00166 00167 CDynamicObjectArray<CParameterCombination>* CModelSelectionParameters::get_combinations() 00168 { 00169 CDynamicObjectArray<CParameterCombination>* result=new CDynamicObjectArray< 00170 CParameterCombination>(); 00171 00172 /* value case: node with values and no children. 00173 * build trees of Parameter instances which each contain one value 00174 */ 00175 00176 if (m_values.vector) 00177 { 00178 for (index_t i=0; i<m_values.vlen; ++i) 00179 { 00180 // create tree with only one parameter element // 00181 Parameter* p=new Parameter(); 00182 00183 switch (m_value_type) 00184 { 00185 case MSPT_FLOAT64: 00186 p->add(&((float64_t*)m_values.vector)[i], m_node_name); 00187 break; 00188 case MSPT_INT32: 00189 p->add(&((int32_t*)m_values.vector)[i], m_node_name);; 00190 break; 00191 case MSPT_NONE: 00192 SG_ERROR("Value node has no type!\n"); 00193 break; 00194 default: 00195 SG_ERROR("Unknown type for model selection parameter!\n"); 00196 break; 00197 } 00198 00199 result->append_element(new CParameterCombination(p)); 00200 } 00201 00202 return result; 00203 } 00204 00205 00206 /* two cases here, similar 00207 * -case CSGObject: 00208 * -case root node (no name, no values, but children 00209 * build all permutations of the result trees of children with values and 00210 * combine them iteratively children which are something different 00211 */ 00212 if (!((m_sgobject && m_node_name) || (!m_node_name && !m_sgobject))) 00213 SG_ERROR("Illegal CModelSelectionParameters node type.\n"); 00214 00215 /* only consider combinations if this node has children */ 00216 if (m_child_nodes->get_num_elements()) 00217 { 00218 /* split value and non-value child combinations */ 00219 CDynamicObjectArray<CModelSelectionParameters> value_children; 00220 CDynamicObjectArray<CModelSelectionParameters> non_value_children; 00221 00222 for (index_t i=0; i<m_child_nodes->get_num_elements(); ++i) 00223 { 00224 CModelSelectionParameters* current=m_child_nodes->get_element(i); 00225 00226 /* split children with values and children with other */ 00227 if (current->m_values.vector) 00228 value_children.append_element(current); 00229 else 00230 non_value_children.append_element(current); 00231 00232 SG_UNREF(current); 00233 } 00234 00235 /* extract all tree sets of all value children */ 00236 CDynamicObjectArray<CDynamicObjectArray<CParameterCombination> > value_node_sets; 00237 for (index_t i=0; i<value_children.get_num_elements(); ++i) 00238 { 00239 /* recursively get all combinations in a new array */ 00240 CModelSelectionParameters* value_child= 00241 value_children.get_element(i); 00242 value_node_sets.append_element(value_child->get_combinations()); 00243 SG_UNREF(value_child); 00244 } 00245 00246 /* build product of all these tree sets */ 00247 00248 /* new root node is needed for new trees, depends on current case */ 00249 CParameterCombination* new_root=NULL; 00250 if (m_sgobject) 00251 { 00252 Parameter* p=new Parameter(); 00253 p->add(&m_sgobject, m_node_name); 00254 new_root=new CParameterCombination(p); 00255 } 00256 else 00257 new_root=new CParameterCombination(); 00258 00259 SG_REF(new_root); 00260 00261 CDynamicObjectArray<CParameterCombination>* value_combinations= 00262 CParameterCombination::leaf_sets_multiplication(value_node_sets, 00263 new_root); 00264 00265 SG_UNREF(new_root); 00266 00267 /* if there are no non-value sets, just use the above result */ 00268 if (!non_value_children.get_num_elements()) 00269 *result=*value_combinations; 00270 /* in the other case, the non-values have also to be treated, but 00271 * combined iteratively */ 00272 else 00273 { 00274 /* extract all tree sets of non-value nodes */ 00275 CDynamicObjectArray<CDynamicObjectArray<CParameterCombination> > 00276 non_value_combinations; 00277 for (index_t i=0; i<non_value_children.get_num_elements(); ++i) 00278 { 00279 /* recursively get all combinations in a new array */ 00280 CModelSelectionParameters* non_value_child= 00281 non_value_children.get_element(i); 00282 non_value_combinations.append_element( 00283 non_value_child->get_combinations()); 00284 SG_UNREF(non_value_child); 00285 } 00286 00287 /* combine combinations of value and non-value nodes */ 00288 00289 /* if there are only non-value children, nothing is combined */ 00290 if (!value_combinations->get_num_elements()) 00291 { 00292 /* non-value children are only pasted together. However, the 00293 * new root node is to put as root in front of all trees. 00294 * If there were value children before, this is done by 00295 * value_node_sets_multiplication. In this case it has to be done 00296 * by hand. */ 00297 00298 for (index_t j=0; 00299 j<non_value_combinations.get_num_elements(); ++j) 00300 { 00301 CDynamicObjectArray<CParameterCombination>* current_non_value_set= 00302 non_value_combinations.get_element(j); 00303 00304 for (index_t k=0; k 00305 <current_non_value_set->get_num_elements(); ++k) 00306 { 00307 CParameterCombination* current_non_value_tree= 00308 current_non_value_set->get_element(k); 00309 00310 /* append new root with rest of tree to current 00311 * tree. re-use of new_root variable, safe here */ 00312 new_root=new CParameterCombination(); 00313 new_root->append_child(current_non_value_tree); 00314 result->append_element(new_root); 00315 00316 SG_UNREF(current_non_value_tree); 00317 } 00318 00319 SG_UNREF(current_non_value_set); 00320 } 00321 } 00322 else 00323 { 00324 for (index_t i=0; i<value_combinations->get_num_elements(); ++i) 00325 { 00326 CParameterCombination* current_value_tree= 00327 value_combinations->get_element(i); 00328 00329 for (index_t j=0; j 00330 <non_value_combinations.get_num_elements(); ++j) 00331 { 00332 CDynamicObjectArray<CParameterCombination> * current_non_value_set= 00333 non_value_combinations.get_element(j); 00334 00335 for (index_t k=0; k 00336 <current_non_value_set->get_num_elements(); ++k) 00337 { 00338 CParameterCombination* current_non_value_tree= 00339 current_non_value_set->get_element(k); 00340 00341 /* copy the current trees and append non-value 00342 * tree to value tree. Note that the root in the 00343 * non-value tree is already the current 00344 * CSGObject and therefore the non-value tree 00345 * copy may just be appended as child */ 00346 CParameterCombination* value_copy= 00347 current_value_tree->copy_tree(); 00348 CParameterCombination* non_value_copy= 00349 current_non_value_tree->copy_tree(); 00350 00351 value_copy->append_child(non_value_copy); 00352 result->append_element(value_copy); 00353 00354 SG_UNREF(current_non_value_tree); 00355 } 00356 00357 SG_UNREF(current_non_value_set); 00358 } 00359 00360 SG_UNREF(current_value_tree); 00361 } 00362 } 00363 } 00364 00365 SG_UNREF(value_combinations); 00366 } 00367 else 00368 { 00369 /* if there are no children of a sgobject or root node, result is 00370 * only one element (sgobject node) or empty (root node) 00371 */ 00372 if (m_sgobject) 00373 { 00374 Parameter* p=new Parameter(); 00375 p->add(&m_sgobject, m_node_name); 00376 result->append_element(new CParameterCombination(p)); 00377 } 00378 } 00379 00380 return result; 00381 } 00382 00383 void CModelSelectionParameters::print_tree(int prefix_num) 00384 { 00385 /* prefix is enlarged */ 00386 char* prefix=SG_MALLOC(char, prefix_num+1); 00387 for (index_t i=0; i<prefix_num; ++i) 00388 prefix[i]='\t'; 00389 00390 prefix[prefix_num]='\0'; 00391 00392 if (has_children()) 00393 { 00394 if (m_sgobject) 00395 SG_PRINT("%s%s:\"%s\"\n", prefix, m_node_name, m_sgobject->get_name()); 00396 else 00397 SG_PRINT("%s%s with\n", prefix, m_node_name ? m_node_name : "root"); 00398 00399 /* now recursively print successors */ 00400 00401 /* cast safe because only CModelSelectionParameters are added to list */ 00402 for (index_t i=0; i<m_child_nodes->get_num_elements(); ++i) 00403 { 00404 CModelSelectionParameters* child=m_child_nodes->get_element(i); 00405 child->print_tree(prefix_num+1); 00406 SG_UNREF(child); 00407 } 00408 } 00409 else 00410 { 00411 /* has to be a node with name and a numeric range or a single sg_object 00412 * without children*/ 00413 if (m_sgobject) 00414 { 00415 SG_PRINT("%s%s:\"%s\"\n", prefix, m_node_name, m_sgobject->get_name()); 00416 } 00417 else 00418 { 00419 if (m_values.vector) 00420 { 00421 // value node 00422 SG_PRINT("%s%s with values: ", prefix, m_node_name); 00423 00424 switch (m_value_type) 00425 { 00426 case MSPT_FLOAT64: 00427 CMath::display_vector((float64_t*)m_values.vector, m_values.vlen); 00428 break; 00429 case MSPT_INT32: 00430 CMath::display_vector((int32_t*)m_values.vector, m_values.vlen);; 00431 break; 00432 case MSPT_NONE: 00433 SG_ERROR("Value node has no type!\n"); 00434 break; 00435 default: 00436 SG_ERROR("Unknown type for model selection parameter!\n"); 00437 break; 00438 } 00439 } 00440 else 00441 SG_PRINT("root\n"); 00442 } 00443 } 00444 00445 SG_FREE(prefix); 00446 } 00447 00448 void CModelSelectionParameters::delete_values() 00449 { 00450 if (m_values.vector) 00451 { 00452 switch (m_value_type) 00453 { 00454 case MSPT_FLOAT64: 00455 SG_FREE((float64_t*) m_values.vector); 00456 break; 00457 case MSPT_INT32: 00458 SG_FREE((int32_t*) m_values.vector); 00459 break; 00460 case MSPT_NONE: 00461 SG_ERROR("Value node has no type!\n"); 00462 break; 00463 default: 00464 SG_ERROR("Unknown type for model selection parameter!\n"); 00465 break; 00466 } 00467 } 00468 }