⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 domaindepot.cpp

📁 orange源码 数据挖掘技术
💻 CPP
字号:
/*
    This file is part of Orange.

    Orange is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    Orange is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Orange; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    Authors: Janez Demsar, Blaz Zupan, 1996--2002
    Contact: janez.demsar@fri.uni-lj.si
*/


#include "vars.hpp"
#include "domain.hpp"

#include "stringvars.hpp"

#include "domaindepot.hpp"


extern TOrangeType PyOrVariable_Type;
extern TOrangeType PyOrPythonVariable_Type;
#include "pythonvars.hpp"
#include "c2py.hpp"

typedef vector<pair<string, PyObject *> > TPythonVariablesRegistry;

TPythonVariablesRegistry pythonVariables;

void registerVariableType(PyObject *variable)
{
  const char *varname;

  if (!PyType_IsSubtype((PyTypeObject *)variable, (PyTypeObject *)&PyOrPythonVariable_Type))
    raiseErrorWho("registerVariableType", "variable type must be derived from PythonVariable");

  PyObject *pyclassname = PyObject_GetAttrString(variable, "__name__");
  if (!pyclassname)
    raiseErrorWho("registerVariableType", "variable type misses the '__name__'");
  varname = PyString_AsString(pyclassname);
  // it won't go away
  Py_DECREF(pyclassname);

  TPythonVariablesRegistry::iterator bi(pythonVariables.begin()), be(pythonVariables.end());
  for(; (bi != be) && ((*bi).first != varname); bi++);

  Py_INCREF(variable);
  if (bi==be)
    pythonVariables.push_back(make_pair(string(varname), variable));
  else {
    Py_DECREF((*bi).second);
    (*bi).second = variable;
  }
}

void pythonVariables_unsafeInitializion()
{
  pythonVariables.push_back(make_pair(string("PythonVariable"), (PyObject *)&PyOrPythonVariable_Type));
}

bool pythonDeclarationMatches(const string &declaration, PVariable var)
{
  PyObject *classname = PyObject_GetAttrString((PyObject *)(var.counter), "__class__");
  PyObject *typenamee = PyObject_GetAttrString(classname, "__name__");
  bool res = !strcmp(PyString_AsString(typenamee), (declaration.size()>6) ? declaration.c_str()+7 : "PythonVariable");
  Py_DECREF(classname);
  Py_DECREF(typenamee);
  return res;
}



PDomain combineDomains(PDomainList sources, TDomainMultiMapping &mapping)
{
  PVariable classVar;
  // I would use reverse iterators, but don't have them
  TDomainList::const_iterator cri(sources->end()), cre(sources->begin());
  while(!(*--cri)->classVar && (cri!=cre));
  classVar = (*cri)->classVar; // might have stopped at the classvar and reached cre which has none...
      
  TVarList variables;

  mapping.clear();
  vector<pair<int, int> > classMapping;

  int domainIdx = 0;
  TDomainList::const_iterator di(sources->begin()), de(sources->end());
  for(; di!=de; di++, domainIdx++) {

    int varIdx = 0;
    TVarList::const_iterator vi((*di)->variables->begin()), ve((*di)->variables->end());
    for(; vi!=ve; vi++, varIdx++) {
      if (*vi == classVar)
        classMapping.push_back(make_pair(domainIdx, varIdx));
      else {
        TDomainMultiMapping::iterator dmmi(mapping.begin());
        TVarList::const_iterator hvi(variables.begin()), hve(variables.end());
        for(; (hvi!=hve) && (*hvi != *vi); hvi++, dmmi++);
        if (hvi==hve) {
          variables.push_back(*vi);
          mapping.push_back(vector<pair<int, int> >());
          mapping.back().push_back(make_pair(domainIdx, varIdx));
        }
        else
          (*dmmi).push_back(make_pair(domainIdx, varIdx));
      }
    }
  }

  if (classVar)
    mapping.push_back(classMapping);

  TDomain *newDomain = mlnew TDomain(classVar, variables);
  PDomain wdomain = newDomain;

  for(domainIdx = 0, di = sources->begin(); di!=de; domainIdx++, di++)
    const_ITERATE(TMetaVector, mi, (*di)->metas) {
      PVariable metavar = newDomain->getMetaVar((*mi).id, false);
      if (!metavar)
        newDomain->metas.push_back(*mi);
      else
        if (metavar != (*mi).variable)
          raiseError("Id %i represents two different attributes ('%s' and '%s')", (*mi).id, metavar->name.c_str(), (*mi).variable->name.c_str());
    }

  return wdomain;
}


void computeMapping(PDomain destination, PDomainList sources, TDomainMultiMapping &mapping)
{
  mapping.clear();
  const_PITERATE(TVarList, vi, destination->variables) {
    mapping.push_back(vector<pair<int, int> >());
    int domainIdx = 0;
    TDomainList::const_iterator si(sources->begin()), se(sources->end());
    for(; si!=se; si++, domainIdx++) {
      int pos = (*si)->getVarNum(*vi, false);
      if (pos != ILLEGAL_INT)
        mapping.back().push_back(make_pair(domainIdx, pos));
    }
  }
}



TDomainDepot::TAttributeDescription::TAttributeDescription(const string &n, const int &vt, const string &td, bool ord)
: name(n),
  varType(vt),
  typeDeclaration(td),
  ordered(ord)
{}


TDomainDepot::TAttributeDescription::TAttributeDescription(const string &n, const int &vt)
: name(n),
  varType(vt),
  typeDeclaration(),
  ordered(false)
{}


TDomainDepot::~TDomainDepot()
{
  ITERATE(list<TDomain *>, di, knownDomains) {
    // this could be done by some remove_if, but I don't want to fight
    //   all various implementations of STL
    list<TDomain::TDestroyNotification>::iterator src((*di)->destroyNotifiers.begin()), end((*di)->destroyNotifiers.end());
    for(; (src!=end) && ((const TDomainDepot *)((*src).second) != this); src++);
    (*di)->destroyNotifiers.erase(src);
  }
}


void TDomainDepot::destroyNotifier(TDomain *domain, void *data)
{ 
  ((TDomainDepot *)(data))->knownDomains.remove(domain);
}

                  
bool TDomainDepot::checkDomain(const TDomain *domain, 
                               const TAttributeDescriptions *attributes, bool hasClass,
                               const TAttributeDescriptions *metas,
                               int *metaIDs)
{
  // check the number of attributes and meta attributes, and the presence of class attribute
  if (    (domain->variables->size() != attributes->size())
       || (bool(domain->classVar) != hasClass)
       || (metas ? (metas->size() != domain->metas.size()) : domain->metas.size() )
     )
    return false;

  // check the names and types of attributes
  TVarList::const_iterator vi(domain->variables->begin());
  const_PITERATE(TAttributeDescriptions, ai, attributes)
    if (    ((*ai).name != (*vi)->name)
         || ((*ai).varType>0) && ((*ai).varType != (*vi)->varType)
         || (((*ai).varType==PYTHONVAR) && !pythonDeclarationMatches((*ai).typeDeclaration, *vi))
       )
      return false;
    else
      vi++;

  // check the meta attributes if they exist
  if (metas)
    const_PITERATE(TAttributeDescriptions, mi, metas) {
      PVariable var = domain->getMetaVar((*mi).name, false);
      if (    !var
           || (((*mi).varType > 0) && ((*mi).varType != var->varType))
           || (((*mi).varType==PYTHONVAR) && !pythonDeclarationMatches((*mi).typeDeclaration, var))
         )
        return false;
      if (metaIDs)
        *(metaIDs++) = domain->getMetaNum((*mi).name, false);
    }

  return true;
}


PDomain TDomainDepot::prepareDomain(const TAttributeDescriptions *attributes, bool hasClass,
                                    const TAttributeDescriptions *metas, PVarList knownVars,
                                    const TMetaVector *knownMetas,
                                    const bool dontStore, const bool dontCheckStored,
                                    bool *domainIsNew, int *metaIDs)
{ 
  if (!dontCheckStored)
    ITERATE(list<TDomain *>, kdi, knownDomains)
      if (checkDomain(*kdi, attributes, hasClass, metas, metaIDs)) {
        if (domainIsNew)
          *domainIsNew = false;
        return *kdi;
      }

  TVarList attrList;
  int foo;
  const_PITERATE(TAttributeDescriptions, ai, attributes) {
    PVariable newvar = makeVariable(*ai, foo, knownVars, knownMetas, false, false);
    if ((*ai).ordered)
      newvar->ordered = true;
    attrList.push_back(newvar);
  }

  PDomain newDomain;

  PVariable classVar;
  if (hasClass) {
    classVar = attrList.back();
    attrList.erase(attrList.end()-1);
  }
  
  newDomain = mlnew TDomain(classVar, attrList);

  if (metas)
    const_PITERATE(TAttributeDescriptions, mi, metas) {
      int id;
      PVariable var = makeVariable(*mi, id, knownVars, knownMetas, false, true);
      if (!id)
        id = getMetaID();
      newDomain->metas.push_back(TMetaDescriptor(id, var));
      if (metaIDs)
        *(metaIDs++) = id;
    }
    
  if (domainIsNew)
    *domainIsNew = true;

  if (!dontStore) {
    newDomain->destroyNotifiers.push_back(TDomain::TDestroyNotification(&TDomainDepot::destroyNotifier, this));
    knownDomains.push_front(newDomain.getUnwrappedPtr());
  }

  return newDomain;
}

PVariable TDomainDepot::createVariable_Python(const string &typeDeclaration, const string &name)
{
  if (typeDeclaration.size() == 6) {
    TPythonVariable *var = mlnew TPythonVariable();
    var->name = name;
    return var;
  }


  char *vartypename = const_cast<char *>(typeDeclaration.c_str()+7);
  char *parpos = strchr(vartypename, '(');
  PyObject *var = NULL;

  if (!parpos) {
    TPythonVariablesRegistry::iterator bi(pythonVariables.begin()), be(pythonVariables.end());
    for(; (bi != be) && strcmp((*bi).first.c_str(), vartypename); bi++);

    if (bi!=be) {
      var = PyObject_CallFunction((*bi).second, NULL);
      if (!var)
        throw pyexception();
    }
  }

  if (!var) {
    PyObject *globals = PyEval_GetGlobals();
    PyObject *locals = PyEval_GetLocals();

    var = PyRun_String(vartypename, Py_eval_input, globals, locals);
    if (!parpos && (!var || PyType_Check(var))) {
      PyErr_Clear();
      const int slen = strlen(vartypename);
      char *wPar = strcpy(new char [slen + 3], vartypename);
      strcpy(wPar+slen, "()");
      var = PyRun_String(wPar, Py_eval_input, globals, locals);
    }
  
    if (!var)
      // if parentheses were given, this is the exception from the first call, else from the second
      throw pyexception();
  }

  if (!PyObject_TypeCheck(var, (PyTypeObject *)&PyOrVariable_Type))
    ::raiseErrorWho("makeVariable", "PythonVariable's constructor is expected to return a 'PythonVariable', not '%s'", var->ob_type->tp_name);

  PVariable pvar = GCPtr<TOrange>((TPyOrange *)var, true);
  Py_DECREF(var);

  pvar->name = name;
  return pvar;
}

PVariable TDomainDepot::createVariable(const TAttributeDescription &desc)
{
  switch (desc.varType) {
    case TValue::INTVAR: {
      TEnumVariable *evar = mlnew TEnumVariable(desc.name, desc.values ? desc.values : PStringList(mlnew TStringList()));
      if (desc.ordered)
        evar->ordered = true;
      return evar;
    }

    case TValue::FLOATVAR:
      return mlnew TFloatVariable(desc.name);

    case STRINGVAR:
      return mlnew TStringVariable(desc.name);

    case PYTHONVAR:
      return createVariable_Python(desc.typeDeclaration, desc.name);
  }

  if (desc.varType==-1)
    ::raiseErrorWho("makeVariable", "unknown type for attribute '%s'", desc.name.c_str());

  return (TVariable *)NULL;
}


PVariable TDomainDepot::makeVariable(const TAttributeDescription &desc, int &id, PVarList knownVars, const TMetaVector *metas, bool dontCreateNew, bool preferMetas)
{ 
  if (!preferMetas && knownVars)
    const_PITERATE(TVarList, vi, knownVars)
      if (   ((*vi)->name==desc.name)
          && (    (desc.varType==-1)
               || (desc.varType==STRINGVAR) && (*vi).is_derived_from(TStringVariable)
               || ((*vi)->varType==desc.varType)
             )
          && ((desc.varType!=PYTHONVAR) || pythonDeclarationMatches(desc.typeDeclaration, *vi))
         ) {
        id = 0;
        return *vi;
      }

  if (metas)
    const_PITERATE(TMetaVector, mi, metas)
      if (   ((*mi).variable->name == desc.name)
          && (    (desc.varType == -1)
               || (desc.varType==STRINGVAR) && (*mi).variable.is_derived_from(TStringVariable)
               || ((*mi).variable->varType==desc.varType)
             )
          && ((desc.varType!=PYTHONVAR) || pythonDeclarationMatches(desc.typeDeclaration, (*mi).variable))
         ) {
        id = (*mi).id;
        return (*mi).variable;
      }

  if (preferMetas && knownVars)
    const_PITERATE(TVarList, vi, knownVars)
      if (   ((*vi)->name==desc.name)
          && (    (desc.varType==-1)
               || (desc.varType==STRINGVAR) && (*vi).is_derived_from(TStringVariable)
               || ((*vi)->varType==desc.varType)
             )
          && ((desc.varType!=PYTHONVAR) || pythonDeclarationMatches(desc.typeDeclaration, *vi))
         ) {
        id = 0;
        return *vi;
      }
  
  id = 0;

  return dontCreateNew ? PVariable() : createVariable(desc);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -