SHOGUN  3.2.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SGObject.cpp
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 3 of the License, or
5  * (at your option) any later version.
6  *
7  * Written (W) 2008-2009 Soeren Sonnenburg
8  * Written (W) 2011-2013 Heiko Strathmann
9  * Written (W) 2013-2014 Thoralf Klein
10  * Copyright (C) 2008-2009 Fraunhofer Institute FIRST and Max Planck Society
11  */
12 
13 #include <shogun/lib/config.h>
14 #include <shogun/lib/memory.h>
15 #include <shogun/lib/RefCount.h>
16 
17 #include <shogun/base/SGObject.h>
18 #include <shogun/io/SGIO.h>
19 #include <shogun/base/Version.h>
20 #include <shogun/base/Parameter.h>
22 #include <shogun/base/DynArray.h>
23 #include <shogun/lib/Map.h>
24 #include <shogun/lib/SGVector.h>
27 
28 #include <shogun/base/class_list.h>
29 
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <string.h>
33 
34 namespace shogun
35 {
36  class Parallel;
37 
38  extern Parallel* sg_parallel;
39  extern SGIO* sg_io;
40  extern Version* sg_version;
41 
42  template<> void CSGObject::set_generic<bool>()
43  {
44  m_generic = PT_BOOL;
45  }
46 
47  template<> void CSGObject::set_generic<char>()
48  {
49  m_generic = PT_CHAR;
50  }
51 
52  template<> void CSGObject::set_generic<int8_t>()
53  {
54  m_generic = PT_INT8;
55  }
56 
57  template<> void CSGObject::set_generic<uint8_t>()
58  {
59  m_generic = PT_UINT8;
60  }
61 
62  template<> void CSGObject::set_generic<int16_t>()
63  {
64  m_generic = PT_INT16;
65  }
66 
67  template<> void CSGObject::set_generic<uint16_t>()
68  {
69  m_generic = PT_UINT16;
70  }
71 
72  template<> void CSGObject::set_generic<int32_t>()
73  {
74  m_generic = PT_INT32;
75  }
76 
77  template<> void CSGObject::set_generic<uint32_t>()
78  {
79  m_generic = PT_UINT32;
80  }
81 
82  template<> void CSGObject::set_generic<int64_t>()
83  {
84  m_generic = PT_INT64;
85  }
86 
87  template<> void CSGObject::set_generic<uint64_t>()
88  {
89  m_generic = PT_UINT64;
90  }
91 
92  template<> void CSGObject::set_generic<float32_t>()
93  {
94  m_generic = PT_FLOAT32;
95  }
96 
97  template<> void CSGObject::set_generic<float64_t>()
98  {
99  m_generic = PT_FLOAT64;
100  }
101 
102  template<> void CSGObject::set_generic<floatmax_t>()
103  {
104  m_generic = PT_FLOATMAX;
105  }
106 
107  template<> void CSGObject::set_generic<CSGObject*>()
108  {
109  m_generic = PT_SGOBJECT;
110  }
111 
112  template<> void CSGObject::set_generic<complex128_t>()
113  {
114  m_generic = PT_COMPLEX128;
115  }
116 
117 } /* namespace shogun */
118 
119 using namespace shogun;
120 
122 {
123  init();
124  set_global_objects();
125  m_refcount = new RefCount(0);
126 
127  SG_SGCDEBUG("SGObject created (%p)\n", this)
128 }
129 
131 :io(orig.io), parallel(orig.parallel), version(orig.version)
132 {
133  init();
134  set_global_objects();
135  m_refcount = new RefCount(0);
136 
137  SG_SGCDEBUG("SGObject copied (%p)\n", this)
138 }
139 
141 {
142  SG_SGCDEBUG("SGObject destroyed (%p)\n", this)
143 
144  unset_global_objects();
145  delete m_parameters;
147  delete m_gradient_parameters;
148  delete m_parameter_map;
149  delete m_refcount;
150 }
151 
152 #ifdef USE_REFERENCE_COUNTING
153 int32_t CSGObject::ref()
154 {
155  int32_t count = m_refcount->ref();
156  SG_SGCDEBUG("ref() refcount %ld obj %s (%p) increased\n", count, this->get_name(), this)
157  return m_refcount->ref_count();
158 }
159 
160 int32_t CSGObject::ref_count()
161 {
162  int32_t count = m_refcount->ref_count();
163  SG_SGCDEBUG("ref_count(): refcount %d, obj %s (%p)\n", count, this->get_name(), this)
164  return m_refcount->ref_count();
165 }
166 
167 int32_t CSGObject::unref()
168 {
169  int32_t count = m_refcount->unref();
170  if (count<=0)
171  {
172  SG_SGCDEBUG("unref() refcount %ld, obj %s (%p) destroying\n", count, this->get_name(), this)
173  delete this;
174  return 0;
175  }
176  else
177  {
178  SG_SGCDEBUG("unref() refcount %ld obj %s (%p) decreased\n", count, this->get_name(), this)
179  return m_refcount->ref_count();
180  }
181 }
182 #endif //USE_REFERENCE_COUNTING
183 
184 #ifdef TRACE_MEMORY_ALLOCS
185 #include <shogun/lib/Map.h>
186 extern CMap<void*, shogun::MemoryBlock>* sg_mallocs;
187 
188 void CSGObject::list_memory_allocs()
189 {
190  shogun::list_memory_allocs();
191 }
192 #endif
193 
195 {
197  return NULL;
198 }
199 
201 {
203  return NULL;
204 }
205 
206 void CSGObject::set_global_objects()
207 {
208  if (!sg_io || !sg_parallel || !sg_version)
209  {
210  fprintf(stderr, "call init_shogun() before using the library, dying.\n");
211  exit(1);
212  }
213 
214  SG_REF(sg_io);
217 
218  io=sg_io;
221 }
222 
223 void CSGObject::unset_global_objects()
224 {
225  SG_UNREF(version);
227  SG_UNREF(io);
228 }
229 
231 {
232  SG_REF(new_io);
233  SG_UNREF(sg_io);
234  sg_io=new_io;
235 }
236 
238 {
239  SG_REF(sg_io);
240  return sg_io;
241 }
242 
244 {
245  SG_REF(new_parallel);
247  sg_parallel=new_parallel;
248 }
249 
251 {
252  SG_DEBUG("entering\n")
253 
254  uint32_t carry=0;
255  uint32_t length=0;
256 
257  get_parameter_incremental_hash(m_hash, carry, length);
259 
260  SG_DEBUG("leaving\n")
261 }
262 
264 {
265  SG_DEBUG("entering\n")
266 
267  uint32_t hash=0;
268  uint32_t carry=0;
269  uint32_t length=0;
270 
271  get_parameter_incremental_hash(hash, carry, length);
272  hash=CHash::FinalizeIncrementalMurmurHash3(hash, carry, length);
273 
274  SG_DEBUG("leaving\n")
275  return (m_hash!=hash);
276 }
277 
279 {
281  return sg_parallel;
282 }
283 
285 {
286  SG_REF(new_version);
288  sg_version=new_version;
289 }
290 
292 {
294  return sg_version;
295 }
296 
297 bool CSGObject::is_generic(EPrimitiveType* generic) const
298 {
299  *generic = m_generic;
300 
301  return m_generic != PT_NOT_GENERIC;
302 }
303 
305 {
306  m_generic = PT_NOT_GENERIC;
307 }
308 
309 void CSGObject::print_serializable(const char* prefix)
310 {
311  SG_PRINT("\n%s\n================================================================================\n", get_name())
312  m_parameters->print(prefix);
313 }
314 
316  const char* prefix, int32_t param_version)
317 {
318  SG_DEBUG("START SAVING CSGObject '%s'\n", get_name())
319  try
320  {
322  }
323  catch (ShogunException& e)
324  {
325  SG_SWARNING("%s%s::save_serializable_pre(): ShogunException: "
326  "%s\n", prefix, get_name(),
328  return false;
329  }
330 
331  if (!m_save_pre_called)
332  {
333  SG_SWARNING("%s%s::save_serializable_pre(): Implementation "
334  "error: BASE_CLASS::SAVE_SERIALIZABLE_PRE() not "
335  "called!\n", prefix, get_name());
336  return false;
337  }
338 
339  /* save parameter version */
340  if (!save_parameter_version(file, prefix, param_version))
341  return false;
342 
343  if (!m_parameters->save(file, prefix))
344  return false;
345 
346  try
347  {
349  }
350  catch (ShogunException& e)
351  {
352  SG_SWARNING("%s%s::save_serializable_post(): ShogunException: "
353  "%s\n", prefix, get_name(),
355  return false;
356  }
357 
358  if (!m_save_post_called)
359  {
360  SG_SWARNING("%s%s::save_serializable_post(): Implementation "
361  "error: BASE_CLASS::SAVE_SERIALIZABLE_POST() not "
362  "called!\n", prefix, get_name());
363  return false;
364  }
365 
366  if (prefix == NULL || *prefix == '\0')
367  file->close();
368 
369  SG_DEBUG("DONE SAVING CSGObject '%s' (%p)\n", get_name(), this)
370 
371  return true;
372 }
373 
375  const char* prefix, int32_t param_version)
376 {
377  REQUIRE(file != NULL, "Serializable file object should be != NULL\n");
378 
379  SG_DEBUG("START LOADING CSGObject '%s'\n", get_name())
380  try
381  {
383  }
384  catch (ShogunException& e)
385  {
386  SG_SWARNING("%s%s::load_serializable_pre(): ShogunException: "
387  "%s\n", prefix, get_name(),
389  return false;
390  }
391  if (!m_load_pre_called)
392  {
393  SG_SWARNING("%s%s::load_serializable_pre(): Implementation "
394  "error: BASE_CLASS::LOAD_SERIALIZABLE_PRE() not "
395  "called!\n", prefix, get_name());
396  return false;
397  }
398 
399  /* try to load version of parameters */
400  int32_t file_version=load_parameter_version(file, prefix);
401  SG_DEBUG("file_version=%d, current_version=%d\n", file_version, param_version)
402 
403  if (file_version<0)
404  {
405  SG_WARNING("%s%s::load_serializable(): File contains no parameter "
406  "version. Seems like your file is from the days before this "
407  "was introduced. Ignore warning or serialize with this version "
408  "of shogun to get rid of above and this warnings.\n",
409  prefix, get_name());
410  }
411 
412  if (file_version>param_version)
413  {
414  if (param_version==Version::get_version_parameter())
415  {
416  SG_WARNING("%s%s::load_serializable(): parameter version of file "
417  "larger than the one of shogun. Try with a more recent"
418  "version of shogun.\n", prefix, get_name());
419  }
420  else
421  {
422  SG_WARNING("%s%s::load_serializable(): parameter version of file "
423  "larger than the current. This is probably an implementation"
424  " error.\n", prefix, get_name());
425  }
426  return false;
427  }
428 
429  if (file_version==param_version)
430  {
431  /* load normally if file has current version */
432  SG_DEBUG("loading normally\n")
433 
434  /* load all parameters, except new ones */
435  for (int32_t i=0; i<m_parameters->get_num_parameters(); i++)
436  {
438 
439  /* skip new parameters */
440  if (is_param_new(SGParamInfo(current, param_version)))
441  continue;
442 
443  if (!current->load(file, prefix))
444  return false;
445  }
446  }
447  else
448  {
449  /* load all parameters from file, mappings to current version */
450  DynArray<TParameter*>* param_base=load_all_file_parameters(file_version,
451  param_version, file, prefix);
452 
453  /* create an array of param infos from current parameters */
454  DynArray<const SGParamInfo*>* param_infos=
456  for (index_t i=0; i<m_parameters->get_num_parameters(); ++i)
457  {
459 
460  /* skip new parameters */
461  if (is_param_new(SGParamInfo(current, param_version)))
462  continue;
463 
464  param_infos->append_element(
465  new SGParamInfo(current, param_version));
466  }
467 
468  /* map all parameters, result may be empty if input is */
469  map_parameters(param_base, file_version, param_infos);
470  SG_DEBUG("mapping is done!\n")
471 
472  /* this is assumed now, mapping worked or no parameters in base */
473  ASSERT(file_version==param_version || !param_base->get_num_elements())
474 
475  /* delete above created param infos */
476  for (index_t i=0; i<param_infos->get_num_elements(); ++i)
477  delete param_infos->get_element(i);
478 
479  delete param_infos;
480 
481  /* replace parameters by loaded and mapped */
482  SG_DEBUG("replacing parameter data by loaded/mapped values\n")
483  for (index_t i=0; i<m_parameters->get_num_parameters(); ++i)
484  {
486  char* s=SG_MALLOC(char, 200);
487  current->m_datatype.to_string(s, 200);
488  SG_DEBUG("processing \"%s\": %s\n", current->m_name, s)
489  SG_FREE(s);
490 
491  /* skip new parameters */
492  if (is_param_new(SGParamInfo(current, param_version)))
493  {
494  SG_DEBUG("%s is new, skipping\n", current->m_name)
495  continue;
496  }
497 
498  /* search for current parameter in mapped ones */
499  index_t index=CMath::binary_search(param_base->get_array(),
500  param_base->get_num_elements(), current);
501 
502  TParameter* migrated=param_base->get_element(index);
503 
504  /* now copy data from migrated TParameter instance
505  * (this automatically deletes the old data allocations) */
506  SG_DEBUG("copying migrated data into parameter\n")
507  current->copy_data(migrated);
508  }
509 
510  /* delete the migrated parameter data base */
511  SG_DEBUG("deleting old parameter base\n")
512  for (index_t i=0; i<param_base->get_num_elements(); ++i)
513  {
514  TParameter* current=param_base->get_element(i);
515  SG_DEBUG("deleting old \"%s\"\n", current->m_name)
516  delete current;
517  }
518  delete param_base;
519  }
520 
521  try
522  {
524  }
525  catch (ShogunException& e)
526  {
527  SG_SWARNING("%s%s::load_serializable_post(): ShogunException: "
528  "%s\n", prefix, get_name(),
530  return false;
531  }
532 
533  if (!m_load_post_called)
534  {
535  SG_SWARNING("%s%s::load_serializable_post(): Implementation "
536  "error: BASE_CLASS::LOAD_SERIALIZABLE_POST() not "
537  "called!\n", prefix, get_name());
538  return false;
539  }
540  SG_DEBUG("DONE LOADING CSGObject '%s' (%p)\n", get_name(), this)
541 
542  return true;
543 }
544 
546  const SGParamInfo* param_info, int32_t file_version,
547  CSerializableFile* file, const char* prefix)
548 {
549  /* ensure that recursion works */
550  SG_SDEBUG("entering %s::load_file_parameters\n", get_name())
551  if (file_version>param_info->m_param_version)
552  {
553  SG_SERROR("parameter version of \"%s\" in file (%d) is more recent than"
554  " provided %d!\n", param_info->m_name, file_version,
555  param_info->m_param_version);
556  }
557 
558  DynArray<TParameter*>* result_array=new DynArray<TParameter*>();
559 
560  /* do mapping */
561  char* s=param_info->to_string();
562  SG_SDEBUG("try to get mapping for: %s\n", s)
563  SG_FREE(s);
564 
565  /* mapping has only be deleted if was created here (no mapping was found) */
566  bool free_mapped=false;
567  DynArray<const SGParamInfo*>* mapped=m_parameter_map->get(param_info);
568  if (!mapped)
569  {
570  /* since a new mapped array will be created, set deletion flag */
571  free_mapped=true;
572  mapped=new DynArray<const SGParamInfo*>();
573 
574  /* if no mapping was found, nothing has changed. Simply create new param
575  * info with decreased version */
576  SG_SDEBUG("no mapping found\n")
577  if (file_version<param_info->m_param_version)
578  {
579  /* create new array and put param info with decreased version in */
580  mapped->append_element(new SGParamInfo(param_info->m_name,
581  param_info->m_ctype, param_info->m_stype,
582  param_info->m_ptype, param_info->m_param_version-1));
583 
584  SG_SDEBUG("using:\n")
585  for (index_t i=0; i<mapped->get_num_elements(); ++i)
586  {
587  s=mapped->get_element(i)->to_string();
588  SG_SDEBUG("\t%s\n", s)
589  SG_FREE(s);
590  }
591  }
592  else
593  {
594  /* create new array and put original param info in */
595  SG_SDEBUG("reached file version\n")
596  mapped->append_element(param_info->duplicate());
597  }
598  }
599  else
600  {
601  SG_SDEBUG("found:\n")
602  for (index_t i=0; i<mapped->get_num_elements(); ++i)
603  {
604  s=mapped->get_element(i)->to_string();
605  SG_SDEBUG("\t%s\n", s)
606  SG_FREE(s);
607  }
608  }
609 
610 
611  /* case file version same as provided version.
612  * means that parameters have to be loaded from file, recursion stops */
613  if (file_version==param_info->m_param_version)
614  {
615  SG_SDEBUG("recursion stop, loading from file\n")
616  /* load all parameters in mapping from file */
617  for (index_t i=0; i<mapped->get_num_elements(); ++i)
618  {
619  const SGParamInfo* current=mapped->get_element(i);
620  s=current->to_string();
621  SG_SDEBUG("loading %s\n", s)
622  SG_FREE(s);
623 
624  TParameter* loaded;
625  /* allocate memory for length and matrix/vector
626  * This has to be done because this stuff normally is in the class
627  * variables which do not exist in this case. Deletion is handled
628  * via the allocated_from_scratch flag of TParameter */
629 
630  /* create type and copy lengths, empty data for now */
631  TSGDataType type(current->m_ctype, current->m_stype,
632  current->m_ptype);
633  loaded=new TParameter(&type, NULL, current->m_name, "");
634 
635  /* allocate data/length variables for the TParameter, lengths are not
636  * important now, so set to one */
637  SGVector<index_t> dims(2);
638  dims[0]=1;
639  dims[1]=1;
640  loaded->allocate_data_from_scratch(dims);
641 
642  /* tell instance to load data from file */
643  if (!loaded->load(file, prefix))
644  {
645  s=param_info->to_string();
646  SG_ERROR("Could not load %s. The reason for this might be wrong "
647  "parameter mappings\n", s);
648  SG_FREE(s);
649  }
650 
651  SG_DEBUG("loaded lengths: y=%d, x=%d\n",
652  loaded->m_datatype.m_length_y ? *loaded->m_datatype.m_length_y : -1,
653  loaded->m_datatype.m_length_x ? *loaded->m_datatype.m_length_x : -1);
654 
655  /* append new TParameter to result array */
656  result_array->append_element(loaded);
657  }
658  SG_SDEBUG("done loading from file\n")
659  }
660  /* recursion with mapped type, a mapping exists in this case (ensured by
661  * above assert) */
662  else
663  {
664  /* for all elements in mapping, do recursion */
665  for (index_t i=0; i<mapped->get_num_elements(); ++i)
666  {
667  const SGParamInfo* current=mapped->get_element(i);
668  s=current->to_string();
669  SG_SDEBUG("starting recursion over %s\n", s)
670 
671  /* recursively get all file parameters for this parameter */
672  DynArray<TParameter*>* recursion_array=
673  load_file_parameters(current, file_version, file, prefix);
674 
675  SG_SDEBUG("recursion over %s done\n", s)
676  SG_FREE(s);
677 
678  /* append all recursion data to current array */
679  SG_SDEBUG("appending all results to current result\n")
680  for (index_t j=0; j<recursion_array->get_num_elements(); ++j)
681  result_array->append_element(recursion_array->get_element(j));
682 
683  /* clean up */
684  delete recursion_array;
685  }
686  }
687 
688  SG_SDEBUG("cleaning up old mapping \n")
689 
690 
691  /* clean up mapping */
692  if (free_mapped)
693  {
694  for (index_t i=0; i<mapped->get_num_elements(); ++i)
695  delete mapped->get_element(i);
696 
697  delete mapped;
698  }
699 
700  SG_SDEBUG("leaving %s::load_file_parameters\n", get_name())
701  return result_array;
702 }
703 
705  int32_t current_version, CSerializableFile* file, const char* prefix)
706 {
708 
709  for (index_t i=0; i<m_parameters->get_num_parameters(); ++i)
710  {
712 
713  /* extract current parameter info */
714  const SGParamInfo* info=new SGParamInfo(current, current_version);
715 
716  /* skip new parameters */
717  if (is_param_new(*info))
718  {
719  delete info;
720  continue;
721  }
722 
723  /* in the other case, load parameters data from file */
724  DynArray<TParameter*>* temp=load_file_parameters(info, file_version,
725  file, prefix);
726 
727  /* and append them all to array */
728  for (index_t j=0; j<temp->get_num_elements(); ++j)
729  result->append_element(temp->get_element(j));
730 
731  /* clean up */
732  delete temp;
733  delete info;
734  }
735 
736  /* sort array before returning */
737  CMath::qsort(result->get_array(), result->get_num_elements());
738 
739  return result;
740 }
741 
743  int32_t& base_version, DynArray<const SGParamInfo*>* target_param_infos)
744 {
745  SG_DEBUG("entering %s::map_parameters\n", get_name())
746  /* NOTE: currently the migration is done step by step over every version */
747 
748  if (!target_param_infos->get_num_elements())
749  {
750  SG_DEBUG("no target parameter infos\n")
751  SG_DEBUG("leaving %s::map_parameters\n", get_name())
752  return;
753  }
754 
755  /* map all target parameter infos once */
756  DynArray<const SGParamInfo*>* mapped_infos=
759  for (index_t i=0; i<target_param_infos->get_num_elements(); ++i)
760  {
761  const SGParamInfo* current=target_param_infos->get_element(i);
762 
763  char* s=current->to_string();
764  SG_DEBUG("trying to get parameter mapping for %s\n", s)
765  SG_FREE(s);
766 
768 
769  if (mapped)
770  {
771  mapped_infos->append_element(mapped->get_element(0));
772  for (index_t j=0; j<mapped->get_num_elements(); ++j)
773  {
774  s=mapped->get_element(j)->to_string();
775  SG_DEBUG("found mapping: %s\n", s)
776  SG_FREE(s);
777  }
778  }
779  else
780  {
781  /* these have to be deleted above */
782  SGParamInfo* no_change=new SGParamInfo(*current);
783  no_change->m_param_version--;
784  s=no_change->to_string();
785  SG_DEBUG("no mapping found, using %s\n", s)
786  SG_FREE(s);
787  mapped_infos->append_element(no_change);
788  to_delete->append_element(no_change);
789  }
790  }
791 
792  /* assert that at least one mapping exists */
793  ASSERT(mapped_infos->get_num_elements())
794  int32_t mapped_version=mapped_infos->get_element(0)->m_param_version;
795 
796  /* assert that all param versions are equal for now (if not empty param) */
797  for (index_t i=1; i<mapped_infos->get_num_elements(); ++i)
798  {
799  ASSERT(mapped_infos->get_element(i)->m_param_version==mapped_version ||
800  *mapped_infos->get_element(i)==SGParamInfo());
801  }
802 
803  /* recursion, after this call, base is at version of mapped infos */
804  if (mapped_version>base_version)
805  map_parameters(param_base, base_version, mapped_infos);
806 
807  /* delete mapped parameter infos array */
808  delete mapped_infos;
809 
810  /* delete newly created parameter infos which have to name or type change */
811  for (index_t i=0; i<to_delete->get_num_elements(); ++i)
812  delete to_delete->get_element(i);
813 
814  delete to_delete;
815 
816  ASSERT(base_version==mapped_version)
817 
818  /* do migration of one version step, create new base */
820  for (index_t i=0; i<target_param_infos->get_num_elements(); ++i)
821  {
822  char* s=target_param_infos->get_element(i)->to_string();
823  SG_DEBUG("migrating one step to target: %s\n", s)
824  SG_FREE(s);
825  TParameter* p=migrate(param_base, target_param_infos->get_element(i));
826  new_base->append_element(p);
827  }
828 
829  /* replace base by new base, delete old base, if it was created in migrate */
830  SG_DEBUG("deleting parameters base version %d\n", base_version)
831  for (index_t i=0; i<param_base->get_num_elements(); ++i)
832  delete param_base->get_element(i);
833 
834  SG_DEBUG("replacing old parameter base\n")
835  *param_base=*new_base;
836  base_version=mapped_version+1;
837 
838  SG_DEBUG("new parameter base of size %d:\n", param_base->get_num_elements())
839  for (index_t i=0; i<param_base->get_num_elements(); ++i)
840  {
841  TParameter* current=param_base->get_element(i);
842  TSGDataType type=current->m_datatype;
843  if (type.m_ptype==PT_SGOBJECT)
844  {
845  if (type.m_ctype==CT_SCALAR)
846  {
847  CSGObject* object=*(CSGObject**)current->m_parameter;
848  SG_DEBUG("(%d:) \"%s\": sgobject \"%s\" at %p\n", i,
849  current->m_name, object ? object->get_name() : "",
850  object);
851  }
852  else
853  {
854  index_t len=1;
855  len*=type.m_length_x ? *type.m_length_x : 1;
856  len*=type.m_length_y ? *type.m_length_y : 1;
857  CSGObject** array=*(CSGObject***)current->m_parameter;
858  for (index_t j=0; j<len; ++j)
859  {
860  CSGObject* object=array[j];
861  SG_DEBUG("(%d:) \"%s\": sgobject \"%s\" at %p\n", i,
862  current->m_name, object ? object->get_name() : "",
863  object);
864  }
865  }
866  }
867  else
868  {
869  char* s=SG_MALLOC(char, 200);
870  current->m_datatype.to_string(s, 200);
871  SG_DEBUG("(%d:) \"%s\": type: %s at %p\n", i, current->m_name, s,
872  current->m_parameter);
873  SG_FREE(s);
874  }
875  }
876 
877  /* because content was copied, new base may be deleted */
878  delete new_base;
879 
880  /* sort the just created new base */
881  SG_DEBUG("sorting base\n")
882  CMath::qsort(param_base->get_array(), param_base->get_num_elements());
883 
884  /* at this point the param_base is at the same version as the version of
885  * the provided parameter infos */
886  SG_DEBUG("leaving %s::map_parameters\n", get_name())
887 }
888 
890  const SGParamInfo* target, TParameter*& replacement,
891  TParameter*& to_migrate, char* old_name)
892 {
893  SG_DEBUG("CSGObject::entering CSGObject::one_to_one_migration_prepare() for "
894  "\"%s\"\n", target->m_name);
895 
896  /* generate type of target structure */
897  TSGDataType type(target->m_ctype, target->m_stype, target->m_ptype);
898 
899  /* first find index of needed data.
900  * in this case, element in base with same name or old name */
901  char* name=target->m_name;
902  if (old_name)
903  name=old_name;
904 
905  /* dummy for searching, search and save result in to_migrate parameter */
906  TParameter* t=new TParameter(&type, NULL, name, "");
907  index_t i=CMath::binary_search(param_base->get_array(),
908  param_base->get_num_elements(), t);
909  delete t;
910 
911  /* assert that something is found */
912  ASSERT(i>=0)
913  to_migrate=param_base->get_element(i);
914 
915  /* result structure, data NULL for now */
916  replacement=new TParameter(&type, NULL, target->m_name,
917  to_migrate->m_description);
918 
919  SGVector<index_t> dims(2);
920  dims[0]=1;
921  dims[1]=1;
922  /* allocate content to write into, lengths are needed for this */
923  if (to_migrate->m_datatype.m_length_x)
924  dims[0]=*to_migrate->m_datatype.m_length_x;
925 
926  if (to_migrate->m_datatype.m_length_y)
927  dims[1]=*to_migrate->m_datatype.m_length_y;
928 
929  replacement->allocate_data_from_scratch(dims);
930 
931  /* in case of sgobject, copy pointer data and SG_REF */
932  if (to_migrate->m_datatype.m_ptype==PT_SGOBJECT)
933  {
934  /* note that the memory is already allocated before the migrate call */
935  CSGObject* object=*((CSGObject**)to_migrate->m_parameter);
936  *((CSGObject**)replacement->m_parameter)=object;
937  SG_REF(object);
938  SG_DEBUG("copied and SG_REF sgobject pointer for \"%s\" at %p\n",
939  object->get_name(), object);
940  }
941 
942  /* tell the old TParameter to delete its data on deletion */
943  to_migrate->m_delete_data=true;
944 
945  SG_DEBUG("CSGObject::leaving CSGObject::one_to_one_migration_prepare() for "
946  "\"%s\"\n", target->m_name);
947 }
948 
950  const SGParamInfo* target)
951 {
952  SG_DEBUG("entering %s::migrate\n", get_name())
953  /* this is only executed, iff there was no migration method which handled
954  * migration to the provided target. In this case, it is assumed that the
955  * parameter simply has not changed. Verify this here and return copy of
956  * data in case its true.
957  * If not, throw an exception -- parameter migration HAS to be implemented
958  * by hand everytime, a parameter changes type or name. */
959 
960  TParameter* result=NULL;
961 
962  /* first find index of needed data.
963  * in this case, element in base with same name */
964  /* type is also needed */
965  TSGDataType type(target->m_ctype, target->m_stype,
966  target->m_ptype);
967 
968  /* dummy for searching, search and save result */
969  TParameter* t=new TParameter(&type, NULL, target->m_name, "");
970  index_t i=CMath::binary_search(param_base->get_array(),
971  param_base->get_num_elements(), t);
972  delete t;
973 
974  /* check if name change occurred while no migration method was specified */
975  if (i<0)
976  {
977  SG_ERROR("Name change for parameter that has to be mapped to \"%s\","
978  " and to no migration method available\n", target->m_name);
979  }
980 
981  TParameter* to_migrate=param_base->get_element(i);
982 
983  /* check if element in base is equal to target one */
984  if (*target==SGParamInfo(to_migrate, target->m_param_version))
985  {
986  char* s=SG_MALLOC(char, 200);
987  to_migrate->m_datatype.to_string(s, 200);
988  SG_DEBUG("nothing changed, using old data: %s\n", s)
989  SG_FREE(s);
990  result=new TParameter(&to_migrate->m_datatype, NULL, to_migrate->m_name,
991  to_migrate->m_description);
992 
993  SGVector<index_t> dims(2);
994  dims[0]=1;
995  dims[1]=1;
996  if (to_migrate->m_datatype.m_length_x)
997  dims[0]=*to_migrate->m_datatype.m_length_x;
998 
999  if (to_migrate->m_datatype.m_length_y)
1000  dims[1]=*to_migrate->m_datatype.m_length_y;
1001 
1002  /* allocate lengths and evtl scalar data but not non-scalar data (no
1003  * new_cont call */
1004  result->allocate_data_from_scratch(dims, false);
1005 
1006  /* now use old data */
1007  if (to_migrate->m_datatype.m_ctype==CT_SCALAR &&
1008  to_migrate->m_datatype.m_ptype!=PT_SGOBJECT)
1009  {
1010  /* copy data */
1011  SG_DEBUG("copying scalar data\n")
1012  memcpy(result->m_parameter,to_migrate->m_parameter,
1013  to_migrate->m_datatype.get_size());
1014  }
1015  else
1016  {
1017  /* copy content of pointer */
1018  SG_DEBUG("copying content of poitner for non-scalar data\n")
1019  *(void**)result->m_parameter=*(void**)(to_migrate->m_parameter);
1020  }
1021  }
1022  else
1023  {
1024  char* s=target->to_string();
1025  SG_ERROR("No migration method available for %s!\n", s)
1026  SG_FREE(s);
1027  }
1028 
1029  SG_DEBUG("leaving %s::migrate\n", get_name())
1030 
1031  return result;
1032 }
1033 
1034 bool CSGObject::save_parameter_version(CSerializableFile* file,
1035  const char* prefix, int32_t param_version)
1036 {
1037  TSGDataType t(CT_SCALAR, ST_NONE, PT_INT32);
1038  TParameter p(&t, &param_version, "version_parameter",
1039  "Version of parameters of this object");
1040  return p.save(file, prefix);
1041 }
1042 
1043 int32_t CSGObject::load_parameter_version(CSerializableFile* file,
1044  const char* prefix)
1045 {
1046  REQUIRE(file != NULL, "Serializable file object should be != NULL");
1047 
1048  TSGDataType t(CT_SCALAR, ST_NONE, PT_INT32);
1049  int32_t v;
1050  TParameter tp(&t, &v, "version_parameter", "");
1051  if (tp.load(file, prefix))
1052  return v;
1053  else
1054  return -1;
1055 }
1056 
1058 {
1059  m_load_pre_called = true;
1060 }
1061 
1063 {
1064  m_load_post_called = true;
1065 }
1066 
1068 {
1069  m_save_pre_called = true;
1070 }
1071 
1073 {
1074  m_save_post_called = true;
1075 }
1076 
1077 #ifdef TRACE_MEMORY_ALLOCS
1078 #include <shogun/lib/Map.h>
1079 extern CMap<void*, shogun::MemoryBlock>* sg_mallocs;
1080 #endif
1081 
1082 void CSGObject::init()
1083 {
1084 #ifdef TRACE_MEMORY_ALLOCS
1085  if (sg_mallocs)
1086  {
1087  int32_t idx=sg_mallocs->index_of(this);
1088  if (idx>-1)
1089  {
1090  MemoryBlock* b=sg_mallocs->get_element_ptr(idx);
1091  b->set_sgobject();
1092  }
1093  }
1094 #endif
1095 
1096  io = NULL;
1097  parallel = NULL;
1098  version = NULL;
1099  m_parameters = new Parameter();
1103  m_generic = PT_NOT_GENERIC;
1104  m_load_pre_called = false;
1105  m_load_post_called = false;
1106  m_save_pre_called = false;
1107  m_save_post_called = false;
1108  m_hash = 0;
1109 }
1110 
1112 {
1113  SG_PRINT("parameters available for model selection for %s:\n", get_name())
1114 
1116 
1117  if (!num_param)
1118  SG_PRINT("\tnone\n")
1119 
1120  for (index_t i=0; i<num_param; i++)
1121  {
1123  index_t l=200;
1124  char* type=SG_MALLOC(char, l);
1125  if (type)
1126  {
1127  current->m_datatype.to_string(type, l);
1128  SG_PRINT("\t%s (%s): %s\n", current->m_name, current->m_description,
1129  type);
1130  SG_FREE(type);
1131  }
1132  }
1133 }
1134 
1136 {
1138 
1139  SGStringList<char> result(num_param, -1);
1140 
1141  index_t max_string_length=-1;
1142 
1143  for (index_t i=0; i<num_param; i++)
1144  {
1146  index_t len=strlen(name);
1147  // +1 to have a zero terminated string
1148  result.strings[i]=SGString<char>(name, len+1);
1149 
1150  if (len>max_string_length)
1151  max_string_length=len;
1152  }
1153 
1154  result.max_string_length=max_string_length;
1155 
1156  return result;
1157 }
1158 
1159 char* CSGObject::get_modsel_param_descr(const char* param_name)
1160 {
1161  index_t index=get_modsel_param_index(param_name);
1162 
1163  if (index<0)
1164  {
1165  SG_ERROR("There is no model selection parameter called \"%s\" for %s",
1166  param_name, get_name());
1167  }
1168 
1170 }
1171 
1173 {
1174  /* use fact that names extracted from below method are in same order than
1175  * in m_model_selection_parameters variable */
1177 
1178  /* search for parameter with provided name */
1179  index_t index=-1;
1180  for (index_t i=0; i<names.num_strings; i++)
1181  {
1183  if (!strcmp(param_name, current->m_name))
1184  {
1185  index=i;
1186  break;
1187  }
1188  }
1189 
1190  return index;
1191 }
1192 
1193 bool CSGObject::is_param_new(const SGParamInfo param_info) const
1194 {
1195  /* check if parameter is new in this version (has empty mapping) */
1196  DynArray<const SGParamInfo*>* value=m_parameter_map->get(&param_info);
1197  bool result=value && *value->get_element(0) == SGParamInfo();
1198 
1199  return result;
1200 }
1201 
1202 void CSGObject::get_parameter_incremental_hash(uint32_t& hash, uint32_t& carry,
1203  uint32_t& total_length)
1204 {
1205  for (index_t i=0; i<m_parameters->get_num_parameters(); i++)
1206  {
1208 
1209  SG_DEBUG("Updating hash for parameter %s.%s\n", get_name(), p->m_name);
1210 
1211  if (p->m_datatype.m_ptype == PT_SGOBJECT)
1212  {
1213  if (p->m_datatype.m_ctype == CT_SCALAR)
1214  {
1215  CSGObject* child = *((CSGObject**)(p->m_parameter));
1216 
1217  if (child)
1218  {
1219  child->get_parameter_incremental_hash(hash, carry,
1220  total_length);
1221  }
1222  }
1223  else if (p->m_datatype.m_ctype==CT_VECTOR ||
1224  p->m_datatype.m_ctype==CT_SGVECTOR)
1225  {
1226  CSGObject** child=(*(CSGObject***)(p->m_parameter));
1227 
1228  for (index_t j=0; j<*(p->m_datatype.m_length_y); j++)
1229  {
1230  if (child[j])
1231  {
1232  child[j]->get_parameter_incremental_hash(hash, carry,
1233  total_length);
1234  }
1235  }
1236  }
1237  }
1238  else
1239  p->get_incremental_hash(hash, carry, total_length);
1240  }
1241 }
1242 
1244 {
1245  for (index_t i=0; i<m_gradient_parameters->get_num_parameters(); i++)
1246  {
1248  dict->add(p, this);
1249  }
1250 
1252  {
1254  CSGObject* child=*(CSGObject**)(p->m_parameter);
1255 
1256  if ((p->m_datatype.m_ptype == PT_SGOBJECT) &&
1257  (p->m_datatype.m_ctype == CT_SCALAR) && child)
1258  {
1260  }
1261  }
1262 }
1263 
1264 bool CSGObject::equals(CSGObject* other, float64_t accuracy, bool tolerant)
1265 {
1266  SG_DEBUG("entering %s::equals()\n", get_name());
1267 
1268  if (other==this)
1269  {
1270  SG_DEBUG("leaving %s::equals(): other object is me\n", get_name());
1271  return true;
1272  }
1273 
1274  if (!other)
1275  {
1276  SG_DEBUG("leaving %s::equals(): other object is NULL\n", get_name());
1277  return false;
1278  }
1279 
1280  SG_DEBUG("comparing \"%s\" to \"%s\"\n", get_name(), other->get_name());
1281 
1282  /* a crude type check based on the get_name */
1283  if (strcmp(other->get_name(), get_name()))
1284  {
1285  SG_INFO("leaving %s::equals(): name of other object differs\n", get_name());
1286  return false;
1287  }
1288 
1289  /* should not be necessary but just ot be sure that type has not changed.
1290  * Will assume that parameters are in same order with same name from here */
1292  {
1293  SG_INFO("leaving %s::equals(): number of parameters of other object "
1294  "differs\n", get_name());
1295  return false;
1296  }
1297 
1298  for (index_t i=0; i<m_parameters->get_num_parameters(); ++i)
1299  {
1300  SG_DEBUG("comparing parameter %d\n", i);
1301 
1302  TParameter* this_param=m_parameters->get_parameter(i);
1303  TParameter* other_param=other->m_parameters->get_parameter(i);
1304 
1305  /* some checks to make sure parameters have same order and names and
1306  * are not NULL. Should never be the case but check anyway. */
1307  if (!this_param && !other_param)
1308  continue;
1309 
1310  if (!this_param && other_param)
1311  {
1312  SG_DEBUG("leaving %s::equals(): parameter %d is NULL where other's "
1313  "parameter \"%s\" is not\n", get_name(), other_param->m_name);
1314  return false;
1315  }
1316 
1317  if (this_param && !other_param)
1318  {
1319  SG_DEBUG("leaving %s::equals(): parameter %d is \"%s\" where other's "
1320  "parameter is NULL\n", get_name(), this_param->m_name);
1321  return false;
1322  }
1323 
1324  SG_DEBUG("comparing parameter \"%s\" to other's \"%s\"\n",
1325  this_param->m_name, other_param->m_name);
1326 
1327  /* hard-wired exception for DynamicObjectArray parameter num_elements */
1328  if (!strcmp("DynamicObjectArray", get_name()) &&
1329  !strcmp(this_param->m_name, "num_elements") &&
1330  !strcmp(other_param->m_name, "num_elements"))
1331  {
1332  SG_DEBUG("Ignoring DynamicObjectArray::num_elements field\n");
1333  continue;
1334  }
1335 
1336  /* hard-wired exception for DynamicArray parameter num_elements */
1337  if (!strcmp("DynamicArray", get_name()) &&
1338  !strcmp(this_param->m_name, "num_elements") &&
1339  !strcmp(other_param->m_name, "num_elements"))
1340  {
1341  SG_DEBUG("Ignoring DynamicArray::num_elements field\n");
1342  continue;
1343  }
1344 
1345  /* use equals method of TParameter from here */
1346  if (!this_param->equals(other_param, accuracy, tolerant))
1347  {
1348  SG_INFO("leaving %s::equals(): parameters at position %d with name"
1349  " \"%s\" differs from other object parameter with name "
1350  "\"%s\"\n",
1351  get_name(), i, this_param->m_name, other_param->m_name);
1352  return false;
1353  }
1354  }
1355 
1356  SG_DEBUG("leaving %s::equals(): object are equal\n", get_name());
1357  return true;
1358 }
1359 
1361 {
1362  SG_DEBUG("entering %s::clone()\n", get_name());
1363 
1364  SG_DEBUG("constructing an empty instance of %s\n", get_name());
1365  CSGObject* copy=new_sgserializable(get_name(), this->m_generic);
1366 
1367  SG_REF(copy);
1368 
1369  REQUIRE(copy, "Could not create empty instance of \"%s\". The reason for "
1370  "this usually is that get_name() of the class returns something "
1371  "wrong, or that a class has a wrongly set generic type.\n",
1372  get_name());
1373 
1374  for (index_t i=0; i<m_parameters->get_num_parameters(); ++i)
1375  {
1376  SG_DEBUG("cloning parameter \"%s\" at index %d\n",
1378 
1380  {
1381  SG_DEBUG("leaving %s::clone(): Clone failed. Returning NULL\n",
1382  get_name());
1383  return NULL;
1384  }
1385  }
1386 
1387  SG_DEBUG("leaving %s::clone(): Clone successful\n", get_name());
1388  return copy;
1389 }

SHOGUN Machine Learning Toolbox - Documentation