source: orange/source/orange/domain.cpp @ 9415:b8c964fe3d51

Revision 9415:b8c964fe3d51, 16.5 KB checked in by janezd <janez.demsar@…>, 2 years ago (diff)

Fixed multiple classes: pickling, conversion between domains, printing

Line 
1/*
2    This file is part of Orange.
3   
4    Copyright 1996-2010 Faculty of Computer and Information Science, University of Ljubljana
5    Contact: janez.demsar@fri.uni-lj.si
6
7    Orange is free software: you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation, either version 3 of the License, or
10    (at your option) any later version.
11
12    Orange is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with Orange.  If not, see <http://www.gnu.org/licenses/>.
19*/
20
21
22#include "vars.hpp"
23#include "examples.hpp"
24#include "examplegen.hpp"
25#include "stladdon.hpp"
26
27#include "domain.ppp"
28
29
30DEFINE_TOrangeVector_classDescription(PDomain, "TDomainList", true, ORANGE_API)
31
32// A counter for version field of domains. It is incremented and copied to version field each time a domain is changed.
33int domainVersion=0;
34
35TDomainMapping::TDomainMapping(TDomain *dom)
36: domain(dom),
37  positions() 
38{}
39
40
41TDomain::TDomain()
42: classVar((TVariable *)NULL),
43  attributes(mlnew TVarList()),
44  variables(mlnew TVarList()),
45  classVars(mlnew TVarList()),
46  version(++domainVersion),
47  lastDomain(knownDomains.end()),
48  destroyNotifiers()
49{}
50
51
52TDomain::TDomain(const TVarList &vl)
53: classVar(vl.size() ? vl.back() : PVariable()),
54  attributes(mlnew TVarList(vl)),
55  variables(mlnew TVarList(vl)),
56  classVars(mlnew TVarList()),
57  version(++domainVersion),
58  lastDomain(knownDomains.end()),
59  destroyNotifiers()
60{ if (attributes->size())
61    attributes->erase(attributes->end()-1); 
62}
63
64
65TDomain::TDomain(PVariable va, const TVarList &vl)
66: classVar(va),
67  attributes(mlnew TVarList(vl)),
68  variables(mlnew TVarList(vl)),
69  classVars(mlnew TVarList()),
70  version(++domainVersion),
71  lastDomain(knownDomains.end()),
72  destroyNotifiers()
73{ 
74  if (va)
75    variables->push_back(va); 
76}
77
78
79TDomain::TDomain(const TDomain &old)
80: TOrange(old),
81  classVar(old.classVar), 
82  attributes(mlnew TVarList(old.attributes.getReference())),
83  variables(mlnew TVarList(old.variables.getReference())), 
84  classVars(mlnew TVarList(old.classVars.getReference())),
85  metas(old.metas),
86  version(++domainVersion),
87  knownDomains(),  // don't copy, unless you want to mess with the notifiers..
88  lastDomain(knownDomains.end()),
89  destroyNotifiers()
90{}
91
92
93TDomain::~TDomain()
94{ domainChangedDispatcher(); 
95  ITERATE(list<TDestroyNotification>, dni, destroyNotifiers)
96    (*(*dni).first)(this, (*dni).second);
97}
98
99
100int TDomain::traverse(visitproc visit, void *arg) const
101{ TRAVERSE(TOrange::traverse);
102  for(TMetaVector::const_iterator mi(metas.begin()), me(metas.end()); mi!=me; mi++)
103    PVISIT((*mi).variable);
104  return 0;
105}
106
107
108int TDomain::dropReferences()
109{ DROPREFERENCES(TOrange::dropReferences);
110
111  metas.clear();
112  domainHasChanged();
113  return 0;
114}
115
116
117/*  Must be called whenever the domain is changed, i.e. a variable is added, changed are removed.
118    This function increases the version number and clears the knownDomains vector. */
119void TDomain::domainHasChanged()
120{ version = ++domainVersion;
121  domainChangedDispatcher();
122
123  knownDomains.clear();
124  knownByDomains.clear();
125  lastDomain = knownDomains.end();
126}
127
128
129void TDomain::afterSet(const char *name)
130{ 
131  if (!strcmp(name, "class_var") 
132      || !strcmp(name, "classVar")) {
133    if (attributes->size()==variables->size())
134      variables->push_back(classVar);
135    else
136      variables->back() = classVar;
137    domainHasChanged();
138  }
139
140  TOrange::afterSet(name);
141}
142
143
144bool TDomain::addVariable(PVariable var)
145{ if (classVar)
146    variables->insert(variables->end()-1, var);
147  else
148    variables->push_back(var);
149
150  attributes->push_back(var);
151  domainHasChanged();
152  return true;
153}
154
155
156
157bool TDomain::addVariable(PVariable var, int position)
158{ if (position>int(attributes->size()))
159    return false;
160  variables->insert(variables->begin()+position, var);
161  attributes->insert(attributes->begin()+position, var);
162  domainHasChanged();
163  return true;
164}
165
166
167void TDomain::removeClass()
168{ if (classVar) {
169    variables->erase(variables->end()-1);
170    classVar = (TVariable *)NULL;
171    domainHasChanged();
172  }
173}
174
175
176void TDomain::setClass(PVariable var)
177{ variables->push_back(var);
178  classVar = var; 
179  domainHasChanged(); 
180}
181
182
183void TDomain::changeClass(PVariable var)
184{ removeClass();
185  setClass(var); 
186  domainHasChanged();
187}
188
189
190bool TDomain::delVariable(PVariable var)
191{ 
192  TVarList::iterator ai = find(attributes->begin(), attributes->end(), var);
193  if (ai==attributes->end())
194    return false;
195
196  TVarList::iterator vi = find(variables->begin(), variables->end(), var);
197  if (vi==variables->end())
198    return false;
199
200  attributes->erase(ai);
201  variables->erase(vi);
202
203  domainHasChanged();
204  return true;
205}
206
207
208int TDomain::getVarNum(PVariable var, bool throwExc) const
209{ int pos = 0;
210  TVarList::const_iterator vi, ve;
211  for(vi = variables->begin(), ve = variables->end(); vi!=ve; vi++, pos++)
212    if (*vi == var)
213      return pos;
214  for(vi = classVars->begin(), ve = classVars->end(); vi != ve; vi++, pos++)
215      if (*vi == var)
216            return pos;
217
218  pos = getMetaNum(var, false);
219  if ((pos == ILLEGAL_INT) && throwExc)
220    raiseError("attribute '%s' not found", var->get_name().c_str());
221
222  return pos;
223}
224
225
226int TDomain::getVarNum(const string &name, bool throwExc) const
227{ int pos = 0;
228  TVarList::const_iterator vi, ve;
229  for(vi = variables->begin(), ve = variables->end(); vi!=ve; vi++, pos++)
230    if ((*vi)->get_name()== name)
231      return pos;
232  for(vi = classVars->begin(), ve = classVars->end(); vi != ve; vi++, pos++)
233        if ((*vi)->get_name() == name)
234            return pos;
235
236  pos = getMetaNum(name, false);
237  if ((pos == ILLEGAL_INT) && throwExc)
238    raiseError("attribute '%s' not found", name.c_str());
239
240  return pos;
241}
242
243
244PVariable TDomain::getVar(int num, bool throwExc) const
245{ checkProperty(variables);
246 
247  if (num>=0) {
248      if (num < variables->size())
249          return variables->at(num);
250      if (num - variables->size() < classVars->size())
251          return classVars->at(num - variables->size());
252      if (throwExc)
253        if (!variables->size())
254          raiseError("no attributes in domain");
255        else
256          raiseError("index %i out of range", num);
257      else
258        return PVariable();
259  }
260  else {
261    const_ITERATE(TMetaVector, mi, metas)
262      if ((*mi).id == num)
263        return (*mi).variable;
264
265    if (throwExc)
266      raiseError("meta attribute with index %i not in domain", num);
267    else
268      return PVariable();
269  }
270
271  return PVariable();
272}
273
274
275PVariable TDomain::getVar(int num, bool throwExc)
276{ checkProperty(variables);
277 
278  if (num>=0) {
279      if (num < variables->size())
280          return variables->at(num);
281
282      if (num - variables->size() < classVars->size())
283          return classVars->at(num - variables->size());
284
285      if (throwExc)
286        if (!variables->size())
287          raiseError("no attributes in domain");
288        else
289          raiseError("index %i out of range", num);
290      else
291        return PVariable();
292  }
293  else {
294    ITERATE(TMetaVector, mi, metas)
295      if ((*mi).id == num)
296        return (*mi).variable;
297
298    if (throwExc)
299      raiseError("meta attribute with index %i not in domain", num);
300    else
301      return PVariable();
302  }
303
304  return PVariable();
305}
306
307
308PVariable TDomain::getVar(const string &name, bool takeMetas, bool throwExc)
309{ 
310  PITERATE(TVarList, vi, variables) {
311    if ((*vi)->get_name()==name)
312      return *vi;
313  }
314  PITERATE(TVarList, vi2, classVars) {
315    if ((*vi2)->get_name()==name)
316      return *vi2;
317  }
318  if (takeMetas)
319    ITERATE(TMetaVector, mi, metas)
320      if ((*mi).variable->get_name()==name)
321        return (*mi).variable;
322
323  if (throwExc)
324    raiseError("attribute '%s' not found", name.c_str());
325
326  return PVariable();
327}
328
329
330PVariable TDomain::getVar(const string &name, bool takeMetas, bool throwExc) const
331{ const_PITERATE(TVarList, vi, variables) {
332    if ((*vi)->get_name()==name)
333      return *vi;
334  }
335  const_PITERATE(TVarList, vi2, classVars) {
336    if ((*vi2)->get_name()==name)
337      return *vi2;
338  }
339
340  if (takeMetas)
341    const_ITERATE(TMetaVector, mi, metas)
342      if ((*mi).variable->get_name()==name)
343        return (*mi).variable;
344
345  if (throwExc)
346    raiseError("attribute '%s' not found", name.c_str());
347
348  return PVariable();
349}
350
351
352const TMetaDescriptor *TDomain::getMetaDescriptor(const string &wname, bool throwExc) const
353{ const_ITERATE(TMetaVector, mi, metas)
354    if ((*mi).variable->get_name()==wname)
355      return &*mi;
356
357  if (throwExc)
358    raiseError("meta attribute '%s' not found", wname.c_str());
359 
360  return NULL;
361}
362
363const TMetaDescriptor *TDomain::getMetaDescriptor(PVariable var, bool throwExc) const
364{ const_ITERATE(TMetaVector, mi, metas)
365    if ((*mi).variable==var)
366      return &*mi;
367
368  if (throwExc)
369    raiseError("meta attribute '%s' not found", var->get_name().c_str());
370 
371  return NULL;
372}
373
374
375const TMetaDescriptor *TDomain::getMetaDescriptor(const int &idx, bool throwExc) const
376{ const_ITERATE(TMetaVector, mi, metas)
377    if ((*mi).id==idx)
378      return &*mi;
379
380  if (throwExc)
381    raiseError("meta attribute with index %i not found", idx);
382 
383  return NULL;
384}
385
386
387
388long TDomain::getMetaNum(const string &wname, bool throwExc) const
389{ const TMetaDescriptor *mi = getMetaDescriptor(wname, throwExc);
390  return mi ? mi->id : ILLEGAL_INT;
391}
392
393
394long TDomain::getMetaNum(PVariable var, bool throwExc) const
395{ const_ITERATE(TMetaVector, mi, metas)
396    if ((*mi).variable==var)
397      return (*mi).id;
398
399  if (throwExc)
400    raiseError("meta attribute '%s' not found", var->get_name().c_str());
401
402  return ILLEGAL_INT;
403}
404
405
406PVariable TDomain::getMetaVar(const int &idx, bool throwExc)
407{ ITERATE(TMetaVector, mi, metas)
408    if ((*mi).id==idx)
409      return (*mi).variable;
410
411  if (throwExc)
412    raiseError("meta attribute with index %i not found", idx);
413
414  return PVariable();
415}
416
417
418PVariable TDomain::getMetaVar(const int &idx, bool throwExc) const
419{ const_ITERATE(TMetaVector, mi, metas)
420    if ((*mi).id==idx)
421      return (*mi).variable;
422
423  if (throwExc)
424    raiseError("meta attribute with index %i not found", idx);
425
426  return PVariable();
427}
428
429
430PVariable TDomain::getMetaVar(const string &wname, bool throwExc) const
431{ const_ITERATE(TMetaVector, mi, metas)
432    if ((*mi).variable->get_name()==wname)
433      return (*mi).variable;
434
435  if (throwExc)
436    raiseError("meta attribute '%s' not found", wname.c_str());
437
438  return PVariable();
439}
440
441
442PVariable TDomain::getMetaVar(const string &wname, bool throwExc)
443{ ITERATE(TMetaVector, mi, metas)
444    if ((*mi).variable->get_name()==wname)
445      return (*mi).variable;
446
447  if (throwExc)
448    raiseError("meta attribute '%s' not found", wname.c_str());
449
450  return PVariable();
451}
452
453
454PVariable TDomain::operator[](const string &name) const
455{ return getVar(name, true, true); }
456
457
458PVariable TDomain::operator[](const string &name)
459{ return getVar(name, true, true); }
460
461
462/*  Converts the example 'src' to 'dest' from this domain. If example is from the same domain,
463    values are copied. If domain is different a corresponding TDomainMapping is found (or constructed
464    if necessary). Converting is done by setting i-th value of 'dest' to position[i]-th value of
465    'src' or by asking variable[i]->computeValue to deduce its value from 'src'. */
466void TDomain::convert(TExample &dest, const TExample &src, bool filterMetas)
467{
468  dest.id = src.id; 
469  if (src.domain==this) {
470    int Nv = variables->size() + classVars->size();
471    TExample::iterator de = dest.begin();
472    TExample::const_iterator sr = src.begin();
473    while(Nv--)
474      *(de++) = *(sr++);
475    dest.meta = src.meta;
476  }
477
478  else {
479    if (lastDomain!=knownDomains.end()) // if not, there are no known domains (otherwise lastDomain would point to one)
480      if (src.domain!=(*lastDomain).domain)
481        for(lastDomain=knownDomains.begin(); lastDomain!=knownDomains.end(); lastDomain++);
482
483    // no domains or no src.domain
484    if (lastDomain==knownDomains.end()) { 
485      knownDomains.push_back(TDomainMapping(const_cast<TDomain *>(src.domain.getUnwrappedPtr())));
486      const_cast<TExample &>(src).domain->knownByDomains.push_back(const_cast<TDomain *>(this));
487
488      lastDomain = knownDomains.end();
489      lastDomain--;
490
491      const_PITERATE(TVarList, vi, variables) {
492        const int cvi = src.domain->getVarNum(*vi, false);
493        (*lastDomain).positions.push_back(cvi);
494        if (cvi<0)
495          (*lastDomain).metasNotToCopy.insert(cvi);
496      }
497
498      const_PITERATE(TVarList, mvi, classVars) {
499        const int cvi = src.domain->getVarNum(*mvi, false);
500        (*lastDomain).positions.push_back(cvi);
501        if (cvi<0)
502          (*lastDomain).metasNotToCopy.insert(cvi);
503      }
504
505      ITERATE(TMetaVector, mvi, metas) {
506        const int cvi = src.domain->getVarNum((*mvi).variable, false);
507        (*lastDomain).metaPositions.push_back(make_pair(int((*mvi).id), cvi));
508        if (cvi<0)
509          (*lastDomain).metasNotToCopy.insert(cvi);
510      }
511
512      const_ITERATE(TMetaVector, mvio, src.domain->metas)
513        (*lastDomain).metasNotToCopy.insert((*mvio).id);
514    }
515
516    // Now, lastDomain points to an appropriate mapping
517    TExample::iterator deval(dest.begin());
518    vector<int>::iterator pi((*lastDomain).positions.begin());
519
520    TVarList::iterator vi;
521    int Nv;
522   
523    for(vi = variables->begin(), Nv = dest.domain->variables->size(); Nv--; pi++, vi++)
524      *(deval++) = (*pi == ILLEGAL_INT) ? (*vi)->computeValue(src) : src[*pi];
525
526    for(vi = classVars->begin(), Nv = dest.domain->classVars->size(); Nv--; pi++, vi++)
527      *(deval++) = (*pi == ILLEGAL_INT) ? (*vi)->computeValue(src) : src[*pi];
528
529    TMetaVector::iterator mvi(metas.begin());
530    for(vector<pair<int, int> >::const_iterator vpii((*lastDomain).metaPositions.begin()), vpie((*lastDomain).metaPositions.end());
531        vpii!=vpie; 
532        vpii++, mvi++) {
533      if (!(*mvi).optional)
534        dest.setMeta((*vpii).first, (*vpii).second==ILLEGAL_INT ? (*mvi).variable->computeValue(src) : src[(*vpii).second]);
535      else if ((*vpii).second != ILLEGAL_INT) {
536        if (src.hasMeta((*vpii).second))
537          dest.setMeta((*vpii).first, src[(*vpii).second]);
538      }
539      else if ((*mvi).variable->getValueFrom) {
540          TValue mval = (*mvi).variable->computeValue(src);
541          if (!mval.isSpecial())
542            dest.setMeta((*vpii).first, mval);
543      }
544    }
545
546    if (!filterMetas) {
547      set<int>::iterator mend = (*lastDomain).metasNotToCopy.end();
548      const_ITERATE(TMetaValues, mi, src.meta)
549        if ((*lastDomain).metasNotToCopy.find((*mi).first) == mend)
550          dest.setMeta((*mi).first, (*mi).second);
551    }
552  }
553}
554
555
556
557void TDomain::domainChangedDispatcher()
558{ ITERATE(list<TDomainMapping>, di, knownDomains)
559    (*di).domain->domainChangedNoticeHandler(this);
560
561  ITERATE(list<TDomain *>, ki, knownByDomains)
562    (*ki)->domainChangedNoticeHandler(this);
563}
564
565
566class eqDom {
567public:
568  TDomain *domain;
569
570  eqDom(TDomain *dom) : domain(dom) {};
571  bool operator==(const TDomainMapping &mp) const
572  { return mp.domain==domain; }
573};
574
575
576void TDomain::domainChangedNoticeHandler(TDomain *dom)
577{ bool rld = (lastDomain==knownDomains.end()) || ((*lastDomain).domain==dom);
578
579  for(list<TDomainMapping>::iterator li(knownDomains.begin()), ln, le(knownDomains.end()); li!=le; )
580    if ((*(ln=li++)).domain==dom)
581      knownDomains.erase(ln);
582
583  if (rld)
584    lastDomain = knownDomains.end();
585
586  knownByDomains.remove(dom);
587}
588
589
590
591PVariable TDomain::hasOtherAttributes(bool checkClass) const
592{
593  const_PITERATE(TVarList, vi, checkClass ? variables : attributes)
594    if (((*vi)->varType != TValue::FLOATVAR) && ((*vi)->varType != TValue::INTVAR))
595      return *vi;
596  return PVariable();
597}
598
599
600PVariable TDomain::hasDiscreteAttributes(bool checkClass) const
601{
602  const_PITERATE(TVarList, vi, checkClass ? variables : attributes)
603    if ((*vi)->varType == TValue::INTVAR)
604      return *vi;
605  return PVariable();
606}
607
608
609PVariable TDomain::hasContinuousAttributes(bool checkClass) const
610{
611  const_PITERATE(TVarList, vi, checkClass ? variables : attributes)
612    if ((*vi)->varType == TValue::FLOATVAR)
613      return *vi;
614  return PVariable();
615}
616
617
618#include "crc.h"
619
620void TDomain::addToCRC(unsigned long &crc) const
621{
622  const_PITERATE(TVarList, vi, variables) {
623    add_CRC((*vi)->get_name().c_str(), crc);
624    add_CRC((const unsigned char)(*vi)->varType, crc);
625    if ((*vi)->varType == TValue::INTVAR)
626      PITERATE(TStringList, vli, dynamic_cast<TEnumVariable &>(vi->getReference()).values)
627        add_CRC(vli->c_str(), crc);
628  }
629}
630
631
632int TDomain::sumValues() const
633{ unsigned long crc;
634  INIT_CRC(crc);
635  addToCRC(crc);
636  FINISH_CRC(crc);
637  return int(crc & 0x7fffffff);
638}
Note: See TracBrowser for help on using the repository browser.