Main Page | Namespace List | Class Hierarchy | Class List | File List | Namespace Members | Class Members | File Members

/home/r0/dav/atlas.dir/atlas3/sources/gkmod/blocks.cpp

Go to the documentation of this file.
00001 /*
00002   This is blocks.cpp
00003 
00004   Copyright (C) 2004,2005 Fokko du Cloux
00005   Modified by Marc van Leeuwen, 2007
00006   Part of the Atlas of Reductive Lie Groups
00007 
00008   See file main.cpp for full copyright notice
00009 */
00010 /*!
00011 \file
00012 \brief Implementation of the class Block.
00013 
00014   This module aims to construct the fundamental combinatorial structure
00015   underlying K-L computations: a block of representations, together with
00016   cross-actions, Cayley transforms, length function, and descent sets.
00017 
00018   Basically, a block should be constructed from a pair of gradings: one
00019   for the fundamental torus of G, and one for the fundamental torus of
00020   G^vee. This suffices to determine the cocycles that allow us to describe
00021   cosets for the corresponding Tits groups, and therefore the one-sided
00022   parameter sets for which we then only have to take the restricted
00023   product. Of course in practice one should be careful to first determine
00024   the support of the block in the set of root datum involutions, and
00025   do the construction only for that part, if possible.
00026 */
00027 
00028 #include "blocks.h"
00029 
00030 #ifdef VERBOSE
00031 #include <iostream>
00032 #endif
00033 
00034 #include <cassert>
00035 #include <memory>
00036 #include <set>
00037 
00038 #include "basic_io.h"
00039 #include "bruhat.h"
00040 #include "complexredgp.h"
00041 #include "cartanset.h"
00042 #include "descents.h"
00043 #include "kgb.h"
00044 #include "realredgp.h"
00045 #include "tags.h"
00046 #include "weyl.h"
00047 #include "hashtable.h"
00048 
00049 /*
00050   Our task is fairly simple: given the one sided parameter sets for the real
00051   form and for the dual real form, as provided by the kgb module, which sets
00052   are fibred over the sets of twisted involutions for the Weyl group and dual
00053   Weyl group respectively, we must form the fibred product over corresponding
00054   pairs of twisted involutions, and equip the resulting structure with
00055   relations inherited from the kgb structures.
00056 
00057   One point to be resolved here is the relation between a twisted involution
00058   and the corresponding dual twisted involution; it is implemented in the
00059   function |dualInvolution| below. On the level of involution matrices acting
00060   on the character and cocharacter lattices, the relation is minus transpose;
00061   this has to be translated into a relation between Weyl group elements, which
00062   is slightly complicated by the fact that while the Weyl group and the dual
00063   Weyl group are the same abstract group, differing only (if at all) by the
00064   involution of the generating set called |twist|, the groups may differ in
00065   their internal representation in their numbering of the simple generators.
00066 
00067   Another important point here is matching the local structure of the two KGB
00068   sets to define the local relations in the block structure. The combinations
00069   possible of local structures in the KGB sets, as given by |gradings::Status|
00070   values, are limited by the relationship between involution and dual
00071   involution: a generator that is complex for one is so as well for the other,
00072   while the remaining generators are imaginary for one are real for the other.
00073 
00074   It turns out that possibilites are even more restricted then implied by the
00075   above relation, and every block element $z=(x,y)$ occurs, for each generator
00076   |s|, in one of the following five configurations. At the left we depict the
00077   coordinate |x| in the kgb set, to the right of it the coordinte |y| in the
00078   dual kgb set; at the former case going down increases the length, in the
00079   latter it increases the length. At the right we describe the local block
00080   structure; the terminology used there refers mostly to what happend in kgb,
00081   and in particular going down is considered to be an ascent in the block.
00082 
00083   If |s| is complex for the involution and its dual, one has cross actions
00084 
00085              ( x      ,     y   )    ComplexAscent       z
00086                |            |                            |
00087                |            |                            |
00088              ( x'     ,     y'  )    ComplexDescent      z'
00089 
00090   If |s| is imaginary noncompact for the involution, it will be real, and in
00091   the image of the Cayley transform, for the dual involution. Either the
00092   Cayley image of the |x| coordinate is shared with that of another KGB
00093   element and the |y| coordinate has a single-valued inverse Cayley transform
00094   (type I situation), or the Cayley image of the |x| coordinate is unshared,
00095   and the |y| coordinate has a double-valued inverse Cayley transform.
00096 
00097       ( x      x'    , s^y   )    Imaginary Type I (twice)    z     z'
00098          \    /         |                                      \   /
00099           \  /          |                                       \ /
00100       (  s^x=s^x'    ,  y    )        Real Type I               s^z
00101 
00102 
00103 
00104       (    x    ,   s^y=s^y' )    Imaginary Type II              z
00105            |          / \                                       / \
00106            |         /   \                                     /   \
00107       (   s^x   ,   y     y' )     Real Type II (twice)     s^z_1  s^z_2
00108 
00109   If |s| is imaginary compact for the involution, it will be real and not in
00110   the image of the Cayley transfor for the dual involution. No Cayley transorm
00111   will be defined for the |x| coordinate, and no inverse Cayley transform for
00112   the |y| coordinate, and both are fixed by the cross action; the situation is
00113   called ImaginaryCompact.
00114 
00115       (    x    ,     y     )     ImaginaryNoncompact            z
00116 
00117   Finally that situation with x and y interchanged is called RealNonparity
00118 
00119       (    x    ,     y     )         RealNonparity              z
00120 
00121   Although the last two cases have no cross action links for |s| to other
00122   block elements, nor any Cayley or inverse Cayley links for |s|, we consider
00123   (more in particular |descents::DescentStatus::isDescent| considers) |s| to
00124   be in the descent set in the ImaginaryNoncompact case, and not in the
00125   descent set for the RealNonparity case (note that this is opposite to the
00126   status of imaginary and real generators in the other (parity) cases). These
00127   cases do not count as strict descent/ascent however, as is indicated in the
00128   predicates |isStrrictDescent| and |isStrictAscent| below.
00129 */
00130 
00131 namespace atlas {
00132 
00133 namespace blocks {
00134 namespace {
00135 
00136 
00137 using namespace blocks;
00138 
00139 weyl::WeylInterface
00140 correlation(const weyl::WeylGroup& W,const weyl::WeylGroup& dW);
00141 
00142 descents::DescentStatus descents(kgb::KGBElt x,
00143                                  kgb::KGBElt y,
00144                                  const kgb::KGB& kgb,
00145                                  const kgb::KGB& dual_kgb);
00146 
00147 void insertAscents(std::set<BlockElt>&, const set::SetEltList&, size_t,
00148                    const Block&);
00149 void makeHasse(std::vector<set::SetEltList>&, const Block&);
00150 
00151 
00152 } // namespace
00153 
00154 } // namespace blocks
00155 
00156 /*****************************************************************************
00157 
00158         Chapter I -- The Block class
00159 
00160 ******************************************************************************/
00161 
00162 namespace blocks {
00163 
00164 /*!
00165   \brief Constructor for the block class.
00166 
00167   Constructs a block from the datum of a real form rf for G and a real
00168   form df for G^vee (_not_ strong real forms: up to isomorphism, the
00169   result depends only on the underlying real forms!).
00170 */
00171 Block::Block(complexredgp::ComplexReductiveGroup& G,
00172              realform::RealForm rf, realform::RealForm df,
00173              bool select_Cartans)
00174   : d_realForm(rf)
00175   , d_dualForm(df)
00176   , d_rank(G.semisimpleRank())
00177   , d_weylGroup(G.weylGroup())
00178   , d_xrange(0), d_yrange(0) // set by |generate|
00179   , d_x(), d_y(), d_first_z_of_x() // filled by |generate|
00180   , d_cross(d_rank), d_cayley(d_rank) // each entry filled by |generate|
00181   , d_descent(), d_length(), d_Cartan(), d_involution() // filled by |generate|
00182   , d_involutionSupport() // filled below
00183   , d_state()
00184   , d_bruhat(NULL)
00185 {
00186   realredgp::RealReductiveGroup G_R(G,rf);
00187   complexredgp::ComplexReductiveGroup dG(G,tags::DualTag()); // the dual group
00188   realredgp::RealReductiveGroup dG_R(dG,df);
00189   dG_R.fillCartan();
00190 
00191 #ifdef VERBOSE
00192   std::cerr << "entering block construction... " << std::flush;
00193 #endif
00194 
00195   generate(G_R,dG_R,select_Cartans); // does most of the construction work
00196 
00197   // all that remains is computing the supports in $S$ of twisted involutions
00198   d_involutionSupport.reserve(size()); // its eventual size
00199   for (BlockElt z=0; z<size() and d_length[z]==d_length[0]; ++z) // minl length
00200   {
00201     if (z==0 or d_involution[z]!=d_involution[z-1])
00202     { // compute involution support directly from definition
00203       bitset::RankFlags support;
00204       weyl::WeylWord ww=weylGroup().word(d_involution[z]);
00205       for (size_t j=0; j<ww.size(); ++j)
00206         support.set(ww[j]);
00207       d_involutionSupport.push_back(support);
00208     }
00209     else // unchanged involution
00210       d_involutionSupport.push_back(d_involutionSupport.back()); // duplicate
00211   }
00212 
00213   // complete by propagating involution supports
00214   for (BlockElt z=d_involutionSupport.size(); z<size(); ++z)
00215   {
00216     size_t s = firstStrictDescent(z);
00217     assert (s<d_rank); // must find one, as we are no longer at minimal length
00218     descents::DescentStatus::Value v = descentValue(s,z);
00219     if (v == descents::DescentStatus::ComplexDescent) // cross link
00220     { // use value from shorter cross neighbour, setting |s| and |twist(s)|
00221       d_involutionSupport[z] = d_involutionSupport[cross(s,z)];
00222       d_involutionSupport[z].set(s);
00223       d_involutionSupport[z].set(weylGroup().twisted(s));
00224     }
00225     else // Real Type I or II
00226     { // use (some) inverse Cayley transform and set |s|
00227       d_involutionSupport[z] = d_involutionSupport[inverseCayley(s,z).first];
00228       d_involutionSupport[z].set(s);
00229     }
00230   } // |for(z)|
00231 
00232 
00233 #ifdef VERBOSE
00234   std::cerr << "done" << std::endl;
00235 #endif
00236 }
00237 
00238 
00239 Block::~Block()
00240 
00241 {
00242   delete d_bruhat;
00243 }
00244 
00245 /******** copy, assignment and swap ******************************************/
00246 
00247 /******** accessors **********************************************************/
00248 
00249 /*!\brief Look up element by |x|, |y| coordinates
00250 
00251   Precondition: |x| and |y| should be compatible: such a block element exists
00252 
00253   This uses the |d_first_z_of_x| table to locate the range where the |x|
00254   coordinates are correct; then comparing the given |y| value with the first
00255   one present for |x| (there must be at least one) we can predict the value
00256   directly, since for each fixed |x| value the values of |y| are consecutive.
00257 */
00258 BlockElt Block::element(kgb::KGBElt x,kgb::KGBElt y) const
00259 {
00260   BlockElt first=d_first_z_of_x[x];
00261   BlockElt z = first +(y-d_y[first]);
00262   assert(z<size() and d_x[z]==x and d_y[z]==y); // element should be found
00263   return z;
00264 }
00265 
00266 /*!
00267   \brief Tells if s is a strict ascent generator for z.
00268 
00269   Explanation: this means that d_descent[z][s] is one of ComplexAscent,
00270   ImaginaryTypeI or ImaginaryTypeII.
00271 */
00272 bool Block::isStrictAscent(size_t s, BlockElt z) const
00273 {
00274   using namespace descents;
00275 
00276   DescentStatus::Value v = descentValue(s,z);
00277   return not DescentStatus::isDescent(v) and v!=DescentStatus::RealNonparity;
00278 }
00279 
00280 /*!
00281   \brief Tells if s is a strict descent generator for z.
00282 
00283   Explanation: this means that d_descent[z][s] is one of ComplexDescent,
00284   RealTypeI or RealTypeII.
00285 */
00286 bool Block::isStrictDescent(size_t s, BlockElt z) const
00287 {
00288   using descents::DescentStatus;
00289 
00290   DescentStatus::Value v = descentValue(s,z);
00291   return DescentStatus::isDescent(v) and v!=DescentStatus::ImaginaryCompact;
00292 }
00293 
00294 /*!
00295   \brief Returns the first descent for z (the number of a simple root) that is
00296 not imaginary compact, or rank() if there is no such descent.
00297 */
00298 size_t Block::firstStrictDescent(BlockElt z) const
00299 {
00300   for (size_t s = 0; s < rank(); ++s)
00301     if (isStrictDescent(s,z))
00302       return s;
00303 
00304   return rank(); // signal nothing was found
00305 }
00306 
00307 /*!
00308   \brief Returns the first descent for z (the number of a simple root) that is
00309 either complex or real type I; if there is no such descent returns |rank()|
00310 */
00311 size_t Block::firstStrictGoodDescent(BlockElt z) const
00312 {
00313   for (size_t s = 0; s < rank(); ++s)
00314     if (isStrictDescent(s,z) and
00315         descentValue(s,z)!=descents::DescentStatus::RealTypeII)
00316       return s;
00317 
00318   return rank(); // signal nothing was found
00319 }
00320 
00321 /*!
00322   \brief the functor \f$T_{\alpha,\beta}\f$
00323 
00324   Precondition: alpha and beta are adjacent roots, of which alpha is a (weak)
00325   descent for y, while beta is not a descent for y.
00326 
00327   In fact if this is not satisfied, we return a pair of UndefBlock elements
00328 */
00329 
00330 BlockEltPair Block::link(size_t alpha,size_t beta,BlockElt y) const
00331 {
00332   const descents::DescentStatus& desc=descent(y);
00333 
00334   std::vector<BlockElt> result(2,UndefBlock); // overwritten using iterator
00335   std::vector<BlockElt>::iterator it=result.begin();
00336 
00337   BlockEltPair p=inverseCayley(alpha,y);
00338   switch (desc[alpha])
00339   {
00340   case descents::DescentStatus::ComplexDescent:
00341     {
00342       BlockElt y1=cross(alpha,y);
00343       if (isWeakDescent(beta,y1))
00344         *it++=y1;
00345       break;
00346     }
00347   case descents::DescentStatus::RealTypeI:
00348     if (isWeakDescent(beta,p.second))
00349       *it++=p.second;
00350     // FALL THROUGH
00351   case descents::DescentStatus::RealTypeII:
00352     if (isWeakDescent(beta,p.first))
00353       *it++=p.first;
00354     break;
00355   default: {}
00356   } // switch(desc[alpha])
00357 
00358   p=cayley(beta,y);
00359   switch (desc[beta])
00360   {
00361   case descents::DescentStatus::ComplexAscent:
00362     {
00363       BlockElt y1=cross(beta,y);
00364       if (not isWeakDescent(alpha,y1))
00365         *it++=y1;
00366       break;
00367     }
00368   case descents::DescentStatus::ImaginaryTypeII:
00369     if (not isWeakDescent(alpha,p.second))
00370       *it++=p.second;
00371     // FALL THROUGH
00372   case descents::DescentStatus::ImaginaryTypeI:
00373     if (not isWeakDescent(alpha,p.first))
00374       *it++=p.first;
00375     break;
00376   default: {}
00377   } // switch(desc[beta])
00378 
00379   assert(&*it<=&result[2]);
00380 
00381   return std::make_pair(result[0],result[1]);
00382 }
00383 
00384 
00385 /******** manipulators *******************************************************/
00386 
00387 // to be called by the constructor
00388 void Block::generate(realredgp::RealReductiveGroup& G,
00389                      realredgp::RealReductiveGroup& dG,
00390                      bool select_Cartans)
00391 {
00392   kgb::KGB kgb(G,select_Cartans ? common_Cartans(G,dG) : bitmap::BitMap(0));
00393   kgb::KGB dual_kgb
00394     (dG,select_Cartans ? common_Cartans(dG,G) : bitmap::BitMap(0));
00395 
00396 #ifdef VERBOSE
00397   std::cerr << "K\\G/B and dual generated... " << std::flush;
00398 #endif
00399 
00400   const weyl::WeylGroup& dual_Weyl_group(dual_kgb.weylGroup());
00401   weyl::WeylInterface to_dual_Weyl=correlation(d_weylGroup,dual_Weyl_group);
00402 
00403   // set |d_xrange| and |d_yrange|
00404   d_xrange = kgb.size();
00405   d_yrange = dual_kgb.size();
00406 
00407   complexredgp::ComplexReductiveGroup& G_C = G.complexGroup();
00408   size_t size=G_C.blockSize(d_realForm,d_dualForm); // not stored in |Block| !
00409 
00410   d_x.reserve(size);
00411   d_y.reserve(size);
00412   d_first_z_of_x.reserve(d_xrange+1);
00413 
00414   d_involution.reserve(size);
00415   d_length.reserve(size);
00416   d_Cartan.reserve(size);
00417   d_descent.reserve(size);
00418 
00419   { // generate the six tables we just dimensioned
00420     kgb::KGBElt x = 0;
00421     BlockElt base_z = 0; // block element |z| where generation for |x| starts
00422 
00423     while (x<kgb.size()) // loop over twisted involutions $\tau$
00424     {
00425       const weyl::TwistedInvolution& w = kgb.involution(x);
00426 
00427       kgb::KGBEltPair xRange = kgb.tauPacket(w);
00428       kgb::KGBEltPair yRange =
00429         dual_kgb.tauPacket(dualInvolution(w,to_dual_Weyl));
00430 
00431       for (assert(x==xRange.first); x < xRange.second; ++x)
00432       {
00433         d_first_z_of_x.push_back(base_z); // set even for |x| without any |y|
00434         for (size_t y = yRange.first; y < yRange.second; ++y)
00435         {
00436           d_x.push_back(x);
00437           d_y.push_back(y);
00438           d_involution.push_back(w);
00439           d_length.push_back(kgb.length(x));
00440           d_Cartan.push_back(kgb.Cartan_class(x));
00441           d_descent.push_back(descents(x,y,kgb,dual_kgb));
00442         } // |for(y)|
00443         base_z += yRange.second - yRange.first; // skip to next |x|
00444       } // |for(x)|
00445     } // "for(tau)"
00446 
00447     assert(base_z == size); // check that number of pairs is as expected
00448     d_first_z_of_x.push_back(base_z);// make |d_first_z_of_x[d_xrange]==d_size|
00449 
00450     assert(d_first_z_of_x.size()==d_xrange+1);
00451     assert(d_x.size()==size); // similarly for |d_y|, ..., |d_descent|
00452   } // end of generation of |(x,y)| tables
00453 
00454   // Now |element| can be safely called; install cross and Cayley tables
00455 
00456   for (size_t s = 0; s < d_rank; ++s)
00457   { // the generation below is completely independent for each |s|
00458     d_cross[s].resize(size);
00459     d_cayley[s].resize(size,std::make_pair(UndefBlock,UndefBlock));
00460     for (BlockElt z = 0; z<size; ++z)
00461     {
00462      d_cross[s][z] = element(kgb.cross(s,x(z)),dual_kgb.cross(s,y(z)));
00463      switch (d_descent[z][s])
00464      {
00465      default: break; // leave |d_cayley[s][z]|
00466      case descents::DescentStatus::ImaginaryTypeII:
00467        {
00468          BlockElt z1=element(kgb.cayley(s,x(z)),
00469                              dual_kgb.inverseCayley(s,y(z)).second);
00470          d_cayley[s][z].second = z1; // double-valued direct Cayley
00471          d_cayley[s][z1].first = z; // single-valued inverse Cayley
00472        }
00473        // FALL THROUGH
00474      case descents::DescentStatus::ImaginaryTypeI:
00475        {
00476          BlockElt z0=element(kgb.cayley(s,x(z)),
00477                              dual_kgb.inverseCayley(s,y(z)).first);
00478          d_cayley[s][z].first = z0; // |.second| remains |UndefBlock| in TypeI
00479          BlockEltPair& ic = d_cayley[s][z0]; // location for inverse Cayley
00480          if (ic.first==UndefBlock) // it may be single or double valued
00481            ic.first = z;
00482          else
00483            ic.second = z;
00484        }
00485      } // switch
00486     } // |for (z)|
00487   } // |for(s)|
00488 
00489 
00490 } // generate
00491 
00492 /*!
00493   \brief Constructs the BruhatOrder.
00494 
00495   NOTE: may throw a MemoryOverflow error. Commit-or-rollback is guaranteed.
00496 */
00497 void Block::fillBruhat()
00498 {
00499   using namespace bruhat;
00500   using namespace set;
00501 
00502   if (d_state.test(BruhatConstructed)) // work was already done
00503     return;
00504 
00505   try {
00506     std::vector<SetEltList> hd; makeHasse(hd,*this);
00507     BruhatOrder* bp = new BruhatOrder(hd); // may throw here
00508 
00509     // commit
00510     delete d_bruhat; // this is overly careful: it must be NULL
00511     d_bruhat = bp;
00512     d_state.set(BruhatConstructed);
00513   }
00514   catch (std::bad_alloc) { // transform failed allocation into MemoryOverflow
00515     throw error::MemoryOverflow();
00516   }
00517 }
00518 
00519 
00520 /******** private accessor *************************************************/
00521 
00522 
00523 //!\brief Returns the twisted involution dual to tw.
00524 
00525 /*
00526   Explanation: we have $\tau = tw.\delta$, with $tw$ in the Weyl group $W$,
00527   and $\delta$ the fundamental involution of the character lattice. We seek
00528   the twisted involution $v$ in the dual Weyl group $W^\vee$ such that
00529   $-\tau^t = v.\delta^\vee$; here $\delta^\vee$ is the fundamental involution
00530   for $W^\vee$, which acts on the cocharacter lattice and can be expressed as
00531   $-w_0^t\delta^t$ where $w_0$ is the longest element of $W$. So we have:
00532 
00533         $(-\delta^t). tw^t = v.w_0^t.(-\delta^t)$
00534 
00535   which leads to $v = (w_0.\delta.tw.\delta)^t$. Conjugation by $\delta$ in
00536   the extended Weyl group defines the automorphism $\theta$ of $W$ coming from
00537   the Dynkin diagram involution that defines the inner class, so we van write
00538   $v=(w_0.\theta(tw))^t$. This equation of endomorphisms of the cocharacter
00539   lattice must be translated into one on the level of abstract Weyl groups.
00540 
00541   Passing from a Weyl group element $w$ acting on the character lattice to the
00542   induced operation $w^t$ on the cocharacter lattice is an anti-isomorphism
00543   $D:W\to W^\vee$ that maps each generator of $W$ to the corresponding
00544   generator of $W^\vee$, so we want to determine $v=D(w_0.\theta(tw))$.
00545   Computing some $D(w)$ amounts to interpreting $w^{-1}$ in $W^\vee$. This
00546   reinterpretation is the identity on the level of Weyl words (the same
00547   numbering of generators is used in the external representation), but since
00548   we are using the internal representation |WeylElt| here, and the respective
00549   Weyl groups may use different internal numberings of generators, a call to
00550   |WeylGroup::translation| is necessary to do the conversion; the |to_daul|
00551   map should define an automorphism of the Weyl group so that one has
00552 
00553        |dual_W.word(W.translation(weyl::WeylElt(ww,W),to_dual)) == ww|
00554 
00555   for each Weyl word |ww|. Note that this difference of internal numbering
00556   could have been avoided if the |WeylGroup| constructor had used the Coxeter
00557   matrix to determine the internal numbering, since this is guaranteed to be
00558   the same for $W$ and $W^\vee$; however since the Cartan matrix and normal
00559   renumbering of the corresponding Dynkin diagram is used instead, $W$ and
00560   $W^\vee$ will differ internally in the cases $B_2$, $G_2$ and $F_4$.
00561 */
00562 weyl::TwistedInvolution Block::dualInvolution
00563   (const weyl::TwistedInvolution& tw,weyl::WeylInterface to_dual) const
00564 {
00565   const weyl::WeylGroup& W = weylGroup();
00566   return weyl::TwistedInvolution
00567     (W.translation(W.inverse(W.prod(W.longest(),W.twisted(tw.w()))),
00568                    to_dual));
00569 }
00570 
00571 } // namespace blocks
00572 
00573 
00574 /*****************************************************************************
00575 
00576         Chapter III -- Functions local to blocks.cpp
00577 
00578 ******************************************************************************/
00579 
00580 namespace blocks {
00581   namespace {
00582 
00583 /*!
00584   \brief Returns mapping of internal numberings from |W| to |dW|
00585 
00586   Explanation: this is a fairly annoying twist. Because of the normalizations
00587   that we do for Weyl groups based on the Cartan matrix rather than the
00588   Coxeter matrix, the dual Weyl group may uses a different internal numbering
00589   than the Weyl group in the (irreducible) cases $B_2$, $G_2$ ad $F_4$. This
00590   means we cannot reinterpret |WeylElt| values for $W$ as values for $dW$
00591   without a conversion. The conversion will be performed by
00592   |WeylGroup::translate| based on the value computed here, which is a mapping
00593   of external numberings, to be applied by |W| on an element just before
00594   reinterpreting it in the |dW|. We should have for each |s|, in terms of the
00595   internal translation arrays:
00596 
00597         |  dW.d_out[W.d_in[d_toDualWeyl[s]]] = s | or equivalently
00598         |  d_toDualWeyl[s] = W.d_out[dW.d_in[s]] |
00599 
00600   so that the reinterpretation will preserve the outer representation. We do
00601   not having direct access to those arrays, but we can pass into internal
00602   representation and back out for another group without acessing them
00603   explicitly. Note this could not possibly be made to work (in all cases) if
00604   |WeylGroup::translate| were to use internal numbering, as it originally did.
00605 */
00606 weyl::WeylInterface
00607 correlation(const weyl::WeylGroup& W,const weyl::WeylGroup& dW)
00608 {
00609   size_t rank=W.rank();
00610   weyl::WeylInterface result(rank);
00611   for (size_t s = 0; s < rank; ++s)
00612   {
00613     weyl::WeylElt w=dW.generator(s); // converts |s| to inner numbering |dW|
00614     weyl::WeylWord ww=W.word(w); // interpret |w| in |dW|; gives singleton
00615     assert(ww.size()==1);
00616 
00617     /* We want to map |s| to |ww[0]| so that interpreting that internally in
00618        |W| gives the element that in |dW| will represent |s|
00619     */
00620     result[s] = ww[0];
00621   }
00622   return result;
00623 }
00624 
00625 descents::DescentStatus descents(kgb::KGBElt x,
00626                                  kgb::KGBElt y,
00627                                  const kgb::KGB& kgb,
00628                                  const kgb::KGB& dual_kgb)
00629 {
00630   using gradings::Status;
00631   using descents::DescentStatus;
00632 
00633   DescentStatus result;
00634   for (size_t s = 0; s < kgb.rank(); ++s)
00635     if (kgb.status(s,x) == Status::Complex) // s is complex
00636       if (kgb.isDescent(s,x))
00637         result.set(s,DescentStatus::ComplexDescent);
00638       else
00639         result.set(s,DescentStatus::ComplexAscent);
00640     else if (kgb.status(s,x) == Status::ImaginaryNoncompact)
00641       if (kgb.cross(s,x)!=x) // type I
00642         result.set(s,DescentStatus::ImaginaryTypeI);
00643       else // type II
00644         result.set(s,DescentStatus::ImaginaryTypeII);
00645     else if (dual_kgb.status(s,y) == Status::ImaginaryNoncompact)
00646       if (dual_kgb.cross(s,y)!=y) // type II
00647         result.set(s,DescentStatus::RealTypeII);
00648       else // type I
00649         result.set(s,DescentStatus::RealTypeI);
00650     // now s is imaginary compact or real nonparity
00651     else if (kgb.status(s,x) == Status::Real)
00652       result.set(s,DescentStatus::RealNonparity);
00653     else
00654       result.set(s,DescentStatus::ImaginaryCompact);
00655 
00656   return result;
00657 }
00658 
00659 /*!
00660   \brief Inserts into hs the ascents from hr through s.
00661 
00662   Explanation: technical function for the Hasse construction, that makes the
00663   part of the coatom list for a given element arising from a given descent.
00664 */
00665 void insertAscents(std::set<BlockElt>& hs, const set::SetEltList& hr, size_t s,
00666                    const Block& block)
00667 {
00668   using descents::DescentStatus;
00669 
00670   for (size_t j = 0; j < hr.size(); ++j)
00671   {
00672     BlockElt z = hr[j];
00673     switch (block.descentValue(s,z))
00674     {
00675     case DescentStatus::ComplexAscent:
00676       hs.insert(block.cross(s,z));
00677       break;
00678     case DescentStatus::ImaginaryTypeI:
00679       hs.insert(block.cayley(s,z).first);
00680       break;
00681     case DescentStatus::ImaginaryTypeII:
00682       hs.insert(block.cayley(s,z).first);
00683       hs.insert(block.cayley(s,z).second);
00684       break;
00685     default: // not a strict ascent
00686       break;
00687     }
00688   }
00689 }
00690 
00691 
00692 /*!
00693   \brief Puts into |Hasse| the hasse diagram data for the Bruhat
00694   ordering on |block|.
00695 
00696   Explanation: we used the algorithm from Vogan's 1982 Park City notes...
00697   which contains a bad definition. Now modified to work like kgb makeHasse:
00698   seek an ascent s that is complex or type I real. If it exists, use it as in
00699   kgb. If it doesn't then we're essentially at a split principal series. The
00700   immediate predecessors of z are just the inverse Cayley transforms.
00701 */
00702 void makeHasse(std::vector<set::SetEltList>& Hasse, const Block& block)
00703 {
00704   using descents::DescentStatus;
00705 
00706   Hasse.resize(block.size());
00707 
00708   for (BlockElt z = 0; z < block.size(); ++z) {
00709 
00710     std::set<BlockElt> h_z;
00711 
00712     size_t s=block.firstStrictGoodDescent(z);
00713     if (s<block.rank())
00714       switch (block.descentValue(s,z))
00715       {
00716       default: assert(false); break;
00717       case DescentStatus::ComplexDescent:
00718         {
00719           BlockElt sz = block.cross(s,z);
00720           h_z.insert(sz);
00721           insertAscents(h_z,Hasse[sz],s,block);
00722         }
00723         break;
00724       case DescentStatus::RealTypeI: // inverseCayley(s,z) is two-valued
00725         {
00726           BlockEltPair sz = block.inverseCayley(s,z);
00727           h_z.insert(sz.first);
00728           h_z.insert(sz.second);
00729           insertAscents(h_z,Hasse[sz.first],s,block);
00730         }
00731       }
00732     else // now just gather all RealTypeII descents of |z|
00733       for (size_t s = 0; s < block.rank(); ++s)
00734         if (block.descentValue(s,z)==DescentStatus::RealTypeII)
00735           h_z.insert(block.inverseCayley(s,z).first);
00736 
00737     std::copy(h_z.begin(),h_z.end(),std::back_inserter(Hasse[z])); // set->list
00738   }
00739 }
00740 
00741 } // namespace
00742 
00743 /*****************************************************************************
00744 
00745       Chapter IV -- Functions exported from blocks.cpp (declared in blocks.h)
00746 
00747 ******************************************************************************/
00748 
00749 std::vector<BlockElt> dual_map(const Block& b, const Block& dual_b)
00750 {
00751 
00752   assert(b.size()==dual_b.size());
00753 
00754   std::vector<BlockElt> result(b.size());
00755   for (BlockElt i=0; i<b.size(); ++i)
00756     result[i]=dual_b.element(b.y(i),b.x(i));
00757 
00758   return result;
00759 }
00760 
00761 /*! Find Cartans classes of |G| whose dual involution occurs for |dG| */
00762 bitmap::BitMap common_Cartans(realredgp::RealReductiveGroup& GR,
00763                               realredgp::RealReductiveGroup& dGR)
00764 {
00765   bitmap::BitMap result=GR.cartanSet();
00766   result &= GR.complexGroup().dualCartanSet(dGR.realForm());
00767 
00768   return result;
00769 }
00770 
00771 } // namespace blocks
00772 
00773 } // namespace atlas

Generated on Wed Mar 26 16:49:33 2008 for atlas by  doxygen 1.3.9.1