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

SHOGUN Machine Learning Toolbox - Documentation