Commits

Janez Demšar  committed 0cea86d

Renamed Domain.classes to Domain.class_vars; now they always exist, but may be empty
Domain's constructor now has a new keyword argument class_vars
ExampleTable now has pickClass for picking a new class and putting the current class attribute to class_vars

  • Participants
  • Parent commits 7d3dab3

Comments (0)

Files changed (11)

File source/Orange.sln

 
-Microsoft Visual Studio Solution File, Format Version 10.00
-# Visual Studio 2008
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Corn", "corn\Corn.vcproj", "{DB7466D1-CF93-44A1-9AB2-27290A2EC7C7}"
-	ProjectSection(ProjectDependencies) = postProject
-		{93B854DA-EC3F-4314-B801-58411F9713FD} = {93B854DA-EC3F-4314-B801-58411F9713FD}
-		{745880F1-8F10-4247-B481-E4321BC1BD9F} = {745880F1-8F10-4247-B481-E4321BC1BD9F}
-	EndProjectSection
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "corn", "corn\corn.vcxproj", "{DB7466D1-CF93-44A1-9AB2-27290A2EC7C7}"
 EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Orange", "orange\Orange.vcproj", "{93B854DA-EC3F-4314-B801-58411F9713FD}"
-	ProjectSection(ProjectDependencies) = postProject
-		{745880F1-8F10-4247-B481-E4321BC1BD9F} = {745880F1-8F10-4247-B481-E4321BC1BD9F}
-	EndProjectSection
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Orange", "orange\Orange.vcxproj", "{93B854DA-EC3F-4314-B801-58411F9713FD}"
 EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Statc", "statc\Statc.vcproj", "{A0E81B4F-E592-4002-A6BE-5EAA1DD86A25}"
-	ProjectSection(ProjectDependencies) = postProject
-		{745880F1-8F10-4247-B481-E4321BC1BD9F} = {745880F1-8F10-4247-B481-E4321BC1BD9F}
-	EndProjectSection
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Statc", "statc\Statc.vcxproj", "{A0E81B4F-E592-4002-A6BE-5EAA1DD86A25}"
 EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "include", "include\include.vcproj", "{745880F1-8F10-4247-B481-E4321BC1BD9F}"
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "include", "include\include.vcxproj", "{745880F1-8F10-4247-B481-E4321BC1BD9F}"
 EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "orangene", "orangene\orangene.vcproj", "{A9DFB98F-8235-4D5B-BFE2-BBCB9A283D98}"
-	ProjectSection(ProjectDependencies) = postProject
-		{745880F1-8F10-4247-B481-E4321BC1BD9F} = {745880F1-8F10-4247-B481-E4321BC1BD9F}
-		{93B854DA-EC3F-4314-B801-58411F9713FD} = {93B854DA-EC3F-4314-B801-58411F9713FD}
-	EndProjectSection
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "orangene", "orangene\orangene.vcxproj", "{A9DFB98F-8235-4D5B-BFE2-BBCB9A283D98}"
 EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "orangeom", "orangeom\orangeom.vcproj", "{1DD56474-1110-413B-80B8-707E8EE28EC6}"
-	ProjectSection(ProjectDependencies) = postProject
-		{93B854DA-EC3F-4314-B801-58411F9713FD} = {93B854DA-EC3F-4314-B801-58411F9713FD}
-		{745880F1-8F10-4247-B481-E4321BC1BD9F} = {745880F1-8F10-4247-B481-E4321BC1BD9F}
-	EndProjectSection
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "orangeom", "orangeom\orangeom.vcxproj", "{1DD56474-1110-413B-80B8-707E8EE28EC6}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution

File source/_pyxtract.bat

 @echo off
 cd orange
+alias python \python26\python
 python ..\pyxtract\defvectors.py
 
 rem I know this is stupid, but works under any shell

File source/orange/cls_example.cpp

 { PyTRY
       const TExample &example = PyExample_AS_ExampleReference(pex);
       PyObject *list=PyList_New(0);
-      if (example.domain->classes) {
-          TExample::const_iterator ei=example.values_end;
-          const_PITERATE(TVarList, vi, example.domain->classes) {
-            PyObject *valo = Value_FromVariableValue(*vi, *ei++);
-            PyList_Append(list, valo);
-            Py_DECREF(valo);
-          }
+      TExample::const_iterator ei=example.values_end;
+      const_PITERATE(TVarList, vi, example.domain->classVars) {
+          PyObject *valo = Value_FromVariableValue(*vi, *ei++);
+          PyList_Append(list, valo);
+          Py_DECREF(valo);
       }
       return list;
   PyCATCH
       if (!PyList_Check(val)) {
           PYERROR(PyExc_TypeError, "list of values expected", PYNULL);
       }
-      if (!example.domain->classes) {
-          if (PyList_Size(val) != 0) {
-              PYERROR(PyExc_ValueError, "domain does not have multiple classes", PYNULL);
-          }
-          else {
-              RETURN_NONE;
-          }
-      }
-      if (PyList_Size(val) != example.domain->classes->size()) {
-          PyErr_Format(PyExc_IndexError, "expected %i values, got %i", example.domain->classes->size(), PyList_Size(val));
+      if (PyList_Size(val) != example.domain->classVars->size()) {
+          PyErr_Format(PyExc_IndexError, "expected %i values, got %i", example.domain->classVars->size(), PyList_Size(val));
           return NULL;
       }
       TExample::iterator ei=example.values_end;
       int pos = 0;
-      const_PITERATE(TVarList, vi, example.domain->classes) {
+      const_PITERATE(TVarList, vi, example.domain->classVars) {
           if (!convertFromPython(PyList_GET_ITEM(val, pos++), *ei++, *vi))
               return PYNULL;
       }

File source/orange/domain.cpp

 : classVar((TVariable *)NULL),
   attributes(mlnew TVarList()),
   variables(mlnew TVarList()),
-  classes(PVarList()),
+  classVars(mlnew TVarList()),
   version(++domainVersion),
   lastDomain(knownDomains.end()),
   destroyNotifiers()
 : classVar(vl.size() ? vl.back() : PVariable()),
   attributes(mlnew TVarList(vl)),
   variables(mlnew TVarList(vl)),
-  classes(PVarList()),
+  classVars(mlnew TVarList()),
   version(++domainVersion),
   lastDomain(knownDomains.end()),
   destroyNotifiers()
 : classVar(va),
   attributes(mlnew TVarList(vl)),
   variables(mlnew TVarList(vl)),
-  classes(PVarList()),
+  classVars(mlnew TVarList()),
   version(++domainVersion),
   lastDomain(knownDomains.end()),
   destroyNotifiers()
   classVar(old.classVar), 
   attributes(mlnew TVarList(old.attributes.getReference())),
   variables(mlnew TVarList(old.variables.getReference())), 
-  classes(old.classes ? mlnew TVarList(old.classes.getReference()) : NULL),
+  classVars(mlnew TVarList(old.classVars.getReference())),
   metas(old.metas),
   version(++domainVersion),
   knownDomains(),  // don't copy, unless you want to mess with the notifiers..
   for(vi = variables->begin(), ve = variables->end(); vi!=ve; vi++, pos++)
     if (*vi == var)
       return pos;
-  if (classes)
-    for(vi = classes->begin(), ve = classes->end(); vi != ve; vi++, pos++)
-        if (*vi == var)
+  for(vi = classVars->begin(), ve = classVars->end(); vi != ve; vi++, pos++)
+      if (*vi == var)
             return pos;
 
   pos = getMetaNum(var, false);
   for(vi = variables->begin(), ve = variables->end(); vi!=ve; vi++, pos++)
     if ((*vi)->get_name()== name)
       return pos;
-  if (classes)
-    for(vi = classes->begin(), ve = classes->end(); vi != ve; vi++, pos++)
+  for(vi = classVars->begin(), ve = classVars->end(); vi != ve; vi++, pos++)
         if ((*vi)->get_name() == name)
             return pos;
 
   if (num>=0) {
       if (num < variables->size())
           return variables->at(num);
-
-      if (classes && (num - variables->size() < classes->size()))
-          return classes->at(num - variables->size());
-
+      if (num - variables->size() < classVars->size())
+          return classVars->at(num - variables->size());
       if (throwExc)
         if (!variables->size())
           raiseError("no attributes in domain");
       if (num < variables->size())
           return variables->at(num);
 
-      if (classes && (num - variables->size() < classes->size()))
-          return classes->at(num - variables->size());
+      if (num - variables->size() < classVars->size())
+          return classVars->at(num - variables->size());
 
       if (throwExc)
         if (!variables->size())
 
 
 PVariable TDomain::getVar(const string &name, bool takeMetas, bool throwExc)
-{ PITERATE(TVarList, vi, variables)
+{ 
+  PITERATE(TVarList, vi, variables) {
     if ((*vi)->get_name()==name)
       return *vi;
-  if (classes) {
-    PITERATE(TVarList, vi, classes)
-    if ((*vi)->get_name()==name)
-      return *vi;
+  }
+  PITERATE(TVarList, vi2, classVars) {
+    if ((*vi2)->get_name()==name)
+      return *vi2;
   }
   if (takeMetas)
     ITERATE(TMetaVector, mi, metas)
 
 
 PVariable TDomain::getVar(const string &name, bool takeMetas, bool throwExc) const
-{ const_PITERATE(TVarList, vi, variables)
+{ const_PITERATE(TVarList, vi, variables) {
     if ((*vi)->get_name()==name)
       return *vi;
-  if (classes) {
-    const_PITERATE(TVarList, vi, classes)
-    if ((*vi)->get_name()==name)
-      return *vi;
+  }
+  const_PITERATE(TVarList, vi2, classVars) {
+    if ((*vi2)->get_name()==name)
+      return *vi2;
   }
 
   if (takeMetas)

File source/orange/domain.hpp

   PVariable classVar; //PR class variable
   PVarList attributes; //PR list of attributes, excluding the class
   PVarList variables; //PR list of attributes, including the class at the end of the list
-  PVarList classes; //PR list of class variables, if multiple; else None
+  PVarList classVars; //PR list of class variables, if multiple; else None
 
   TMetaVector metas;
 

File source/orange/domaindepot.cpp

   newDomain = mlnew TDomain(classVar, attrList);
 
   if (classDescriptions) {
-      newDomain->classes = mlnew TVarList();
       PITERATE(TPAttributeDescriptions, ai, classDescriptions) {
-          newDomain->classes->push_back(makeVariable(**ai, tStatus, createNewOn));
+          newDomain->classVars->push_back(makeVariable(**ai, tStatus, createNewOn));
       }
   }
 

File source/orange/examples.cpp

     raiseError("example needs domain");
 
   const int attrs = domain->variables->size();
-  const int classes = domain->classes ? domain->classes->size() : 0;
+  const int classes = domain->classVars->size();
   TValue *vi = values = mlnew TValue[attrs+classes];
   values_end = values + attrs;
   classes_end = values_end + classes;
   PITERATE(TVarList, di, dom->variables)
     *(vi++) = (*di)->DK();
-  if (dom->classes) {
-    PITERATE(TVarList, ci, dom->classes) {
-        *(vi++) = (*ci)->DK();
-    }
+  PITERATE(TVarList, ci, dom->classVars) {
+    *(vi++) = (*ci)->DK();
   }
   if (initMetas)
     ITERATE(TMetaVector, mi, dom->metas)
     raiseError("example needs a domain");
 
   const int attrs = domain->variables->size();
-  const int classes = domain->classes ? domain->classes->size() : 0;
+  const int classes = domain->classVars->size();
   values = mlnew TValue[attrs + classes];
   values_end = values + attrs;
   classes_end = values_end + classes;
 {
   if (!dom)
     raiseError("example needs a domain");
-  if (dom->classes) {
+  if (dom->classVars->size()) {
       raiseError("example merging does not support multiple classes");
   }
 
   const int attrs = domain->variables->size();
-  const int classes = domain->classes ? domain->classes->size() : 0;
+  const int classes = domain->classVars->size();
   vector<bool> defined(attrs, false);
 
   TValue *vi = values = mlnew TValue[attrs];
   if (domain != other.domain)
     raiseError("examples are from different domains");
 
-  int Na = domain->variables->size() + (domain->classes ? domain->classes->size() : 0);
+  int Na = domain->variables->size() + domain->classVars->size();
   if (!Na)
     return true;
   for (const_iterator vi1(begin()), vi2(other.begin()); (*vi1==*vi2) && --Na; vi1++, vi2++);
       }
   }
   else {
-      if (domain->classes) {
-          Na += domain->classes->size();
-      }
+      Na += domain->classVars->size();
   }
   if (!Na)
     return true;
       }
   }
   else {
-      if (domain->classes) {
-          Na += domain->classes->size();
-      }
+      Na += domain->classVars->size();
   }
   if (!Na)
     return true;
 {
   TValue *vli = values;
   ::addToCRC(crc, domain->variables, vli);
-  if (domain->classes)
-      ::addToCRC(crc, domain->classes, vli);
+  ::addToCRC(crc, domain->classVars, vli);
   
   if (includeMetas) {
     const_ITERATE(TMetaValues, mi, meta) {

File source/orange/lib_kernel.cpp

   PyCATCH_1
 }
 
-CONSTRUCTOR_KEYWORDS(Domain, "source")
+CONSTRUCTOR_KEYWORDS(Domain, "source class_vars")
 
 PyObject *Domain_new(PyTypeObject *type, PyObject *args, PyObject *keywds) BASED_ON(Orange - Orange.data.Domain, "(list-of-attrs | domain [, hasClass | classVar | None] [,domain | list-of-attrs | source=domain])")
 { PyTRY
     PyObject *list;
     PyObject *arg1 = PYNULL;
     PyObject *arg2 = PYNULL;
+    PyObject *pyclassvars = PYNULL;
 
     if (PyArg_ParseTuple(args, "O|OO", &list, &arg1, &arg2)) {
 
       if (keywds) {
-        if (PyDict_Size(keywds)>1)
-          PYERROR(PyExc_TypeError, "Domain() accepts only one keyword argument ('source')", PYNULL);
-        if (PyDict_Size(keywds)==1) {
-          PyObject *arg3 = PyDict_GetItemString(keywds, "source");
-          if (!arg3)
-            PYERROR(PyExc_TypeError, "Domain: invalid keywords argument ('source' expected)", PYNULL);
-          if (arg1 && arg2) {
-            PYERROR(PyExc_TypeError, "Domain: too many arguments", PYNULL);
+          PyObject *key, *value;
+          Py_ssize_t pos = 0;
+          while (PyDict_Next(keywds, &pos, &key, &value)) {
+              if (!PyString_Check(key)) {
+                  Py_XDECREF(pyclassvars);
+                  PYERROR(PyExc_TypeError, "keyword argument name must be a string", PYNULL);
+              }
+              if (!strcmp(PyString_AS_STRING(key), "source")) {
+                  if (arg1 && arg2) {
+                      Py_XDECREF(pyclassvars);
+                      PYERROR(PyExc_TypeError, "Domain: too many arguments", PYNULL);
+                  }
+                  Py_INCREF(value);
+                  if (!arg1) {
+                      arg1 = value;
+                  }
+                  else {
+                      arg2 = value;
+                  }
+              }
+              else if (!strcmp(PyString_AS_STRING(key), "class_vars")) {
+                  Py_INCREF(value);
+                  pyclassvars = value;
+              }
+              else {
+                  Py_XDECREF(pyclassvars);
+                  PyErr_Format(PyExc_ValueError, "unexpected keyword argument '%s'", PyString_AS_STRING(key));
+                  return PYNULL;
+              }
           }
-          else
-            if (!arg1)
-              arg1 = arg3;
-            else
-              arg2 = arg3;
-        }
       }
 
-
       if (PyOrDomain_Check(list)) {
 
         PDomain dom = PyOrange_AsDomain(list);
-
-        if (arg1)
+        TDomain *newdomain = NULL;
+
+        if (arg1) {
           if (PyString_Check(arg1) || PyOrVariable_Check(arg1)) {
             PVariable classVar = varFromArg_byDomain(arg1, dom, false);
-            if (!classVar)
-              return PYNULL;
+            if (!classVar) {
+                Py_XDECREF(pyclassvars);
+                return PYNULL;
+            }
             TVarList attributes = dom->variables.getReference();
             int vnumint = dom->getVarNum(classVar, false);
-            if (vnumint>=0)
-              attributes.erase(attributes.begin()+vnumint);
-            return WrapNewOrange(mlnew TDomain(classVar, attributes), type);
+            if (vnumint>=0) {
+                attributes.erase(attributes.begin()+vnumint);
+            }
+            newdomain = mlnew TDomain(classVar, attributes);
           }
           else if (PyInt_Check(arg1) || (arg1==Py_None)) {
             TVarList attributes = dom->variables.getReference();
             if (PyObject_IsTrue(arg1))
-              return WrapNewOrange(CLONE(TDomain, dom), type);
+                newdomain = CLONE(TDomain, dom), type;
             else
-              return WrapNewOrange(mlnew TDomain(PVariable(), dom->variables.getReference()), type);
+                newdomain = mlnew TDomain(PVariable(), dom->variables.getReference());
           }
-          else
-            PYERROR(PyExc_TypeError, "Domain: invalid arguments for constructor (I'm unable to guess what you meant)", PYNULL);
-
-        return WrapNewOrange(CLONE(TDomain, dom), type);
+          else {
+              Py_XDECREF(pyclassvars);
+              PYERROR(PyExc_TypeError, "Domain: invalid arguments for constructor (I'm unable to guess what you meant)", PYNULL);
+          }
+        }
+        else {
+           newdomain = CLONE(TDomain, dom);
+        }
+        if (pyclassvars) {
+            if (!varListFromVarList(pyclassvars, dom->variables, newdomain->classVars.getReference(), false, false)) {
+                Py_DECREF(pyclassvars);
+                mldelete newdomain;
+                return PYNULL;
+            }
+            Py_DECREF(pyclassvars);
+        }
+        return WrapNewOrange(newdomain, type);
       }
 
       /* Now, arg1 can be either
         variables.erase(variables.end()-1);
       }
 
-      return WrapNewOrange(mlnew TDomain(classVar, variables), type);
+      TDomain *newdomain = mlnew TDomain(classVar, variables);
+      if (pyclassvars) {
+          if (!varListFromVarList(pyclassvars, source, newdomain->classVars.getReference(), false, false)) {
+              Py_DECREF(pyclassvars);
+              mldelete newdomain;
+              return PYNULL;
+          }
+          Py_DECREF(pyclassvars);
+      }
+      return WrapNewOrange(newdomain, type);
     }
 
     PYERROR(PyExc_TypeError, "invalid parameters (list of 'Variable' expected)", PYNULL);
   PyCATCH
 }
 
+PyObject *ExampleTable_pickClass(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Variable | name) -> None")
+{
+    PyTRY
+        CAST_TO(TExampleTable, table);
+        if (!table->ownsExamples) {
+            PYERROR(PyExc_TypeError, "tables containing references to examples cannot change domain", PYNULL);
+        }
+        PVariable newClass;
+        if (PyString_Check(obj)) {
+            const char *attr = PyString_AS_STRING(obj);
+            TVarList::const_iterator mci(table->domain->classVars->begin()), mce(table->domain->classVars->end());
+            for(; (mci != mce) && ((*mci)->get_name() != attr); mci++);
+            if (mci == mce) {
+                PYERROR(PyExc_TypeError, "table does not have multiple classes", PYNULL);
+            }
+            newClass = *mci;
+        }
+        if (PyOrVariable_Check(obj)) {
+            newClass = PyOrange_AsVariable(obj);
+        }
+        else if (obj != Py_None) {
+            PYERROR(PyExc_TypeError, "class should be given as Variable, name or None", PYNULL);
+        }
+        table->pickClass(newClass);
+        RETURN_NONE;
+    PyCATCH;
+}
+
+
 
 PyObject *ExampleTable_hasMissingValues(TPyOrange *self) PYARGS(0, "() -> bool")
 {

File source/orange/tabdelim.cpp

           }
           else if (classPoses && (cp != ce) && (pos == *cp)) {
               const int ind = cp - cb;
-              domain->classes->at(ind)->filestr2val(valstr, exam.values_end[ind], exam);
+              domain->classVars->at(ind)->filestr2val(valstr, exam.values_end[ind], exam);
               cp++;
           }
           else { // if this is a normal value
      waste time studying it since we are moving to 3.0 */
   else if (classPoses && (cp != ce) && (pos == *cp)) {
     const int ind = cp - cb;
-    domain->classes->at(ind)->filestr2val(ai==atoms.end() ? "?" : *(ai++), exam.values_end[ind], exam);
+    domain->classVars->at(ind)->filestr2val(ai==atoms.end() ? "?" : *(ai++), exam.values_end[ind], exam);
   }
 
   while ((ai!=atoms.end()) && !(*ai).length()) ai++; // line must be empty from now on

File source/orange/table.cpp

 }
 
 
+void TExampleTable::pickClass(PVariable classVar)
+{
+    if (!ownsExamples) {
+        raiseError("Cannot change the class in a table of references");
+    }
+    const int attrs = domain->attributes->size();
+    const int classes = domain->classVars->size();
+    TDomain *newDomain;
+    int classPos;
+    int end_off = 0;
+    if (!classVar) {
+        if (!classes) {
+            return;
+        }
+        end_off = -1;
+        newDomain = mlnew TDomain(classVar, domain->attributes.getReference()); // No class
+        newDomain->classVars->push_back(domain->classVar);
+        PITERATE(TVarList, ci, domain->classVars) {
+            if (*ci != classVar) {
+                newDomain->classVars->push_back(*ci);
+            }
+        }
+        classPos = attrs;
+    }
+    else {
+        classPos = attrs;
+        if (domain->classVar) {
+            classPos += 1;
+        }
+        else {
+            end_off += 1;
+        }
+        TVarList::const_iterator mci(domain->classVars->begin()), mce(domain->classVars->end());
+        for(; (mci != mce) && (*mci != classVar); ++mci, ++classPos);
+        if (mci == mce) {
+            raiseError("Domain has no class %s", classVar->get_name());
+        }
+        newDomain = mlnew TDomain(classVar, domain->attributes.getReference());
+        newDomain->classVars = mlnew TVarList();
+        PITERATE(TVarList, ci, domain->classVars) {
+            if (*ci == classVar) {
+                if (domain->classVar) {
+                    newDomain->classVars->push_back(domain->classVar);
+                }
+            }
+            else {
+                newDomain->classVars->push_back(*ci);
+            }
+        }
+    }
+    ITERATE(TMetaVector, mi, domain->metas) {
+        newDomain->metas.push_back(*mi);
+    }
+    PDomain wdomain = newDomain;
+    domain = wdomain;
+    for(TExample **ri = examples; ri != _Last; ri++) {
+        (**ri).domain = wdomain;
+        if (classPos != attrs) {
+            TValue t = (**ri).values[attrs];
+            (**ri).values[attrs] = (**ri).values[classPos];
+            (**ri).values[classPos] = t;
+        }
+        (**ri).values_end += end_off;
+    }
+}
+
 void TExampleTable::addMetaAttribute(const int &id, const TValue &value)
 { 
   PEITERATE(ei, this)

File source/orange/table.hpp

   bool randomExample(TExample &);
 
   virtual void changeDomain(PDomain, bool filterMetas = false);
+  virtual void pickClass(PVariable);
 
 protected:
   virtual void increaseIterator(TExampleIterator &);