예제 #1
0
파일: Main.cpp 프로젝트: joergkappes/daoopt
bool Main::runLDS() {
#ifdef PARALLEL_STATIC
  if (m_options->par_postOnly)
    return true;  // skip LDS for static post mode
#endif
  // Run LDS if specified
  if (m_options->lds != NONE) {
    cout << "Running LDS with limit " << m_options->lds << endl;
    scoped_ptr<SearchSpace> spaceLDS(new SearchSpace(m_pseudotree.get(), m_options.get()));
    LimitedDiscrepancy lds(m_problem.get(), m_pseudotree.get(), spaceLDS.get(),
                           m_heuristic.get(), m_options->lds);
    if (!m_options->in_subproblemFile.empty()) {
      if (!lds.restrictSubproblem(m_options->in_subproblemFile)) {
        err_txt("Subproblem restriction for LDS failed.");
        return false;
      }
    }

    // load current best solution into LDS
    if (lds.updateSolution(m_problem->getSolutionCost()
#ifndef NO_ASSIGNMENT
        , m_problem->getSolutionAssg()
#endif
    ))
      cout << "LDS: Initial solution loaded." << endl;

    BoundPropagator propLDS(m_problem.get(), spaceLDS.get(), false);  // doCaching = false
    lds.finalizeHeuristic();
    SearchNode* n = lds.nextLeaf();
    while (n) {
      propLDS.propagate(n,true); // true = report solution
      n = lds.nextLeaf();
    }
    cout << "LDS: explored " << spaceLDS->stats.numExpOR << '/' << spaceLDS->stats.numExpAND
         << " OR/AND nodes" << endl;
    cout << "LDS: solution cost " << lds.getCurOptValue() << endl;

#ifndef NO_HEURISTIC
    if (m_search->getCurOptValue() >= m_heuristic->getGlobalUB()) {
      m_solved = true;
      cout << endl << "--------- Solved by LDS ---------" << endl;
    }
#endif
  }

  return true;
}
예제 #2
0
파일: Main.cpp 프로젝트: joergkappes/daoopt
bool Main::parseOptions(int argc, char** argv) {
  // Reprint command line
  for (int i=0; i<argc; ++i)
    cout << argv[i] << ' ';
  cout << endl;
  // parse command line
  ProgramOptions* opt = parseCommandLine(argc, argv);
  if (!opt) {
    err_txt("Error parsing command line.");
    return false;
  }

  if (opt->seed == NONE)
    opt->seed = time(0);
  rand::seed(opt->seed);

  m_options.reset(opt);
  return true;
}
예제 #3
0
파일: Main.cpp 프로젝트: joergkappes/daoopt
/* static master mode for distributed execution */
bool Main::runSearchStatic() {
  bool preOnly = m_options->par_preOnly, postOnly = m_options->par_postOnly,
        local = m_options->par_solveLocal;

  bool success = true;
  if (!postOnly) {
    success = success && m_search->doLearning();
  }
  if (true) {  // TODO
    /* find frontier from scratch */
    success = success && m_search->findFrontier();
  }
  if (!postOnly) {
    /* writes CSV with subproblem stats */
    success = success && m_search->writeSubprobStats();
  }
  if (!postOnly && !local) {
    /* generate files for subproblems */
    success = success && m_search->writeJobs();
    if (m_search->getSubproblemCount()==0) m_solved = true;
  }
  if (local && !preOnly) {
    /* solve external subproblems locally */
    success = success && m_search->extSolveLocal();
  }
  if (!local && !preOnly && !postOnly) {
    /* run Condor and wait for results */
    success = success && m_search->runCondor();
  }
  if (!local && !preOnly) {
    /* read external results */
    success = success && m_search->readExtResults();
  }

  if (!success) {
    myprint("!!! Search failed. !!!\n");
    err_txt("Main search routine failed.");
    return false;
  }

  return true;
}
예제 #4
0
SEXP R_export2dataset(SEXP path, SEXP dataframe, SEXP shape, SEXP shape_info)
{
  std::wstring dataset_name;
  tools::copy_to(path, dataset_name);

  struct _cleanup
  {
    typedef std::vector<cols_base*> c_type;
    std::vector<std::wstring> name;
    c_type c;
    //std::vector<c_type::const_iterator> shape;
    c_type shape;
    ~_cleanup()
    {
      for (size_t i = 0; i < c.size(); i++)
        delete c[i];
      for (size_t i = 0; i < shape.size(); i++)
        delete shape[i];
    }
  }cols;

  shape_extractor extractor;
  bool isShape = extractor.init(shape, shape_info) == S_OK;
  //SEXP sinfo = Rf_getAttrib(shape, Rf_mkChar("shape_info"));
  //cols.name = df.attr("names");
  tools::getNames(dataframe, cols.name);
  
  //tools::vectorGeneric shape_info(sinfo);
  //std::string gt_type;
  //tools::copy_to(shape_info.at("type"), gt_type);
  esriGeometryType gt = extractor.type();//str2geometryType(gt_type.c_str());
  R_xlen_t n = 0;

  ATLTRACE("dataframe type:%s", Rf_type2char(TYPEOF(dataframe)));

  if (Rf_isVectorList(dataframe))
  {
    size_t k = tools::size(dataframe);
    cols.name.resize(k);
    for (size_t i = 0; i < k; i++)
    {
      n = std::max(n, tools::size(VECTOR_ELT(dataframe, (R_xlen_t)i)));
      if (cols.name[i].empty())
        cols.name[i] = L"data";
    }
  }
  else
  {
    n = tools::size(dataframe);
    ATLASSERT(cols.name.empty());
  }

  if (isShape == false && n == 0)
    return showError<false>(L"nothing to save"), R_NilValue;

  if (isShape && n != extractor.size() )
    return showError<false>(L"length of shape != data.frame"), R_NilValue;

  CComPtr<IGPUtilities> ipDEUtil;
  if (ipDEUtil.CoCreateInstance(CLSID_GPUtilities) != S_OK)
    return showError<true>(L"IDEUtilitiesImpl - CoCreateInstance has failed"), R_NilValue;

  HRESULT hr = 0;

  CComPtr<IName> ipName;
  if (isShape)
    hr = ipDEUtil->CreateFeatureClassName(CComBSTR(dataset_name.c_str()), &ipName);
  else
    hr = ipDEUtil->CreateTableName(CComBSTR(dataset_name.c_str()), &ipName);

  CComQIPtr<IDatasetName> ipDatasetName(ipName);
  CComPtr<IWorkspaceName> ipWksName;
  CComQIPtr<IWorkspace> ipWks;
  if (hr == S_OK)
    hr = ipDatasetName->get_WorkspaceName(&ipWksName);
  if (hr == S_OK)
  {
    CComPtr<IUnknown> ipUnk;
    hr = CComQIPtr<IName>(ipWksName)->Open(&ipUnk);
    ipWks = ipUnk;
  }

  if (hr != S_OK)
    return showError<true>(L"invalid table name"), R_NilValue;
  
  CComQIPtr<IFeatureWorkspace> ipFWKS(ipWks);
  ATLASSERT(ipFWKS);
  if (!ipFWKS)
    return showError<true>(L"not a FeatureWorkspace"), R_NilValue;
  
  CComBSTR bstrTableName;
  ipDatasetName->get_Name(&bstrTableName);

  CComPtr<IFieldsEdit> ipFields;
  hr = ipFields.CoCreateInstance(CLSID_Fields);
  if (hr != S_OK) return showError<true>(L"CoCreateInstance"), R_NilValue;

  createField(NULL, esriFieldTypeOID, ipFields);

  CComPtr<ISpatialReference> ipSR;

  if (isShape)
  {
    long pos = createField(NULL, esriFieldTypeGeometry, ipFields);
    CComPtr<IGeometryDef> ipGeoDef;
    CComPtr<IField> ipField;
    ipFields->get_Field(pos, &ipField);
    ipField->get_GeometryDef(&ipGeoDef);
    
    CComQIPtr<IGeometryDefEdit> ipGeoDefEd(ipGeoDef);
    ipGeoDefEd->put_GeometryType(gt);
    ipGeoDefEd->putref_SpatialReference(extractor.sr());
  }

  if (cols.name.empty())
  {
    cols.name.push_back(L"data");
    cols_base* item = setup_field(ipFields, dataframe, cols.name[0].c_str());
    if (!item)
      return showError<false>(L"unsupported datat.field column type"), NULL;
    cols.c.push_back(item);
    item->name_ref = &cols.name[0];
  }
  else
    for (size_t i = 0; i < cols.name.size(); i++)
    {
      if (cols.name[i].empty())
        continue;
      const wchar_t* str = cols.name[i].c_str();
      SEXP it = VECTOR_ELT(dataframe, (R_len_t)i);
      cols_base* item = setup_field(ipFields, it, str);
      if (!item)
        return showError<false>(L"unsupported datat.field column type"), NULL;
      cols.c.push_back(item);
      item->name_ref = &cols.name[i];
    }

  CComPtr<IFieldChecker> ipFieldChecker; ipFieldChecker.CoCreateInstance(CLSID_FieldChecker);  
  if (ipFieldChecker)
  {
    ipFieldChecker->putref_ValidateWorkspace(ipWks);
    long error = 0;

    //fix fields names
    CComPtr<IFields> ipFixedFields;
    
    CComPtr<IEnumFieldError> ipEError;
    hr = ipFieldChecker->Validate(ipFields, &ipEError, &ipFixedFields);
    if (hr != S_OK)
      return showError<true>(L"validate fields failed"), NULL;
  
    if (ipFixedFields)
    {
      ipFields = ipFixedFields;
      for (size_t c = 0; c < cols.c.size(); c++)
      {
        CComPtr<IField> ipFixedField;
        ipFixedFields->get_Field(cols.c[c]->pos, &ipFixedField);
        _bstr_t name;
        ipFixedField->get_Name(name.GetAddress());
        cols.c[c]->name_ref->assign(name);
      }
    }
  }

  CComPtr<IUID> ipUID; ipUID.CoCreateInstance(CLSID_UID);
  if (ipUID)
  {
    OLECHAR buf[256];
    ::StringFromGUID2(isShape ? CLSID_Feature : CLSID_Row, buf, 256);
    ipUID->put_Value(CComVariant(buf));
  }

  CComQIPtr<ITable> ipTableNew;
  CComBSTR keyword(L"");
  hr = E_FAIL;
  if (isShape)
  {
    CComPtr<IFeatureClass> ipFClass;
    hr = ipFWKS->CreateFeatureClass(bstrTableName, ipFields, ipUID, 0, esriFTSimple, CComBSTR(L"Shape"), keyword, &ipFClass);
    ipTableNew = ipFClass;
  }
  else
  {
    hr = ipFWKS->CreateTable(bstrTableName, ipFields, ipUID, 0, keyword, &ipTableNew);
  }
  if (hr != S_OK)
  {
    std::wstring err_txt(isShape ? L"Create FeatureClass :" : L"Create Table :");
    err_txt += bstrTableName;
    err_txt += L" has failed";
    return showError<true>(err_txt.c_str()), R_NilValue;
  }

  CComVariant oid;

  CComPtr<ICursor> ipCursor;
  CComPtr<IRowBuffer> ipRowBuffer;
  hr = ipTableNew->Insert(VARIANT_TRUE, &ipCursor);
  if (hr != S_OK)
    return showError<true>(L"Insert cursor failed"), R_NilValue;
  hr = ipTableNew->CreateRowBuffer(&ipRowBuffer);
  if (hr != S_OK)
    return showError<true>(L"Insert cursor failed"), R_NilValue;
  
  //re-map fields
  CComPtr<IFields> ipRealFields;
  ipCursor->get_Fields(&ipRealFields);
  for (size_t c = 0; c < cols.c.size(); c++)
  {
    ipRealFields->FindField(CComBSTR(cols.c[c]->name_ref->c_str()), &(cols.c[c]->pos));
    CComPtr<IField> ipField;
    ipRealFields->get_Field(cols.c[c]->pos, &ipField);
    VARIANT_BOOL b = VARIANT_FALSE;
    ipField->get_IsNullable(&b);
    if (b == VARIANT_FALSE)
    {
      esriFieldType ft = esriFieldTypeInteger;
      ipField->get_Type(&ft);
      switch(ft)
      {
        case esriFieldTypeInteger:
          cols.c[c]->vNULL = 0;//std::numeric_limits<int>::min();
          break;
        case esriFieldTypeDouble:
          cols.c[c]->vNULL = 0.0;//-std::numeric_limits<double>::max();
          break;
        case esriFieldTypeString:
          cols.c[c]->vNULL = L"";
      }
    }
  }

  CComQIPtr<IFeatureBuffer> ipFBuffer(ipRowBuffer);
  for (R_len_t i = 0; i < n; i++)
  {
    //ATLTRACE("\n");
    for (size_t c = 0; c < cols.c.size(); c++)
    {
      if (cols.c[c]->pos < 0)
        continue;
      CComVariant val;
      cols.c[c]->get(i, val);
      if (val.vt == VT_NULL)
        hr = ipRowBuffer->put_Value(cols.c[c]->pos, cols.c[c]->vNULL);
      else
        hr = ipRowBuffer->put_Value(cols.c[c]->pos, val);
      if (FAILED(hr))
        return showError<true>(L"insert row value failed"), R_NilValue;
    }
    VARIANT oid;

    if (isShape)
    {
      ATLASSERT(ipFBuffer);
      CComQIPtr<IGeometry> ipNewShape;
      hr = extractor.at(i, &ipNewShape);
      if (hr != S_OK)
        return R_NilValue;

      hr = ipFBuffer->putref_Shape(ipNewShape);
      if (FAILED(hr))
        return showError<true>(L"insert shape failed"), R_NilValue;
    }

    hr = ipCursor->InsertRow(ipRowBuffer, &oid);
    if (hr != S_OK)
      return showError<true>(L"insert row failed"), R_NilValue;
  }
  return R_NilValue;
}
예제 #5
0
파일: Main.cpp 프로젝트: joergkappes/daoopt
bool Main::compileHeuristic() {
  m_options->ibound = min(m_options->ibound, m_pseudotree->getWidthCond());
  size_t sz = 0;
  if (m_options->memlimit != NONE) {
    sz = m_heuristic->limitSize(m_options->memlimit,
                                & m_search->getAssignment() );
    sz *= sizeof(double) / (1024*1024.0);
    cout << "Enforcing memory limit resulted in i-bound " << m_options->ibound
         << " with " << sz << " MByte." << endl;
  }

  if (m_options->nosearch) {
    cout << "Simulating mini bucket heuristic..." << endl;
    sz = m_heuristic->build(& m_search->getAssignment(), false); // false = just compute memory estimate
  }
  else {
    time(&_time_pre);
    bool mbFromFile = false;
    if (!m_options->in_minibucketFile.empty()) {
      mbFromFile = m_heuristic->readFromFile(m_options->in_minibucketFile);
      sz = m_heuristic->getSize();
    }
    if (!mbFromFile) {
      cout << "Computing mini bucket heuristic..." << endl;
      sz = m_heuristic->build(& m_search->getAssignment(), true); // true =  actually compute heuristic
      time_t cur_time;
      time(&cur_time);
      double time_passed = difftime(cur_time, _time_pre);
      cout << "\tMini bucket finished in " << time_passed << " seconds" << endl;
    }
    if (!mbFromFile && !m_options->in_minibucketFile.empty()) {
      cout << "\tWriting mini bucket to file " << m_options->in_minibucketFile << " ..." << flush;
      m_heuristic->writeToFile(m_options->in_minibucketFile);
      cout << " done" << endl;
    }
  }
  cout << '\t' << (sz / (1024*1024.0)) * sizeof(double) << " MBytes" << endl;

  // heuristic might have changed problem functions, pseudotree needs remapping
  m_pseudotree->addFunctionInfo(m_problem->getFunctions());

  // set initial lower bound if provided (but only if no subproblem was specified)
  if (m_options->in_subproblemFile.empty() ) {
    if (m_options->in_boundFile.size()) {
      cout << "Loading initial lower bound from file " << m_options->in_boundFile << '.' << endl;
      if (!m_search->loadInitialBound(m_options->in_boundFile)) {
        err_txt("Loading initial bound failed");
        return false;
      }
    } else if (!ISNAN ( m_options->initialBound )) {
#ifdef NO_ASSIGNMENT
      cout <<  "Setting external lower bound " << m_options->initialBound << endl;
      m_search->updateSolution(m_options->initialBound);
#else
      err_txt("Compiled with tuple support, value-based bound not possible.");
      return false;
#endif
    }
  }

#ifndef NO_HEURISTIC
  if (m_search->getCurOptValue() >= m_heuristic->getGlobalUB()) {
    m_solved = true;
    cout << endl << "--------- Solved during preprocessing ---------" << endl;
  }
  else if (m_heuristic->isAccurate()) {
    cout << endl << "Heuristic is accurate!" << endl;
    m_options->lds = 0; // set LDS to 0 (sufficient given perfect heuristic)
    m_solved = true;
  }
#endif

  return true;
}
예제 #6
0
파일: Main.cpp 프로젝트: joergkappes/daoopt
bool Main::initDataStructs() {

  // The main search space
#ifdef PARALLEL_DYNAMIC
  m_space.reset( new SearchSpaceMaster(m_pseudotree.get(), m_options.get()) );
#else
  m_space.reset( new SearchSpace(m_pseudotree.get(), m_options.get()) );
#endif

  // Heuristic is initialized here, built later in compileHeuristic()
#ifdef NO_HEURISTIC
  m_heuristic.reset(new UnHeuristic);
#else
  m_heuristic.reset(new MiniBucketElim(m_problem.get(), m_pseudotree.get(),
				       m_options.get(), m_options->ibound) );
#endif

  // Main search engine
#if defined PARALLEL_DYNAMIC
  m_search.reset(new BranchAndBoundMaster(m_problem.get(), m_pseudotree.get(),
                                          m_space.get(), m_heuristic.get())); // TODO
#elif defined PARALLEL_STATIC
  m_search.reset(new ParallelManager(m_problem.get(), m_pseudotree.get(),
                                     m_space.get(), m_heuristic.get()));
#else
  if (m_options->rotate) {
    m_search.reset(new BranchAndBoundRotate(
        m_problem.get(), m_pseudotree.get(), m_space.get(), m_heuristic.get()));
  } else {
    m_search.reset(new BranchAndBound(
        m_problem.get(), m_pseudotree.get(), m_space.get(), m_heuristic.get()));
  }
#endif

  // Subproblem specified? If yes, restrict.
  if (!m_options->in_subproblemFile.empty()) {
    if (m_options->in_orderingFile.empty()) {
      err_txt("Subproblem specified but no ordering given.");
      return false;
    }else {
      m_problem->setSubprobOnly();
      m_options->order_iterations = 0;
      cout << "Reading subproblem from file " << m_options->in_subproblemFile << '.' << endl;
      if (!m_search->restrictSubproblem(m_options->in_subproblemFile) ) {
        err_txt("Subproblem restriction failed.");
        return false;
      }
    }
  }

  cout << "Induced width:\t\t" << m_pseudotree->getWidthCond()
       << " / " << m_pseudotree->getWidth() << endl;
  cout << "Pseudotree depth:\t" << m_pseudotree->getHeightCond()
       << " / " << m_pseudotree->getHeight() << endl;
  cout << "Problem variables:\t" << m_pseudotree->getSizeCond()
       <<  " / " << m_pseudotree->getSize() << endl;
#ifdef PARALLEL_STATIC
  cout << "State space bound:\t" << m_pseudotree->getStateSpaceCond() << endl;
#endif
  cout << "Disconn. components:\t" << m_pseudotree->getComponentsCond()
       << " / " << m_pseudotree->getComponents() << endl;

#ifdef MEMDEBUG
  malloc_stats();
#endif

  return true;
}
예제 #7
0
파일: Main.cpp 프로젝트: joergkappes/daoopt
bool Main::findOrLoadOrdering() {
  // Create primal graph of *reduced* problem
  Graph g(m_problem->getN());
  const vector<Function*>& fns = m_problem->getFunctions();
  for (vector<Function*>::const_iterator it = fns.begin(); it != fns.end(); ++it) {
    g.addClique((*it)->getScopeVec());
  }
  cout << "Graph with " << g.getStatNodes() << " nodes and "
       << g.getStatEdges() << " edges created." << endl;

#ifdef PARALLEL_STATIC
  // for static parallelization post-processing mode, look for
  // ordering from preprocessing step
  if (m_options->par_postOnly) {
    m_options->in_orderingFile = string("temp_elim.") + m_options->problemName
        + string(".") + m_options->runTag + string(".gz");
    m_options->order_iterations = 0;
  }
#endif

  // Find variable ordering
  vector<int> elim;
  int w = numeric_limits<int>::max();
  bool orderFromFile = false;
  if (!m_options->in_orderingFile.empty()) {
    orderFromFile = m_problem->parseOrdering(m_options->in_orderingFile, elim);
  }

  // Init. pseudo tree
  m_pseudotree.reset(new Pseudotree(m_problem.get(), m_options->subprobOrder));

  if (orderFromFile) { // Reading from file succeeded (i.e. file exists)
    m_pseudotree->build(g, elim, m_options->cbound);
    w = m_pseudotree->getWidth();
    cout << "Read elimination ordering from file " << m_options->in_orderingFile
         << " (" << w << '/' << m_pseudotree->getHeight() << ")." << endl;
  } else {
    if (m_options->order_timelimit == NONE)
      // compute at least one
      m_options->order_iterations = max(1, m_options->order_iterations);
  }

  time_t time_order_start, time_order_cur;
  double timediff = 0.0;
  time(&time_order_start);

  // Search for variable elimination ordering, looking for min. induced
  // width, breaking ties via pseudo tree height
  cout << "Searching for elimination ordering,";
  if (m_options->order_iterations != NONE)
    cout << " " << m_options->order_iterations << " iterations";
  if (m_options->order_timelimit != NONE)
    cout << " " << m_options->order_timelimit << " seconds";
  cout << ":" << flush;

  int iterCount=0, sinceLast=0;
  int remaining = m_options->order_iterations;

  while (true) {

    if (m_options->order_iterations != NONE && remaining == 0)
      break;

    vector<int> elimCand;  // new ordering candidate
    bool improved = false;  // improved in this iteration?
    int new_w = m_pseudotree->eliminate(g, elimCand, w, m_options->order_tolerance);
    if (new_w < w) {
      elim = elimCand; w = new_w; improved = true;
      m_pseudotree->build(g, elimCand, m_options->cbound);
      cout << " " << iterCount << ':' << w <<'/' << m_pseudotree->getHeight() << flush;
    } else if (new_w == w) {
      Pseudotree ptCand(m_problem.get(), m_options->subprobOrder);
      ptCand.build(g, elimCand, m_options->cbound);
      if (ptCand.getHeight() < m_pseudotree->getHeight()) {
        elim = elimCand; improved = true;
        m_pseudotree->build(g, elim, m_options->cbound);
        cout << " " << iterCount << ':' << w << '/' << m_pseudotree->getHeight() << flush;
      }
    }
    ++iterCount, ++sinceLast, --remaining;

    // Adaptive ordering scheme
    if (improved && m_options->autoIter && remaining > 0) {
      remaining = max(remaining, sinceLast+1);
      sinceLast = 0;
    }

    // check termination conditions
    time(&time_order_cur);
    timediff = difftime(time_order_cur, time_order_start);
    if (m_options->order_timelimit != NONE && timediff > m_options->order_timelimit)
      break;
  }
  time(&time_order_cur);
  timediff = difftime(time_order_cur, time_order_start);
  cout << endl << "Ran " << iterCount << " iterations (" << int(timediff)
       << " seconds), lowest width/height found: "
       << w << '/' << m_pseudotree->getHeight() << '\n';

  // Save order to file?
  if (!m_options->in_orderingFile.empty() && !orderFromFile) {
    m_problem->saveOrdering(m_options->in_orderingFile, elim);
    cout << "Saved ordering to file " << m_options->in_orderingFile << endl;
  }
#if defined PARALLEL_DYNAMIC || defined PARALLEL_STATIC
#if defined PARALLEL_STATIC
  if (!m_options->par_solveLocal && !m_options->par_postOnly) // no need to write ordering
#endif
  {
    m_options->in_orderingFile = string("temp_elim.") + m_options->problemName
        + string(".") + m_options->runTag + string(".gz");
    m_problem->saveOrdering(m_options->in_orderingFile,elim);
    cout << "Saved ordering to file " << m_options->in_orderingFile << endl;
  }
#endif

  // OR search?
  if (m_options->orSearch) {
    cout << "Rebuilding pseudo tree as chain." << endl;
    m_pseudotree->buildChain(g, elim, m_options->cbound);
  }

  // Pseudo tree has dummy node after build(), add to problem
  m_problem->addDummy(); // add dummy variable to problem, to be in sync with pseudo tree
  m_pseudotree->addFunctionInfo(m_problem->getFunctions());
  m_pseudotree->addDomainInfo(m_problem->getDomains());

#if defined PARALLEL_STATIC
  m_pseudotree->computeSubprobStats();
#endif
#if defined PARALLEL_DYNAMIC //|| defined PARALLEL_STATIC
  int cutoff = m_pseudotree->computeComplexities(m_options->threads);
  cout << "Suggested cutoff:\t" << cutoff << " (ignored)" << endl;
//  if (opt.autoCutoff) {
//    cout << "Auto cutoff:\t\t" << cutoff << endl;
//    opt.cutoff_depth = cutoff;
//  }
#endif

  // Output pseudo tree to file for plotting?
  if (!m_options->out_pstFile.empty()) {
    m_pseudotree->outputToFile(m_options->out_pstFile);
  }

  if (m_options->maxWidthAbort != NONE &&
      m_options->maxWidthAbort < m_pseudotree->getWidth()) {
    oss msg;
    msg << "Problem instance with width w="<< m_pseudotree->getWidth()
        << " is too complex, aborting (limit is w="
        << m_options->maxWidthAbort << ")";
    err_txt(msg.str());
    return false;
  }
  return true;
}