Gecode中的替代分支策略

时间:2018-02-14 11:19:32

标签: c++ constraint-programming branching-strategy gecode

我在这里发帖询问是否有办法改变不同的分支策略。让我解释一下,我有一个有效的分支策略,我们称之为策略 A 。最大的问题是策略 A 不能经常使用。因此,当我无法使用策略 A 时,我会使用另一种策略,我将其称为策略 B ,效率较低。

文档说:

  

分支机构订单。创建分支机构将其注册到其主空间。空间维护其分支机构的队列,因为首先注册的分支机构也首先用于   分枝。分支队列中的第一个分支机构称为当前分支机构。

所以,我认为如果我发布分支机构A然后发布分支机构 B ,则分支机构 A 将具有优先权,并且每次status < em> A 表示没有分支要做,将使用分支机构 B 。好像我错了,因为当分支机构的status返回false时,它永远不会再被调用。 这是一个&#34; 最小示例&#34;:

#include <gecode/minimodel.hh>
#include <iostream>

using namespace Gecode;
using namespace std;

class MyChoice : public Choice {
  public:
    int pos; // Position of the variable
    int val; // Value of to assign

    MyChoice(const Brancher& b, int pos0, int val0)
      : Choice(b,2), pos(pos0), val(val0) {}

    // Report size occupied
    virtual size_t size(void) const {
      return sizeof(*this);
    }

    // Archive into e
    virtual void archive(Archive& e) const {
      Choice::archive(e);
      e << pos << val;
    }
};

class BranchA : public Brancher {
  protected:
    ViewArray<Int::IntView> x;
  public:
    BranchA(Home home, ViewArray<Int::IntView>& x0)
      : Brancher(home), x(x0) {}

    static void post(Home home, ViewArray<Int::IntView>& x) {
      (void) new (home) BranchA(home,x);
    }

    virtual size_t dispose(Space& home) {
      (void) Brancher::dispose(home);
      return sizeof(*this);
    }
    BranchA(Space& home, bool share, BranchA& b)
      : Brancher(home,share,b) {
      x.update(home,share,b.x);
    }
    virtual Brancher* copy(Space& home, bool share) {
      return new (home) BranchA(home,share,*this);
    }
    // status
    virtual bool status(const Space& home) const {
      for (int i=0; i<x.size(); i++)
        if (!x[i].assigned())
          return !i%2 && x[i].in(1);
      return false;
    }
    // choice
    virtual Choice* choice(Space& home) {
      for (int i=0; true; i++)
        if (!x[i].assigned())
          return new MyChoice(*this,i,1);
      GECODE_NEVER;
      return NULL;
    }
    virtual Choice* choice(const Space&, Archive& e) {
      int pos, val;
      e >> pos >> val;
      return new MyChoice(*this, pos, val);
    }
    // commit
    virtual ExecStatus commit(Space& home, 
                              const Choice& c,
                              unsigned int a) {
      const MyChoice& pv = static_cast<const MyChoice&>(c);
      int pos=pv.pos, val=pv.val;
      if (a == 0)
        return me_failed(x[pos].eq(home,val)) ? ES_FAILED : ES_OK;
      else
        return me_failed(x[pos].nq(home,val)) ? ES_FAILED : ES_OK;
    }
};
void branchA(Home home, const IntVarArgs& x) {
  if (home.failed()) return;
  ViewArray<Int::IntView> y(home,x);
  BranchA::post(home,y);
}
// BranchB //////////////////////////////////////////////////////

class BranchB : public Brancher {
  protected:
    ViewArray<Int::IntView> x;
  public:
    BranchB(Home home, ViewArray<Int::IntView>& x0)
      : Brancher(home), x(x0) {}
    static void post(Home home, ViewArray<Int::IntView>& x) {
      (void) new (home) BranchB(home,x);
    }
    virtual size_t dispose(Space& home) {
      (void) Brancher::dispose(home);
      return sizeof(*this);
    }
    BranchB(Space& home, bool share, BranchB& b)
      : Brancher(home,share,b) {
      x.update(home,share,b.x);
    }
    virtual Brancher* copy(Space& home, bool share) {
      return new (home) BranchB(home,share,*this);
    }
    // status
    virtual bool status(const Space& home) const {
      for (int i=0; i<x.size(); i++)
        if (!x[i].assigned())
          return i%2 && x[i].in(2);
      return false;
    }
    // choice
    virtual Choice* choice(Space& home) {
      for (int i=0; true; i++)
        if (!x[i].assigned())
          return new MyChoice(*this,i,2);
      GECODE_NEVER;
      return NULL;
    }
    virtual Choice* choice(const Space&, Archive& e) {
      int pos, val;
      e >> pos >> val;
      return new MyChoice(*this, pos, val);
    }
    // commit
    virtual ExecStatus commit(Space& home, 
                              const Choice& c,
                              unsigned int a) {
      const MyChoice& pv = static_cast<const MyChoice&>(c);
      int pos=pv.pos, val=pv.val;
      if (a == 0)
        return me_failed(x[pos].eq(home,val)) ? ES_FAILED : ES_OK;
      else
        return me_failed(x[pos].nq(home,val)) ? ES_FAILED : ES_OK;
    }
};
void branchB(Home home, const IntVarArgs& x) {
  if (home.failed()) return;
  ViewArray<Int::IntView> y(home,x);
  BranchB::post(home,y);
}

// Minimal Space ///////////////////////////////////////


class TestSpace : public Space {
  protected:
    IntVarArray x;
  public:
    TestSpace(int size)
      : x(*this, size, 0, 10) {
      branchA(*this, x);
      branchB(*this, x);
    }

    TestSpace (bool share, TestSpace& s)
      : Space(share, s) {
      x.update(*this, share, s.x);
    }

    virtual Space* copy (bool share) {
      return new TestSpace(share, *this);
    }
    void print(std::ostream& os) {
      os << "x= " << x << endl;
    }
};

// Minimal Main //////////////////////:

int main (int, char**) {
  // create model and search engine
  TestSpace* m = new TestSpace(10);
  DFS<TestSpace> e(m);
  delete m;
  // search and print all solutions
  while (TestSpace* s = e.next()) {
    s->print(cout); delete s;
  }
  return 0;
}

在此示例中,如果要分配的下一个变量位于偶数索引上,则分支机构 A status会返回true变量可以取1false else)的值。如果要分配的下一个变量位于奇数索引上且变量可以取值{,则分支 B status返回true {1}}(2其他)。 使用该代码,我希望获得解决方案false[1, 2, 1, 2, ...](以及其他组合,例如[!1, !2, !1, !2, ...]),但由于分支机构在[!1, 2, 1, !2, ...]返回status时处理掉,只分配了两个第一个变量。

有没有一种好的方法可以让分支机构在false返回status之后不被处置(或者替换两个不同的分支策略),还是应该将两个分支机构合并为一个?

1 个答案:

答案 0 :(得分:0)

如果它可以帮助某人,这是我使用的解决方案。 正如Patrick Trentin所建议的那样,我通过制作第三个分支机构来统一控制,这是一个分支机构的载体。这是我使用的实现:

标题 branchAllInOne.h

#include <gecode/minimodel.hh>

using namespace Gecode;
using namespace std;

class BranchAllInOne : public Brancher {
 protected:
  // Queue of brancher (may be better with ActorLink)
  vector<Actor *> queue;

  // Every brancher are in the brancher
  BrancherGroup group;

  mutable int toChoose;

  class ChoiceAndID : public Choice {
  public:
    // Choice of the brancher used
    Choice* c;
    /// ID of brancher used
    unsigned int id;

    ChoiceAndID(const Brancher& b, Choice * c, unsigned int id);
    virtual ~ChoiceAndID();
    virtual size_t size(void) const ;
    virtual void archive(Archive& e) const ;
  };

 public:
  BranchAllInOne(Home home);
  virtual size_t dispose(Space& home);
  BranchAllInOne(Home home, bool share, BranchAllInOne& b);
  virtual ~BranchAllInOne();
  /**
   * Check status of brancher, set toChoose value to the ID of the first 
   * brancher with alternative left
   **/
  virtual bool status(const Space&) const ;

  /**
   * Let the brancher of ID toChoose make the choice
   */
  virtual Choice* choice(Space&);
  virtual Choice* choice(const Space&, Archive& e);

  /**
   * Let the brancher of ID toChoose commit his choice
   */
  virtual ExecStatus commit(Space& home, const Choice& _c, unsigned int a);

  /// Copy brancher
  virtual Actor* copy(Space& home, bool share);

  /// Post brancher
  static BranchAllInOne * post(Home home);

  virtual void print(const Space& home,
             const Choice& c,
             unsigned int a,
             ostream& o) const ;
  void pushBrancher(Space& home, Brancher *b);
};

BranchAllInOne * branchAllInOne(Home home);

实施 branchAllInOne.cpp

#include "branchAllInOne.h"

static Brancher * ActorToBrancher(Actor *a);
// Choice implementation
BranchAllInOne::ChoiceAndID::ChoiceAndID(const Brancher& b, Choice * c0, unsigned int id0)
  : Choice(b, c0->alternatives()),
    c(c0),
    id(id0){}

BranchAllInOne::ChoiceAndID::~ChoiceAndID() {
  delete c;
}

size_t BranchAllInOne::ChoiceAndID::size(void) const {
  return sizeof(*this) + c->size();
}

void BranchAllInOne::ChoiceAndID::archive(Archive& e) const {
  Choice::archive(e);
  c->archive(e);
}

BranchAllInOne::BranchAllInOne(Home home)
  : Brancher(home),
    toChoose(-1) {
  home.notice(*this,AP_DISPOSE);
}

// brancher
BranchAllInOne * BranchAllInOne::post(Home home) {
  return new (home) BranchAllInOne(home);
}


size_t BranchAllInOne::dispose(Space& home) {
  home.ignore(*this, AP_DISPOSE);
  size_t size = queue.size() * sizeof(Actor*);
  for (unsigned int i = queue.size() ; i--;) {
    size += ActorToBrancher(queue[i])->dispose(home);
  }
  queue.~vector();

  // Making sure to kill each brancher inserted in the queue (may be useless)
  group.kill(home);

  (void) Brancher::dispose(home);
  return sizeof(*this) + size;
}

BranchAllInOne::BranchAllInOne(Home home, bool share, BranchAllInOne& b)
  : Brancher(home, share, b),
    queue(b.queue.size()),
    toChoose(b.toChoose){
  for (unsigned int i = 0 ; i < queue.size() ; i++)
    queue[i] = b.queue[i]->copy(home, share);  
}

BranchAllInOne::~BranchAllInOne() {
  for (unsigned int i = 0 ; i < queue.size() ; i++) {
    delete queue[i];
  }
  queue.~vector();
}

Actor* BranchAllInOne::copy(Space& home, bool share){
  return new (home) BranchAllInOne(home, share, *this);
}

// status
bool BranchAllInOne::status(const Space& s) const {
  for (unsigned int i = 0 ; i < queue.size() ; i++) {
    if (ActorToBrancher(queue[i])->status(s)) {
      toChoose = i;
      return true;
    }
  }  
  std::cout << std::endl;
  return false;
}

// choice
Choice* BranchAllInOne::choice(Space& s) {
  ChoiceAndID* res = new ChoiceAndID(*this,
                                     const_cast<Choice *>(ActorToBrancher(queue[toChoose])->choice(s)),
                                     toChoose);
  toChoose = -1;
  return res;
}

Choice* BranchAllInOne::choice(const Space& s, Archive& e) {
  return new ChoiceAndID(*this,
                         const_cast<Choice *>(ActorToBrancher(queue[toChoose])->choice(s, e)),
                         toChoose);
}

// Perform commit for choice \a _c and alternative \a a
ExecStatus BranchAllInOne::commit(Space& home, const Choice& c, unsigned int a) {
  const BranchAllInOne::ChoiceAndID& ch =  static_cast<const BranchAllInOne::ChoiceAndID&>(c);
  return ActorToBrancher(queue[ch.id])->commit(home, const_cast<Choice&>(*ch.c), a);

}



void BranchAllInOne::print(const Space& home,
                           const Choice& c,
                           unsigned int a,
                           ostream& o) const {
  const BranchAllInOne::ChoiceAndID& ch =  static_cast<const BranchAllInOne::ChoiceAndID&>(c);
  o << ch.id << ": ";
  ActorToBrancher(queue[ch.id])->print(home, *(ch.c), a, o);
}

void BranchAllInOne::pushBrancher(Space &home, Brancher *b) {
  queue.push_back(b);
  group.move(home, *b); 
}

static Brancher * ActorToBrancher(Actor *a) {
  return dynamic_cast<Brancher *>(a);
}

// end of BranchAllInOne implementation

BranchAllInOne* branchAllInOne(Home home) {
  if (home.failed()) return NULL;
  return BranchAllInOne::post(home);
}

我做了一些修改,以获取指向我想放入向量的分支器的指针(包括每个分支器的post函数): brancherA例子:

BranchA * BranchA::post(Home home, ViewArray<Int::IntView>& x) {
    return new (home) BranchA(home,x);
}


BranchA * branchA(Home home, const IntVarArgs& x) {
  if (home.failed()) return NULL;
  ViewArray<Int::IntView> y(home,x);
  return BranchA::post(home,y);
}

这个空间也被修改了:

  TestSpace::TestSpace(int size)
    : x(*this, size, 0, 10) {
    BranchAllInOne * b = branchAllInOne(*this);
    b->pushBrancher(*this, branchA(*this, x));
    b->pushBrancher(*this, branchB(*this, x));
  }

我使用和不使用Gist测试它,并且只有每个分支器放入向量中的指针的内存泄漏(这里只有两个)。一个小问题仍然是放在向量中的分支机构也在第三个分支机构停止后安排(但它们的状态返回false)。