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 "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::LOAD_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::LOAD_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  SG_DEBUG("START LOADING CSGObject '%s'\n", get_name())
324  try
325  {
327  }
328  catch (ShogunException& e)
329  {
330  SG_SWARNING("%s%s::load_serializable_pre(): ShogunException: "
331  "%s\n", prefix, get_name(),
333  return false;
334  }
335  if (!m_load_pre_called)
336  {
337  SG_SWARNING("%s%s::load_serializable_pre(): Implementation "
338  "error: BASE_CLASS::LOAD_SERIALIZABLE_PRE() not "
339  "called!\n", prefix, get_name());
340  return false;
341  }
342 
343  /* try to load version of parameters */
344  int32_t file_version=load_parameter_version(file, prefix);
345  SG_DEBUG("file_version=%d, current_version=%d\n", file_version, param_version)
346 
347  if (file_version<0)
348  {
349  SG_WARNING("%s%s::load_serializable(): File contains no parameter "
350  "version. Seems like your file is from the days before this "
351  "was introduced. Ignore warning or serialize with this version "
352  "of shogun to get rid of above and this warnings.\n",
353  prefix, get_name());
354  }
355 
356  if (file_version>param_version)
357  {
358  if (param_version==Version::get_version_parameter())
359  {
360  SG_WARNING("%s%s::load_serializable(): parameter version of file "
361  "larger than the one of shogun. Try with a more recent"
362  "version of shogun.\n", prefix, get_name());
363  }
364  else
365  {
366  SG_WARNING("%s%s::load_serializable(): parameter version of file "
367  "larger than the current. This is probably an implementation"
368  " error.\n", prefix, get_name());
369  }
370  return false;
371  }
372 
373  if (file_version==param_version)
374  {
375  /* load normally if file has current version */
376  SG_DEBUG("loading normally\n")
377 
378  /* load all parameters, except new ones */
379  for (int32_t i=0; i<m_parameters->get_num_parameters(); i++)
380  {
382 
383  /* skip new parameters */
384  if (is_param_new(SGParamInfo(current, param_version)))
385  continue;
386 
387  if (!current->load(file, prefix))
388  return false;
389  }
390  }
391  else
392  {
393  /* load all parameters from file, mappings to current version */
394  DynArray<TParameter*>* param_base=load_all_file_parameters(file_version,
395  param_version, file, prefix);
396 
397  /* create an array of param infos from current parameters */
398  DynArray<const SGParamInfo*>* param_infos=
400  for (index_t i=0; i<m_parameters->get_num_parameters(); ++i)
401  {
403 
404  /* skip new parameters */
405  if (is_param_new(SGParamInfo(current, param_version)))
406  continue;
407 
408  param_infos->append_element(
409  new SGParamInfo(current, param_version));
410  }
411 
412  /* map all parameters, result may be empty if input is */
413  map_parameters(param_base, file_version, param_infos);
414  SG_DEBUG("mapping is done!\n")
415 
416  /* this is assumed now, mapping worked or no parameters in base */
417  ASSERT(file_version==param_version || !param_base->get_num_elements())
418 
419  /* delete above created param infos */
420  for (index_t i=0; i<param_infos->get_num_elements(); ++i)
421  delete param_infos->get_element(i);
422 
423  delete param_infos;
424 
425  /* replace parameters by loaded and mapped */
426  SG_DEBUG("replacing parameter data by loaded/mapped values\n")
427  for (index_t i=0; i<m_parameters->get_num_parameters(); ++i)
428  {
430  char* s=SG_MALLOC(char, 200);
431  current->m_datatype.to_string(s, 200);
432  SG_DEBUG("processing \"%s\": %s\n", current->m_name, s)
433  SG_FREE(s);
434 
435  /* skip new parameters */
436  if (is_param_new(SGParamInfo(current, param_version)))
437  {
438  SG_DEBUG("%s is new, skipping\n", current->m_name)
439  continue;
440  }
441 
442  /* search for current parameter in mapped ones */
443  index_t index=CMath::binary_search(param_base->get_array(),
444  param_base->get_num_elements(), current);
445 
446  TParameter* migrated=param_base->get_element(index);
447 
448  /* now copy data from migrated TParameter instance
449  * (this automatically deletes the old data allocations) */
450  SG_DEBUG("copying migrated data into parameter\n")
451  current->copy_data(migrated);
452  }
453 
454  /* delete the migrated parameter data base */
455  SG_DEBUG("deleting old parameter base\n")
456  for (index_t i=0; i<param_base->get_num_elements(); ++i)
457  {
458  TParameter* current=param_base->get_element(i);
459  SG_DEBUG("deleting old \"%s\"\n", current->m_name)
460  delete current;
461  }
462  delete param_base;
463  }
464 
465  try
466  {
468  }
469  catch (ShogunException& e)
470  {
471  SG_SWARNING("%s%s::load_serializable_post(): ShogunException: "
472  "%s\n", prefix, get_name(),
474  return false;
475  }
476 
477  if (!m_load_post_called)
478  {
479  SG_SWARNING("%s%s::load_serializable_post(): Implementation "
480  "error: BASE_CLASS::LOAD_SERIALIZABLE_POST() not "
481  "called!\n", prefix, get_name());
482  return false;
483  }
484  SG_DEBUG("DONE LOADING CSGObject '%s' (%p)\n", get_name(), this)
485 
486  return true;
487 }
488 
490  const SGParamInfo* param_info, int32_t file_version,
491  CSerializableFile* file, const char* prefix)
492 {
493  /* ensure that recursion works */
494  SG_SDEBUG("entering %s::load_file_parameters\n", get_name())
495  if (file_version>param_info->m_param_version)
496  {
497  SG_SERROR("parameter version of \"%s\" in file (%d) is more recent than"
498  " provided %d!\n", param_info->m_name, file_version,
499  param_info->m_param_version);
500  }
501 
502  DynArray<TParameter*>* result_array=new DynArray<TParameter*>();
503 
504  /* do mapping */
505  char* s=param_info->to_string();
506  SG_SDEBUG("try to get mapping for: %s\n", s)
507  SG_FREE(s);
508 
509  /* mapping has only be deleted if was created here (no mapping was found) */
510  bool free_mapped=false;
511  DynArray<const SGParamInfo*>* mapped=m_parameter_map->get(param_info);
512  if (!mapped)
513  {
514  /* since a new mapped array will be created, set deletion flag */
515  free_mapped=true;
516  mapped=new DynArray<const SGParamInfo*>();
517 
518  /* if no mapping was found, nothing has changed. Simply create new param
519  * info with decreased version */
520  SG_SDEBUG("no mapping found\n")
521  if (file_version<param_info->m_param_version)
522  {
523  /* create new array and put param info with decreased version in */
524  mapped->append_element(new SGParamInfo(param_info->m_name,
525  param_info->m_ctype, param_info->m_stype,
526  param_info->m_ptype, param_info->m_param_version-1));
527 
528  SG_SDEBUG("using:\n")
529  for (index_t i=0; i<mapped->get_num_elements(); ++i)
530  {
531  s=mapped->get_element(i)->to_string();
532  SG_SDEBUG("\t%s\n", s)
533  SG_FREE(s);
534  }
535  }
536  else
537  {
538  /* create new array and put original param info in */
539  SG_SDEBUG("reached file version\n")
540  mapped->append_element(param_info->duplicate());
541  }
542  }
543  else
544  {
545  SG_SDEBUG("found:\n")
546  for (index_t i=0; i<mapped->get_num_elements(); ++i)
547  {
548  s=mapped->get_element(i)->to_string();
549  SG_SDEBUG("\t%s\n", s)
550  SG_FREE(s);
551  }
552  }
553 
554 
555  /* case file version same as provided version.
556  * means that parameters have to be loaded from file, recursion stops */
557  if (file_version==param_info->m_param_version)
558  {
559  SG_SDEBUG("recursion stop, loading from file\n")
560  /* load all parameters in mapping from file */
561  for (index_t i=0; i<mapped->get_num_elements(); ++i)
562  {
563  const SGParamInfo* current=mapped->get_element(i);
564  s=current->to_string();
565  SG_SDEBUG("loading %s\n", s)
566  SG_FREE(s);
567 
568  TParameter* loaded;
569  /* allocate memory for length and matrix/vector
570  * This has to be done because this stuff normally is in the class
571  * variables which do not exist in this case. Deletion is handled
572  * via the allocated_from_scratch flag of TParameter */
573 
574  /* create type and copy lengths, empty data for now */
575  TSGDataType type(current->m_ctype, current->m_stype,
576  current->m_ptype);
577  loaded=new TParameter(&type, NULL, current->m_name, "");
578 
579  /* allocate data/length variables for the TParameter, lengths are not
580  * important now, so set to one */
581  SGVector<index_t> dims(2);
582  dims[0]=1;
583  dims[1]=1;
584  loaded->allocate_data_from_scratch(dims);
585 
586  /* tell instance to load data from file */
587  if (!loaded->load(file, prefix))
588  {
589  s=param_info->to_string();
590  SG_ERROR("Could not load %s. The reason for this might be wrong "
591  "parameter mappings\n", s);
592  SG_FREE(s);
593  }
594 
595  SG_DEBUG("loaded lengths: y=%d, x=%d\n",
596  loaded->m_datatype.m_length_y ? *loaded->m_datatype.m_length_y : -1,
597  loaded->m_datatype.m_length_x ? *loaded->m_datatype.m_length_x : -1);
598 
599  /* append new TParameter to result array */
600  result_array->append_element(loaded);
601  }
602  SG_SDEBUG("done loading from file\n")
603  }
604  /* recursion with mapped type, a mapping exists in this case (ensured by
605  * above assert) */
606  else
607  {
608  /* for all elements in mapping, do recursion */
609  for (index_t i=0; i<mapped->get_num_elements(); ++i)
610  {
611  const SGParamInfo* current=mapped->get_element(i);
612  s=current->to_string();
613  SG_SDEBUG("starting recursion over %s\n", s)
614 
615  /* recursively get all file parameters for this parameter */
616  DynArray<TParameter*>* recursion_array=
617  load_file_parameters(current, file_version, file, prefix);
618 
619  SG_SDEBUG("recursion over %s done\n", s)
620  SG_FREE(s);
621 
622  /* append all recursion data to current array */
623  SG_SDEBUG("appending all results to current result\n")
624  for (index_t j=0; j<recursion_array->get_num_elements(); ++j)
625  result_array->append_element(recursion_array->get_element(j));
626 
627  /* clean up */
628  delete recursion_array;
629  }
630  }
631 
632  SG_SDEBUG("cleaning up old mapping \n")
633 
634 
635  /* clean up mapping */
636  if (free_mapped)
637  {
638  for (index_t i=0; i<mapped->get_num_elements(); ++i)
639  delete mapped->get_element(i);
640 
641  delete mapped;
642  }
643 
644  SG_SDEBUG("leaving %s::load_file_parameters\n", get_name())
645  return result_array;
646 }
647 
649  int32_t current_version, CSerializableFile* file, const char* prefix)
650 {
652 
653  for (index_t i=0; i<m_parameters->get_num_parameters(); ++i)
654  {
656 
657  /* extract current parameter info */
658  const SGParamInfo* info=new SGParamInfo(current, current_version);
659 
660  /* skip new parameters */
661  if (is_param_new(*info))
662  {
663  delete info;
664  continue;
665  }
666 
667  /* in the other case, load parameters data from file */
668  DynArray<TParameter*>* temp=load_file_parameters(info, file_version,
669  file, prefix);
670 
671  /* and append them all to array */
672  for (index_t j=0; j<temp->get_num_elements(); ++j)
673  result->append_element(temp->get_element(j));
674 
675  /* clean up */
676  delete temp;
677  delete info;
678  }
679 
680  /* sort array before returning */
681  CMath::qsort(result->get_array(), result->get_num_elements());
682 
683  return result;
684 }
685 
687  int32_t& base_version, DynArray<const SGParamInfo*>* target_param_infos)
688 {
689  SG_DEBUG("entering %s::map_parameters\n", get_name())
690  /* NOTE: currently the migration is done step by step over every version */
691 
692  if (!target_param_infos->get_num_elements())
693  {
694  SG_DEBUG("no target parameter infos\n")
695  SG_DEBUG("leaving %s::map_parameters\n", get_name())
696  return;
697  }
698 
699  /* map all target parameter infos once */
700  DynArray<const SGParamInfo*>* mapped_infos=
703  for (index_t i=0; i<target_param_infos->get_num_elements(); ++i)
704  {
705  const SGParamInfo* current=target_param_infos->get_element(i);
706 
707  char* s=current->to_string();
708  SG_DEBUG("trying to get parameter mapping for %s\n", s)
709  SG_FREE(s);
710 
712 
713  if (mapped)
714  {
715  mapped_infos->append_element(mapped->get_element(0));
716  for (index_t j=0; j<mapped->get_num_elements(); ++j)
717  {
718  s=mapped->get_element(j)->to_string();
719  SG_DEBUG("found mapping: %s\n", s)
720  SG_FREE(s);
721  }
722  }
723  else
724  {
725  /* these have to be deleted above */
726  SGParamInfo* no_change=new SGParamInfo(*current);
727  no_change->m_param_version--;
728  s=no_change->to_string();
729  SG_DEBUG("no mapping found, using %s\n", s)
730  SG_FREE(s);
731  mapped_infos->append_element(no_change);
732  to_delete->append_element(no_change);
733  }
734  }
735 
736  /* assert that at least one mapping exists */
737  ASSERT(mapped_infos->get_num_elements())
738  int32_t mapped_version=mapped_infos->get_element(0)->m_param_version;
739 
740  /* assert that all param versions are equal for now (if not empty param) */
741  for (index_t i=1; i<mapped_infos->get_num_elements(); ++i)
742  {
743  ASSERT(mapped_infos->get_element(i)->m_param_version==mapped_version ||
744  *mapped_infos->get_element(i)==SGParamInfo());
745  }
746 
747  /* recursion, after this call, base is at version of mapped infos */
748  if (mapped_version>base_version)
749  map_parameters(param_base, base_version, mapped_infos);
750 
751  /* delete mapped parameter infos array */
752  delete mapped_infos;
753 
754  /* delete newly created parameter infos which have to name or type change */
755  for (index_t i=0; i<to_delete->get_num_elements(); ++i)
756  delete to_delete->get_element(i);
757 
758  delete to_delete;
759 
760  ASSERT(base_version==mapped_version)
761 
762  /* do migration of one version step, create new base */
764  for (index_t i=0; i<target_param_infos->get_num_elements(); ++i)
765  {
766  char* s=target_param_infos->get_element(i)->to_string();
767  SG_DEBUG("migrating one step to target: %s\n", s)
768  SG_FREE(s);
769  TParameter* p=migrate(param_base, target_param_infos->get_element(i));
770  new_base->append_element(p);
771  }
772 
773  /* replace base by new base, delete old base, if it was created in migrate */
774  SG_DEBUG("deleting parameters base version %d\n", base_version)
775  for (index_t i=0; i<param_base->get_num_elements(); ++i)
776  delete param_base->get_element(i);
777 
778  SG_DEBUG("replacing old parameter base\n")
779  *param_base=*new_base;
780  base_version=mapped_version+1;
781 
782  SG_DEBUG("new parameter base of size %d:\n", param_base->get_num_elements())
783  for (index_t i=0; i<param_base->get_num_elements(); ++i)
784  {
785  TParameter* current=param_base->get_element(i);
786  TSGDataType type=current->m_datatype;
787  if (type.m_ptype==PT_SGOBJECT)
788  {
789  if (type.m_ctype==CT_SCALAR)
790  {
791  CSGObject* object=*(CSGObject**)current->m_parameter;
792  SG_DEBUG("(%d:) \"%s\": sgobject \"%s\" at %p\n", i,
793  current->m_name, object ? object->get_name() : "",
794  object);
795  }
796  else
797  {
798  index_t len=1;
799  len*=type.m_length_x ? *type.m_length_x : 1;
800  len*=type.m_length_y ? *type.m_length_y : 1;
801  CSGObject** array=*(CSGObject***)current->m_parameter;
802  for (index_t j=0; j<len; ++j)
803  {
804  CSGObject* object=array[j];
805  SG_DEBUG("(%d:) \"%s\": sgobject \"%s\" at %p\n", i,
806  current->m_name, object ? object->get_name() : "",
807  object);
808  }
809  }
810  }
811  else
812  {
813  char* s=SG_MALLOC(char, 200);
814  current->m_datatype.to_string(s, 200);
815  SG_DEBUG("(%d:) \"%s\": type: %s at %p\n", i, current->m_name, s,
816  current->m_parameter);
817  SG_FREE(s);
818  }
819  }
820 
821  /* because content was copied, new base may be deleted */
822  delete new_base;
823 
824  /* sort the just created new base */
825  SG_DEBUG("sorting base\n")
826  CMath::qsort(param_base->get_array(), param_base->get_num_elements());
827 
828  /* at this point the param_base is at the same version as the version of
829  * the provided parameter infos */
830  SG_DEBUG("leaving %s::map_parameters\n", get_name())
831 }
832 
834  const SGParamInfo* target, TParameter*& replacement,
835  TParameter*& to_migrate, char* old_name)
836 {
837  SG_DEBUG("CSGObject::entering CSGObject::one_to_one_migration_prepare() for "
838  "\"%s\"\n", target->m_name);
839 
840  /* generate type of target structure */
841  TSGDataType type(target->m_ctype, target->m_stype, target->m_ptype);
842 
843  /* first find index of needed data.
844  * in this case, element in base with same name or old name */
845  char* name=target->m_name;
846  if (old_name)
847  name=old_name;
848 
849  /* dummy for searching, search and save result in to_migrate parameter */
850  TParameter* t=new TParameter(&type, NULL, name, "");
851  index_t i=CMath::binary_search(param_base->get_array(),
852  param_base->get_num_elements(), t);
853  delete t;
854 
855  /* assert that something is found */
856  ASSERT(i>=0)
857  to_migrate=param_base->get_element(i);
858 
859  /* result structure, data NULL for now */
860  replacement=new TParameter(&type, NULL, target->m_name,
861  to_migrate->m_description);
862 
863  SGVector<index_t> dims(2);
864  dims[0]=1;
865  dims[1]=1;
866  /* allocate content to write into, lengths are needed for this */
867  if (to_migrate->m_datatype.m_length_x)
868  dims[0]=*to_migrate->m_datatype.m_length_x;
869 
870  if (to_migrate->m_datatype.m_length_y)
871  dims[1]=*to_migrate->m_datatype.m_length_y;
872 
873  replacement->allocate_data_from_scratch(dims);
874 
875  /* in case of sgobject, copy pointer data and SG_REF */
876  if (to_migrate->m_datatype.m_ptype==PT_SGOBJECT)
877  {
878  /* note that the memory is already allocated before the migrate call */
879  CSGObject* object=*((CSGObject**)to_migrate->m_parameter);
880  *((CSGObject**)replacement->m_parameter)=object;
881  SG_REF(object);
882  SG_DEBUG("copied and SG_REF sgobject pointer for \"%s\" at %p\n",
883  object->get_name(), object);
884  }
885 
886  /* tell the old TParameter to delete its data on deletion */
887  to_migrate->m_delete_data=true;
888 
889  SG_DEBUG("CSGObject::leaving CSGObject::one_to_one_migration_prepare() for "
890  "\"%s\"\n", target->m_name);
891 }
892 
894  const SGParamInfo* target)
895 {
896  SG_DEBUG("entering %s::migrate\n", get_name())
897  /* this is only executed, iff there was no migration method which handled
898  * migration to the provided target. In this case, it is assumed that the
899  * parameter simply has not changed. Verify this here and return copy of
900  * data in case its true.
901  * If not, throw an exception -- parameter migration HAS to be implemented
902  * by hand everytime, a parameter changes type or name. */
903 
904  TParameter* result=NULL;
905 
906  /* first find index of needed data.
907  * in this case, element in base with same name */
908  /* type is also needed */
909  TSGDataType type(target->m_ctype, target->m_stype,
910  target->m_ptype);
911 
912  /* dummy for searching, search and save result */
913  TParameter* t=new TParameter(&type, NULL, target->m_name, "");
914  index_t i=CMath::binary_search(param_base->get_array(),
915  param_base->get_num_elements(), t);
916  delete t;
917 
918  /* check if name change occurred while no migration method was specified */
919  if (i<0)
920  {
921  SG_ERROR("Name change for parameter that has to be mapped to \"%s\","
922  " and to no migration method available\n", target->m_name);
923  }
924 
925  TParameter* to_migrate=param_base->get_element(i);
926 
927  /* check if element in base is equal to target one */
928  if (*target==SGParamInfo(to_migrate, target->m_param_version))
929  {
930  char* s=SG_MALLOC(char, 200);
931  to_migrate->m_datatype.to_string(s, 200);
932  SG_DEBUG("nothing changed, using old data: %s\n", s)
933  SG_FREE(s);
934  result=new TParameter(&to_migrate->m_datatype, NULL, to_migrate->m_name,
935  to_migrate->m_description);
936 
937  SGVector<index_t> dims(2);
938  dims[0]=1;
939  dims[1]=1;
940  if (to_migrate->m_datatype.m_length_x)
941  dims[0]=*to_migrate->m_datatype.m_length_x;
942 
943  if (to_migrate->m_datatype.m_length_y)
944  dims[1]=*to_migrate->m_datatype.m_length_y;
945 
946  /* allocate lengths and evtl scalar data but not non-scalar data (no
947  * new_cont call */
948  result->allocate_data_from_scratch(dims, false);
949 
950  /* now use old data */
951  if (to_migrate->m_datatype.m_ctype==CT_SCALAR &&
952  to_migrate->m_datatype.m_ptype!=PT_SGOBJECT)
953  {
954  /* copy data */
955  SG_DEBUG("copying scalar data\n")
956  memcpy(result->m_parameter,to_migrate->m_parameter,
957  to_migrate->m_datatype.get_size());
958  }
959  else
960  {
961  /* copy content of pointer */
962  SG_DEBUG("copying content of poitner for non-scalar data\n")
963  *(void**)result->m_parameter=*(void**)(to_migrate->m_parameter);
964  }
965  }
966  else
967  {
968  char* s=target->to_string();
969  SG_ERROR("No migration method available for %s!\n", s)
970  SG_FREE(s);
971  }
972 
973  SG_DEBUG("leaving %s::migrate\n", get_name())
974 
975  return result;
976 }
977 
978 bool CSGObject::save_parameter_version(CSerializableFile* file,
979  const char* prefix, int32_t param_version)
980 {
981  TSGDataType t(CT_SCALAR, ST_NONE, PT_INT32);
982  TParameter p(&t, &param_version, "version_parameter",
983  "Version of parameters of this object");
984  return p.save(file, prefix);
985 }
986 
987 int32_t CSGObject::load_parameter_version(CSerializableFile* file,
988  const char* prefix)
989 {
990  TSGDataType t(CT_SCALAR, ST_NONE, PT_INT32);
991  int32_t v;
992  TParameter tp(&t, &v, "version_parameter", "");
993  if (tp.load(file, prefix))
994  return v;
995  else
996  return -1;
997 }
998 
1000 {
1001  m_load_pre_called = true;
1002 }
1003 
1005 {
1006  m_load_post_called = true;
1007 }
1008 
1010 {
1011  m_save_pre_called = true;
1012 }
1013 
1015 {
1016  m_save_post_called = true;
1017 }
1018 
1019 #ifdef TRACE_MEMORY_ALLOCS
1020 #include <shogun/lib/Map.h>
1021 extern CMap<void*, shogun::MemoryBlock>* sg_mallocs;
1022 #endif
1023 
1024 void CSGObject::init()
1025 {
1026 #ifdef TRACE_MEMORY_ALLOCS
1027  if (sg_mallocs)
1028  {
1029  int32_t idx=sg_mallocs->index_of(this);
1030  if (idx>-1)
1031  {
1032  MemoryBlock* b=sg_mallocs->get_element_ptr(idx);
1033  b->set_sgobject();
1034  }
1035  }
1036 #endif
1037 
1038  io = NULL;
1039  parallel = NULL;
1040  version = NULL;
1041  m_parameters = new Parameter();
1045  m_generic = PT_NOT_GENERIC;
1046  m_load_pre_called = false;
1047  m_load_post_called = false;
1048  m_save_pre_called = false;
1049  m_save_post_called = false;
1050  m_hash = 0;
1051 }
1052 
1054 {
1055  SG_PRINT("parameters available for model selection for %s:\n", get_name())
1056 
1058 
1059  if (!num_param)
1060  SG_PRINT("\tnone\n")
1061 
1062  for (index_t i=0; i<num_param; i++)
1063  {
1065  index_t l=200;
1066  char* type=SG_MALLOC(char, l);
1067  if (type)
1068  {
1069  current->m_datatype.to_string(type, l);
1070  SG_PRINT("\t%s (%s): %s\n", current->m_name, current->m_description,
1071  type);
1072  SG_FREE(type);
1073  }
1074  }
1075 }
1076 
1078 {
1080 
1081  SGStringList<char> result(num_param, -1);
1082 
1083  index_t max_string_length=-1;
1084 
1085  for (index_t i=0; i<num_param; i++)
1086  {
1088  index_t len=strlen(name);
1089  // +1 to have a zero terminated string
1090  result.strings[i]=SGString<char>(name, len+1);
1091 
1092  if (len>max_string_length)
1093  max_string_length=len;
1094  }
1095 
1096  result.max_string_length=max_string_length;
1097 
1098  return result;
1099 }
1100 
1101 char* CSGObject::get_modsel_param_descr(const char* param_name)
1102 {
1103  index_t index=get_modsel_param_index(param_name);
1104 
1105  if (index<0)
1106  {
1107  SG_ERROR("There is no model selection parameter called \"%s\" for %s",
1108  param_name, get_name());
1109  }
1110 
1112 }
1113 
1115 {
1116  /* use fact that names extracted from below method are in same order than
1117  * in m_model_selection_parameters variable */
1119 
1120  /* search for parameter with provided name */
1121  index_t index=-1;
1122  for (index_t i=0; i<names.num_strings; i++)
1123  {
1125  if (!strcmp(param_name, current->m_name))
1126  {
1127  index=i;
1128  break;
1129  }
1130  }
1131 
1132  return index;
1133 }
1134 
1135 bool CSGObject::is_param_new(const SGParamInfo param_info) const
1136 {
1137  /* check if parameter is new in this version (has empty mapping) */
1138  DynArray<const SGParamInfo*>* value=m_parameter_map->get(&param_info);
1139  bool result=value && *value->get_element(0) == SGParamInfo();
1140 
1141  return result;
1142 }
1143 
1144 void CSGObject::get_parameter_incremental_hash(uint32_t& hash, uint32_t& carry,
1145  uint32_t& total_length)
1146 {
1147  for (index_t i=0; i<m_parameters->get_num_parameters(); i++)
1148  {
1150 
1151  SG_DEBUG("Updating hash for parameter %s.%s\n", get_name(), p->m_name);
1152 
1153  if (p->m_datatype.m_ptype == PT_SGOBJECT)
1154  {
1155  if (p->m_datatype.m_ctype == CT_SCALAR)
1156  {
1157  CSGObject* child = *((CSGObject**)(p->m_parameter));
1158 
1159  if (child)
1160  {
1161  child->get_parameter_incremental_hash(hash, carry,
1162  total_length);
1163  }
1164  }
1165  else if (p->m_datatype.m_ctype==CT_VECTOR ||
1166  p->m_datatype.m_ctype==CT_SGVECTOR)
1167  {
1168  CSGObject** child=(*(CSGObject***)(p->m_parameter));
1169 
1170  for (index_t j=0; j<*(p->m_datatype.m_length_y); j++)
1171  {
1172  if (child[j])
1173  {
1174  child[j]->get_parameter_incremental_hash(hash, carry,
1175  total_length);
1176  }
1177  }
1178  }
1179  }
1180  else
1181  p->get_incremental_hash(hash, carry, total_length);
1182  }
1183 }
1184 
1186 {
1187  for (index_t i=0; i<m_gradient_parameters->get_num_parameters(); i++)
1188  {
1190  dict->add(p, this);
1191  }
1192 
1194  {
1196  CSGObject* child=*(CSGObject**)(p->m_parameter);
1197 
1198  if ((p->m_datatype.m_ptype == PT_SGOBJECT) &&
1199  (p->m_datatype.m_ctype == CT_SCALAR) && child)
1200  {
1202  }
1203  }
1204 }
1205 
1206 bool CSGObject::equals(CSGObject* other, float64_t accuracy, bool tolerant)
1207 {
1208  SG_DEBUG("entering %s::equals()\n", get_name());
1209 
1210  if (other==this)
1211  {
1212  SG_DEBUG("leaving %s::equals(): other object is me\n", get_name());
1213  return true;
1214  }
1215 
1216  if (!other)
1217  {
1218  SG_DEBUG("leaving %s::equals(): other object is NULL\n", get_name());
1219  return false;
1220  }
1221 
1222  SG_DEBUG("comparing \"%s\" to \"%s\"\n", get_name(), other->get_name());
1223 
1224  /* a crude type check based on the get_name */
1225  if (strcmp(other->get_name(), get_name()))
1226  {
1227  SG_INFO("leaving %s::equals(): name of other object differs\n", get_name());
1228  return false;
1229  }
1230 
1231  /* should not be necessary but just ot be sure that type has not changed.
1232  * Will assume that parameters are in same order with same name from here */
1234  {
1235  SG_INFO("leaving %s::equals(): number of parameters of other object "
1236  "differs\n", get_name());
1237  return false;
1238  }
1239 
1240  for (index_t i=0; i<m_parameters->get_num_parameters(); ++i)
1241  {
1242  SG_DEBUG("comparing parameter %d\n", i);
1243 
1244  TParameter* this_param=m_parameters->get_parameter(i);
1245  TParameter* other_param=other->m_parameters->get_parameter(i);
1246 
1247  /* some checks to make sure parameters have same order and names and
1248  * are not NULL. Should never be the case but check anyway. */
1249  if (!this_param && !other_param)
1250  continue;
1251 
1252  if (!this_param && other_param)
1253  {
1254  SG_DEBUG("leaving %s::equals(): parameter %d is NULL where other's "
1255  "parameter \"%s\" is not\n", get_name(), other_param->m_name);
1256  return false;
1257  }
1258 
1259  if (this_param && !other_param)
1260  {
1261  SG_DEBUG("leaving %s::equals(): parameter %d is \"%s\" where other's "
1262  "parameter is NULL\n", get_name(), this_param->m_name);
1263  return false;
1264  }
1265 
1266  SG_DEBUG("comparing parameter \"%s\" to other's \"%s\"\n",
1267  this_param->m_name, other_param->m_name);
1268 
1269  /* hard-wired exception for DynamicObjectArray parameter num_elements */
1270  if (!strcmp("DynamicObjectArray", get_name()) &&
1271  !strcmp(this_param->m_name, "num_elements") &&
1272  !strcmp(other_param->m_name, "num_elements"))
1273  {
1274  SG_DEBUG("Ignoring DynamicObjectArray::num_elements field\n");
1275  continue;
1276  }
1277 
1278  /* hard-wired exception for DynamicArray parameter num_elements */
1279  if (!strcmp("DynamicArray", get_name()) &&
1280  !strcmp(this_param->m_name, "num_elements") &&
1281  !strcmp(other_param->m_name, "num_elements"))
1282  {
1283  SG_DEBUG("Ignoring DynamicArray::num_elements field\n");
1284  continue;
1285  }
1286 
1287  /* use equals method of TParameter from here */
1288  if (!this_param->equals(other_param, accuracy, tolerant))
1289  {
1290  SG_INFO("leaving %s::equals(): parameters at position %d with name"
1291  " \"%s\" differs from other object parameter with name "
1292  "\"%s\"\n",
1293  get_name(), i, this_param->m_name, other_param->m_name);
1294  return false;
1295  }
1296  }
1297 
1298  SG_DEBUG("leaving %s::equals(): object are equal\n", get_name());
1299  return true;
1300 }
1301 
1303 {
1304  SG_DEBUG("entering %s::clone()\n", get_name());
1305 
1306  SG_DEBUG("constructing an empty instance of %s\n", get_name());
1307  CSGObject* copy=new_sgserializable(get_name(), this->m_generic);
1308 
1309  SG_REF(copy);
1310 
1311  REQUIRE(copy, "Could not create empty instance of \"%s\". The reason for "
1312  "this usually is that get_name() of the class returns something "
1313  "wrong, or that a class has a wrongly set generic type.\n",
1314  get_name());
1315 
1316  for (index_t i=0; i<m_parameters->get_num_parameters(); ++i)
1317  {
1318  SG_DEBUG("cloning parameter \"%s\" at index %d\n",
1320 
1322  {
1323  SG_DEBUG("leaving %s::clone(): Clone failed. Returning NULL\n",
1324  get_name());
1325  return NULL;
1326  }
1327  }
1328 
1329  SG_DEBUG("leaving %s::clone(): Clone successful\n", get_name());
1330  return copy;
1331 }

SHOGUN Machine Learning Toolbox - Documentation