source: orange/source/orange/examples.cpp @ 11716:6f5c66aed28e

Revision 11716:6f5c66aed28e, 10.5 KB checked in by Ales Erjavec <ales.erjavec@…>, 7 months ago (diff)

Initialize the 'classes_end' member in TExample merging constructor.

(fixes #1315).

Line 
1#include <algorithm>
2#include <iomanip>
3#include "stladdon.hpp"
4#include "vars.hpp"
5#include "domain.hpp"
6
7#include "examplegen.hpp"
8#include "values.hpp"
9#include "distvars.hpp"
10
11#include "examples.ppp"
12#include "crc.h"
13
14DEFINE_TOrangeVector_classDescription(PExample, "TExampleList", true, ORANGE_API)
15
16long exampleId = 0;
17
18long getExampleId()
19{ return ++exampleId; }
20 
21TExample::TExample()
22: values(NULL),
23  values_end(NULL),
24  classes_end(NULL),
25  name(NULL),
26  id(getExampleId())
27{}
28
29
30TExample::TExample(PDomain dom, bool initMetas)
31: domain(dom),
32  values(NULL),
33  values_end(NULL),
34  classes_end(NULL),
35  name(NULL),
36  id(getExampleId())
37{ if (!dom)
38    raiseError("example needs domain");
39
40  const int attrs = domain->variables->size();
41  const int classes = domain->classVars->size();
42  TValue *vi = values = mlnew TValue[attrs+classes];
43  values_end = values + attrs;
44  classes_end = values_end + classes;
45  PITERATE(TVarList, di, dom->variables)
46    *(vi++) = (*di)->DK();
47  PITERATE(TVarList, ci, dom->classVars) {
48    *(vi++) = (*ci)->DK();
49  }
50  if (initMetas)
51    ITERATE(TMetaVector, mi, dom->metas)
52      if (!(*mi).optional)
53        setMeta((*mi).id, (*mi).variable->DK());
54}
55
56
57TExample::TExample(const TExample &orig, bool copyMetas)
58: domain(orig.domain),
59  meta(copyMetas ? orig.meta : TMetaValues()),
60  name(orig.name ? new string(*orig.name) : NULL),
61  id(orig.id)
62{ if (domain) {
63    const int attrs = domain->variables->size();
64    const int classes = orig.classes_end - orig.values_end;
65    TValue *vi = values = mlnew TValue[attrs+classes];
66    values_end = values + attrs;
67    classes_end = values_end + classes;
68    for(TValue *origi = orig.values, *thisi = values; thisi != classes_end; *(thisi++) = *(origi++));
69  }
70  else 
71      values = values_end = classes_end = NULL;
72}
73
74
75TExample::TExample(PDomain dom, const TExample &orig, bool copyMetas)
76: domain(dom),
77  meta(),
78  name(NULL),
79  id(orig.id)
80{ if (!dom)
81    raiseError("example needs a domain");
82
83  const int attrs = domain->variables->size();
84  const int classes = domain->classVars->size();
85  values = mlnew TValue[attrs + classes];
86  values_end = values + attrs;
87  classes_end = values_end + classes;
88  domain->convert(*this, orig, !copyMetas);
89}
90
91
92void TExample::insertVal(TValue &srcval, PVariable var, const long &metaID, vector<bool> &defined)
93{
94  int position = var ? domain->getVarNum(var, false) : ILLEGAL_INT;
95
96  if (position != ILLEGAL_INT) {
97    // Check if this is an ordinary attribute
98    if (position >= 0) {
99      if (!mergeTwoValues(values[position], srcval, defined[position]))
100        raiseError("ambiguous value of attribute '%s'", var->get_name().c_str());
101      else
102        defined[position] = true;
103    }
104   
105    else {
106      // Is it meta?
107      if (hasMeta(position)) {
108        if (!mergeTwoValues(meta[metaID], srcval, true))
109          raiseError("ambiguous value for meta-attribute '%s'", var->get_name().c_str());
110      }
111      else
112        setMeta(position, srcval);
113    }
114  }
115
116
117  else {
118    /* This attribute is not required in the example.
119       But if it is meta and there is no other meta-attribute with same id,
120       we shall copy it nevertheless */
121    if (metaID && !domain->getMetaVar(metaID, false))
122      if (hasMeta(metaID)) {
123        if (!mergeTwoValues(meta[metaID], srcval, true))
124          raiseError("ambiguous value for meta-attribute %i", position);
125      }
126      else
127        setMeta(metaID  , srcval);
128  }
129}
130
131
132TExample::TExample(PDomain dom, PExampleList elist)
133: domain(dom),
134  name(NULL),
135  id(elist->size() ? elist->front()->id : getExampleId())
136{
137  if (!dom)
138    raiseError("example needs a domain");
139  if (dom->classVars->size()) {
140      raiseError("example merging does not support multiple classes");
141  }
142
143  const int attrs = domain->variables->size();
144  const int classes = domain->classVars->size();
145  vector<bool> defined(attrs, false);
146
147  TValue *vi = values = mlnew TValue[attrs];
148  values_end = classes_end = values + attrs;
149
150  PITERATE(TVarList, di, dom->variables)
151    *(vi++) = (*di)->DK();
152
153  PITERATE(TExampleList, eli, elist) {
154    TVarList::iterator vli((*eli)->domain->variables->begin());
155    TExample::iterator ei((*eli)->begin()), ee((*eli)->end());
156    for(; ei!=ee; ei++, vli++) 
157      if (!(*ei).isSpecial())
158        insertVal(*ei, *vli, 0, defined);
159
160    set<int> metasNotToCopy;
161    ITERATE(TMetaVector, mai, (*eli)->domain->metas) {
162      metasNotToCopy.insert((*mai).id);
163      if ((*eli)->hasMeta((*mai).id))
164        insertVal((*eli)->getMeta((*mai).id), (*mai).variable, (*mai).id, defined);
165    }
166
167    set<int>::iterator mend(metasNotToCopy.end());
168    ITERATE(TMetaValues, mi, (*eli)->meta)
169      if (metasNotToCopy.find((*mi).first)==mend)
170        insertVal((*mi).second, PVariable(), (*mi).first, defined);
171  }
172
173  ITERATE(TMetaVector, mai, domain->metas)
174    if (!(*mai).optional && !hasMeta((*mai).id))
175      setMeta((*mai).id, (*mai).variable->DK());
176}
177
178
179TExample::~TExample()
180{ 
181  mldelete[] values; 
182  if (name)
183    delete name;
184}
185
186
187int TExample::traverse(visitproc visit, void *arg) const
188{ TRAVERSE(TOrange::traverse);
189 
190  for(TValue *vi = values, *ve = classes_end; vi!=ve; vi++)
191    if (vi->svalV)
192      PVISIT(vi->svalV);
193
194  const_ITERATE(TMetaValues, mi, meta)
195    if ((*mi).second.svalV)
196      PVISIT((*mi).second.svalV);
197
198  return 0;
199}
200
201
202int TExample::dropReferences()
203{
204  for(TValue *vi = values, *ve = classes_end; vi!=ve; vi++)
205    if (vi->svalV)
206      vi->svalV.~PSomeValue();
207
208  const_ITERATE(TMetaValues, mi, meta)
209    if ((*mi).second.svalV)
210      (*mi).second.svalV.~PSomeValue();
211
212  delete name;
213  name = NULL;
214
215  return 0;
216}
217
218
219TExample &TExample::operator =(const TExample &orig)
220{
221  if (!orig.domain) {
222    if (values)
223       mldelete[] values;
224    values = values_end = classes_end = NULL;
225    domain = PDomain();
226  }
227
228  else {
229    const int attrs = orig.values_end - orig.values;
230    const int classes = orig.classes_end - orig.values_end;
231    if (domain != orig.domain) {
232      if ((values_end - values != attrs) || (classes_end - values_end != classes)) {
233        if (values)
234          mldelete[] values;
235        values = mlnew TValue[attrs+classes];
236        values_end = values + attrs;
237        classes_end = values_end + classes;
238      }
239      domain = orig.domain;
240    }
241
242    for(TValue *origi = orig.values, *thisi = values; thisi != classes_end; *(thisi++) = *(origi++));
243  }
244
245  meta = orig.meta;
246 
247  if (name) {
248    delete name;
249    name = NULL;
250  }
251  if (orig.name)
252    name = new string(*orig.name);
253
254  id = orig.id;
255 
256  return *this;
257}
258
259
260TValue TExample::getValue(PVariable &var) const
261{
262  // if there is no getValueFrom, throw an exception
263  const int position = domain->getVarNum(var, var->getValueFrom);
264  return position != ILLEGAL_INT ? operator[](position) : var->computeValue(*this);
265}
266
267TValue &TExample::operator[] (PVariable &var)
268{ return operator[](domain->getVarNum(var)); }
269
270
271const TValue &TExample::operator[] (PVariable &var) const
272{ return operator[](domain->getVarNum(var)); }
273
274
275TValue &TExample::operator[] (const string &name)
276{ return operator[](domain->getVarNum(name)); }
277
278
279const TValue &TExample::operator[] (const string &name) const
280{ return operator[](domain->getVarNum(name)); }
281
282
283const TValue &TExample::missingMeta(const int &i) const
284{
285  const TMetaDescriptor *md = domain->metas[i];
286  if (md)
287    if (md->optional)
288      return md->variable->DK();
289    else
290      if (md->variable->get_name().size())
291        raiseError("the value of meta attribute '%s' is missing", md->variable->get_name().c_str());
292
293  // no descriptor or no name
294  raiseError("meta value with id %i is missing", i);
295  throw 0;
296}
297
298
299bool TExample::operator < (const TExample &other) const
300{ 
301  if (domain != other.domain)
302    raiseError("examples are from different domains");
303  return compare(other)<0;
304}
305
306
307bool TExample::operator == (const TExample &other) const
308{ 
309  if (domain != other.domain)
310    raiseError("examples are from different domains");
311
312  int Na = domain->variables->size() + domain->classVars->size();
313  if (!Na)
314    return true;
315  for (const_iterator vi1(begin()), vi2(other.begin()); (*vi1==*vi2) && --Na; vi1++, vi2++);
316  return !Na;
317}
318
319
320int TExample::compare(const TExample &other, const bool ignoreClass) const
321{ if (domain != other.domain)
322    raiseError("examples are from different domains");
323  int Na = domain->variables->size();
324  if (ignoreClass) {
325      if (domain->classVar) {
326          Na--;
327      }
328  }
329  else {
330      Na += domain->classVars->size();
331  }
332  if (!Na)
333    return 0;
334
335  const_iterator i1(begin()), i2(other.begin());
336  int comp;
337  while (0==(comp= (*(i1++)).compare(*(i2++))) && --Na);
338  return comp;
339}
340
341
342bool TExample::compatible(const TExample &other, const bool ignoreClass) const
343{ if (domain != other.domain)
344    raiseError("examples are from different domains");
345 
346  int Na = domain->variables->size();
347  if (ignoreClass) {
348      if (domain->classVar) {
349          Na--;
350      }
351  }
352  else {
353      Na += domain->classVars->size();
354  }
355  if (!Na)
356    return true;
357  for (const_iterator i1(begin()), i2(other.begin()); (*i1).compatible(*i2) && --Na; i1++, i2++);
358  return !Na;
359}
360
361
362#include "stringvars.hpp"
363
364inline void addToCRC(unsigned int &crc, const PVarList &vars, TValue *&vli)
365{
366  const_PITERATE(TVarList, vi, vars) {
367    if ((*vi)->varType == TValue::INTVAR)
368      add_CRC(vli->isSpecial() ? ILLEGAL_INT : vli->intV, crc);
369    else if (((*vi)->varType == TValue::FLOATVAR))
370      add_CRC(vli->isSpecial() ? ILLEGAL_FLOAT : vli->floatV, crc);
371    else if ((*vi)->varType == STRINGVAR) {
372      if (vli->isSpecial() || !vli->svalV)
373        add_CRC(ILLEGAL_INT, crc);
374      else
375        add_CRC(vli->svalV.AS(TStringValue)->value.c_str(), crc);
376    }
377    vli++;
378  }
379}
380
381void TExample::addToCRC(unsigned int &crc, const bool includeMetas) const
382{
383  TValue *vli = values;
384  ::addToCRC(crc, domain->variables, vli);
385  ::addToCRC(crc, domain->classVars, vli);
386 
387  if (includeMetas) {
388    const_ITERATE(TMetaValues, mi, meta) {
389      add_CRC((const unsigned long)(mi->first), crc);
390      const TValue &val = mi->second;
391      if (val.varType == TValue::INTVAR)
392        add_CRC(val.isSpecial() ? ILLEGAL_INT : val.intV, crc);
393      else if (val.varType == TValue::INTVAR)
394        add_CRC(val.isSpecial() ? ILLEGAL_FLOAT: val.floatV, crc);
395      else if (val.varType == STRINGVAR) {
396        if (val.isSpecial()  || !vli->svalV)
397          add_CRC(ILLEGAL_INT, crc);
398        else
399          add_CRC(val.svalV.AS(TStringValue)->value.c_str(), crc);
400      }
401    }
402  }
403}
404
405
406int TExample::sumValues(const bool includeMetas) const
407{ unsigned int crc;
408  INIT_CRC(crc);
409  addToCRC(crc, includeMetas);
410  FINISH_CRC(crc);
411  return int(crc & 0x7fffffff);
412}
Note: See TracBrowser for help on using the repository browser.