Exemplo n.º 1
0
void OrientedGraph::levelPartition(Partition& pi) const

/*
  Assuming the graph has no oriented cycles, this function writes in pi the 
  partition of the vertices according to their level, where sinks have level
  0, then sinks in the remaining poset have level one, etc.

  NOTE : the implementation is simple-minded : we traverse the graph as many
  times as there are levels.
*/

{
  static BitMap b(0);
  static BitMap b1(0);

  b.setSize(size());
  b.reset();
  b1.setSize(size());
  b1.reset();
  pi.setSize(size());
  Ulong count = 0;
  Ulong current_level = 0;

  while (count < size()) {
    for (SetElt x = 0; x < size(); ++x) {
      if (b.getBit(x))
	continue;
      const EdgeList e = d_edge[x];
      for (Ulong j = 0; j < e.size(); ++j) {
	if (!b.getBit(e[j])) /* next x */
	  goto nextx;
      }
      /* i we get here, x is the next element in the permutation */
      pi[x] = current_level;
      b1.setBit(x);
      ++count;
    nextx:
      continue;
    }
    b.assign(b1);
    current_level++;
  }

  pi.setClassCount(current_level);
  return;
}
Exemplo n.º 2
0
void OrientedGraph::permute(const Permutation& a)

/*
  This function permutes the graph according to the permutation a, according
  to the usual rule : the edges of a(x) should be the image under a of the
  edge set of x.

  As usual, permuting values is easy : it is enough to apply a to the
  elements in the various edgelists. Permuting ranges is trickier, because
  it involves a^-1.

  It is assumed of course that a holds a permutation of size size().
*/

{
  static BitMap b(0);
  static EdgeList e_buf(0);

  /* permute values */

  for (SetElt x = 0; x < size(); ++x) {
    EdgeList& e = d_edge[x];
    for (Ulong j = 0; j < e.size(); ++j) {
      e[j] = a[e[j]];
    }
  }

  /* permute ranges */

  b.setSize(size());
  b.reset();

  for (SetElt x = 0; x < size(); ++x) {
    if (b.getBit(x))
      continue;
    if (a[x] == x) { /* fixed point */
      b.setBit(x);
      continue;
    }
    for (SetElt y = a[x]; y != x; y = a[y]) {
      /* back up values for y */
      e_buf.shallowCopy(d_edge[y]);
      /* put values for x in y */
      d_edge[y].shallowCopy(d_edge[x]);
      /* store backup values in x */
      d_edge[x].shallowCopy(e_buf);
      /* set bit */
      b.setBit(y);
    }
    b.setBit(x);
  }
}
Exemplo n.º 3
0
void OrientedGraph::cells(Partition& pi, OrientedGraph* P) const

/*
  Define a preorder relation on the vertices by setting x <= y iff there is an
  oriented path from x to y. This function puts in pi the partition function
  corresponding to the equivalence classes of this preorder. We use the 
  Tarjan algorithm, explained in one of the Knuth books, but which I learned 
  from Bill Casselman.

  The vertices for which the partition function is already defined will
  be said to be dealt with. These are marked off in an auxiliary bitmap.
  The algorithm goes as follows. Start with the first vertex that has not
  been dealt with, say x0. We will have to deal (potentially) with the set
  of all vertices visible from x0 (i.e >= x0). There will be a stack of
  vertices, corresponding to a path originating from x0, such that at each
  point in time, each vertex y >= x0 which is not dealt with will be
  equivalent to an element of the stack; the least such (in the stack
  ordering) will be called y_min, so that for instance x0_min = 0. We
  record these values in an additional table, initialized to some value
  undefined.

  Now let x be at the top of the stack. Look at the edges originating from
  x. Ignore the ones that go to vertices which are dealt with. If there
  are no edges left, x is minimal and is a class by itself; we can take
  it off, mark it as dealt with, and continue. Otherwise, run through the
  edges one by one. Let the edge be x->y. If y_min is defined, this means
  that y has already been examined, and is not dealt with. But each such
  element is equivalent to an element in the active stack, so y_min should
  be one of the elements in the active stack, hence x is visible from y_min:
  in other words, x and y are equivalent, and we set x_min = y_min if
  y_min < x_min. Otherwise, y is seen for the first time; then we just put
  it on the stack. When we are done with the edges of x, we have now the
  value of x_min which is the inf over the edges originating from x of
  the y_min. If this value is equal to the stack-position of x, we see that x 
  is minimal in its class, and we get a new class by taking all the successors
  of x not already dealt with. We then move to the parent of x and continue
  the process there.
*/

{
  static Permutation a(0);
  static BitMap b(0);
  static List<Vertex> v(1);
  static List<const EdgeList*> elist(1);
  static List<Ulong> ecount(1);
  static List<Ulong> min(0);

  pi.setSize(size());
  pi.setClassCount(0);

  b.setSize(size());
  b.reset();
  min.setSize(size());
  min.setZero();

  for (Vertex x = 0; x < size(); ++x)
    min[x] = size();

  for (Vertex x = 0; x < size(); ++x) {

    if (b.getBit(x)) /* x is dealt with */
      continue;

    v[0] = x;
    v.setSize(1);
    elist[0] = &edge(x);
    elist.setSize(1);
    ecount[0] = 0;
    ecount.setSize(1);
    min[x] = 0;
    Ulong t = 1;

    while(t) {
      Vertex y = v[t-1];
      Vertex z;
      const EdgeList& e = *elist[t-1];
      for (; ecount[t-1] < e.size(); ++ecount[t-1]) {
	z = e[ecount[t-1]];
	if (b.getBit(z))
	  continue;
	if (min[z] == size()) /* z is new */
	  goto add_path;
	if (min[y] > min[z])
	  min[y] = min[z];
      }
    /* at this point we have exhausted the edges of y */
      if (min[y] == t-1) { /* take off class */
	getClass(*this,y,b,pi,P);
      }
      else if (min[y] < min[v[t-2]]) /* if t=1, previous case holds */
	min[v[t-2]] = min[y];
      t--;
      continue;
    add_path:
      v.setSize(t+1);
      elist.setSize(t+1);
      ecount.setSize(t+1);
      v[t] = z;
      elist[t] = &edge(z);
      ecount[t] = 0;
      min[z] = t;
      t++;
    }

  }

  return;
}