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

SHOGUN Machine Learning Toolbox - Documentation