"Christian Schulte" <cschu...@kth.se> writes:

> Sounds like a pretty good idea. I'll leave it to Guido as the master of set
> variables (he is away right now).
> [...]
>> From: Luca Di Gaspero <l.digasp...@uniud.it>
>> [...]
>> would it be possible to have channeling constraints between SetVarArrays in
>> the new gecode version. Even though they are just implemented with
>> decomposition they would be extremely useful in modeling (and in teaching). 
>> The constraints I am thinking about are of the form:
>>
>> i \in SetA_j \iff j \in SetB_i

Here you go:

Index: gecode/set.hh
===================================================================
--- gecode/set.hh	(revision 12448)
+++ gecode/set.hh	(working copy)
@@ -894,6 +894,10 @@
   GECODE_SET_EXPORT void
   channel(Home home, const BoolVarArgs& x, SetVar y);
 
+  /// Post propagator for \f$j\in x_i \Leftrightarrow i\in y_j\f$
+  GECODE_SET_EXPORT void
+  channel(Home home, const SetVarArgs& x, const SetVarArgs& y);
+
   /// Post propagator for \f$ |s|=x \f$
   GECODE_SET_EXPORT void
   cardinality(Home home, SetVar s, IntVar x);
Index: gecode/set/int.cpp
===================================================================
--- gecode/set/int.cpp	(revision 12448)
+++ gecode/set/int.cpp	(working copy)
@@ -179,6 +179,19 @@
                          ::post(home,xv,y)));
   }
 
+  void
+  channel(Home home, const SetVarArgs& x, const SetVarArgs& y)
+  {
+    if (home.failed()) return;
+    ViewArray<Set::CachedView<Set::SetView> > xa(home, x.size());
+    for (int i=x.size(); i--;)
+      new (&xa[i]) Int::CachedView<Set::SetView>(x[i]);
+    ViewArray<Set::CachedView<Set::SetView> > ya(home, y.size());
+    for (int i=y.size(); i--;)
+      new (&ya[i]) Set::CachedView<Set::SetView>(y[i]);
+    GECODE_ES_FAIL((Set::Int::ChannelSet<Set::SetView>::post(home,xa,ya)));
+  }
+
   void weights(Home home, IntSharedArray elements, IntSharedArray weights,
                SetVar x, IntVar y) {
     if (home.failed()) return;
Index: gecode/set/int/channel-int.hpp
===================================================================
--- gecode/set/int/channel-int.hpp	(revision 12448)
+++ gecode/set/int/channel-int.hpp	(working copy)
@@ -153,6 +153,136 @@
     return (assigned==xs.size()) ? home.ES_SUBSUMED(*this) : ES_NOFIX;
   }
 
+  template <typename View>
+  forceinline
+  ChannelSet<View>::ChannelSet(Home home,
+                               ViewArray<CachedView<View> >& xs0,
+                               ViewArray<CachedView<View> >& ys0)
+    : Propagator(home), xs(xs0), ys(ys0)
+  {
+    for (int i=xs.size(); i--;)
+      xs[i].initCache(home,IntSet::empty,IntSet(0,ys.size()-1));
+    for (int i=ys.size(); i--;)
+      ys[i].initCache(home,IntSet::empty,IntSet(0,xs.size()-1));
+    xs.subscribe(home,*this, PC_SET_ANY);
+    ys.subscribe(home,*this, PC_SET_ANY);
+  }
+
+  template <typename View>
+  forceinline
+  ChannelSet<View>::ChannelSet(Space& home, bool share, ChannelSet& p)
+    : Propagator(home, share, p)
+  {
+    xs.update(home, share, p.xs);
+    ys.update(home, share, p.ys);
+  }
+
+  template <typename View>
+  forceinline ExecStatus
+  ChannelSet<View>::post(Home home,
+                         ViewArray<CachedView<View> >& xs,
+                         ViewArray<CachedView<View> >& ys)
+  {
+    int xssize = xs.size();
+    for (int i=ys.size(); i--;)
+      {
+        GECODE_ME_CHECK(ys[i].exclude(home, xssize, Limits::max));
+        GECODE_ME_CHECK(ys[i].exclude(home, Limits::min, -1));
+      }
+    int yssize = ys.size();
+    for (int i=xs.size(); i--;)
+      {
+        GECODE_ME_CHECK(xs[i].exclude(home, yssize, Limits::max));
+        GECODE_ME_CHECK(xs[i].exclude(home, Limits::min, -1));
+      }
+    (void) new (home) ChannelSet(home,xs,ys);
+    return ES_OK;
+  }
+
+template <typename View>
+  PropCost
+  ChannelSet<View>::cost(const Space&, const ModEventDelta&) const
+  {
+    return PropCost::quadratic(PropCost::HI, xs.size()+ys.size());
+  }
+
+  template <typename View>
+  forceinline size_t
+  ChannelSet<View>::dispose(Space& home)
+  {
+    xs.cancel(home, *this, PC_SET_ANY);
+    ys.cancel(home, *this, PC_SET_ANY);
+    (void) Propagator::dispose(home);
+    return sizeof(*this);
+  }
+
+  template <typename View>
+  Actor*
+  ChannelSet<View>::copy(Space& home, bool share)
+  {
+    return new (home) ChannelSet(home,share,*this);
+  }
+
+  template <typename View>
+  ExecStatus
+  ChannelSet<View>::propagate(Space& home, const ModEventDelta&)
+  {
+    int assigned = 0;
+    bool again = true;
+    while (again)
+      {
+        assigned = 0;
+        again = false;
+        for (int i=xs.size(); i--;)
+          {
+            if (xs[i].assigned())
+              ++assigned;
+            if (xs[i].glbModified())
+              {
+                GlbDiffRanges<View> xilb(xs[i]);
+                Iter::Ranges::ToValues<GlbDiffRanges<View> > dv(xilb);
+                for (;dv();++dv)
+                  GECODE_ME_CHECK(ys[dv.val()].include(home,i));
+                xs[i].cacheGlb(home);
+                again = true;
+              }
+            if (xs[i].lubModified())
+              {
+                LubDiffRanges<View> xiub(xs[i]);
+                Iter::Ranges::ToValues<LubDiffRanges<View> > dv(xiub);
+                for (;dv();++dv)
+                  GECODE_ME_CHECK(ys[dv.val()].exclude(home,i));
+                xs[i].cacheLub(home);
+                again = true;
+              }
+          }
+        for (int i=ys.size(); i--;)
+          {
+            if (ys[i].assigned())
+              ++assigned;
+            if (ys[i].glbModified())
+              {
+                GlbDiffRanges<View> yilb(ys[i]);
+                Iter::Ranges::ToValues<GlbDiffRanges<View> > dv(yilb);
+                for (;dv();++dv)
+                  GECODE_ME_CHECK(xs[dv.val()].include(home,i));
+                ys[i].cacheGlb(home);
+                again = true;
+              }
+            if (ys[i].lubModified())
+              {
+                LubDiffRanges<View> yiub(ys[i]);
+                Iter::Ranges::ToValues<LubDiffRanges<View> > dv(yiub);
+                for (;dv();++dv)
+                  GECODE_ME_CHECK(xs[dv.val()].exclude(home,i));
+                ys[i].cacheLub(home);
+                again = true;
+              }
+          }
+      }
+
+    return (assigned == xs.size()+ys.size()) ? home.ES_SUBSUMED(*this) : ES_FIX;
+  }
 }}}
 
 // STATISTICS: set-prop
Index: gecode/set/int.hh
===================================================================
--- gecode/set/int.hh	(revision 12448)
+++ gecode/set/int.hh	(working copy)
@@ -406,6 +406,48 @@
   };
 
   /**
+   * \brief %Propagator for successors/predecessors channelling
+   *
+   * Implements channelling constraints between 2 sequences of SetVars.
+   * For SetVars \f$x_0,\dots,x_n\f$ and SetVars \f$y_0,\dots,y_m\f$ it
+   * propagates the constraint \f$j\in x_i \Leftrightarrow i\in y_i\f$.
+   * \f$x_i\f$ is the set of successors of \f$i\f$, and \f$y_j\f$ is the
+   * set of predecessors of \f$j\f$.
+   *
+   * Requires \code #include <gecode/set/int.hh> \endcode
+   * \ingroup FuncSetProp
+   */
+
+  template<typename View>
+  class ChannelSet: public Propagator {
+  protected:
+    /// SetViews, \f$x_i\f$ reflects the successors of \f$i\f$
+    ViewArray<CachedView<View> > xs;
+    /// SetViews, \f$y_j\f$ reflects the predecessors of \f$j\f$
+    ViewArray<CachedView<View> > ys;
+
+    /// Constructor for cloning \a p
+    ChannelSet(Space& home, bool share, ChannelSet& p);
+    /// Constructor for posting
+    ChannelSet(Home home,
+               ViewArray<CachedView<View> >&,
+               ViewArray<CachedView<View> >&);
+  public:
+    /// Copy propagator during cloning
+    virtual Actor* copy(Space& home, bool);
+    /// Cost function (defined as PC_QUADRATIC_HI)
+    virtual PropCost cost(const Space& home, const ModEventDelta& med) const;
+    /// Delete propagator and return its size
+    virtual size_t dispose(Space& home);
+    /// Perform propagation
+    virtual ExecStatus propagate(Space& home, const ModEventDelta& med);
+    /// Post propagator for \f$j\in x_i \Leftrightarrow i\in y_j\f$
+    static ExecStatus post(Home home,
+                           ViewArray<CachedView<View> >& x,
+                           ViewArray<CachedView<View> >& y);
+  };
+
+  /**
    * \brief %Propagator for weight of a set
    *
    * Requires \code #include <gecode/set/int.hh> \endcode
Index: gecode/set/branch/post-view.cpp
===================================================================
--- gecode/set/branch/post-view.cpp	(revision 12448)
+++ gecode/set/branch/post-view.cpp	(working copy)
@@ -2,7 +2,7 @@
  *  CAUTION:
  *    This file has been automatically generated. Do not edit,
  *    edit the specification file
- *      gecode/set/branch/post-view.bs
+ *      ../gecode/set/branch/post-view.bs
  *    instead.
  *
  *  This file contains generated code fragments which are
Cheers,

--Denys

PS: Guido, you might want to shuffle the code to different files. I just
wasn't sure where to put it.
_______________________________________________
Gecode users mailing list
users@gecode.org
https://www.gecode.org/mailman/listinfo/gecode-users

Reply via email to