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

/home/r0/dav/atlas.dir/atlas3/sources/structure/cartanset.cpp

Go to the documentation of this file.
00001 /*! \file \brief Implementation of the class CartanClassSet, storing
00002 information about the set of stable conjugacy classes of Cartan subgroups.
00003 
00004   This module, together with the cartanclass one, contains code for
00005   dealing with conjugacy classes of Cartan subgroups, and real
00006   forms. In this version, we have de-emphasized the classification of
00007   strong real forms, which is perhaps better treated as an
00008   input-output issue (it can certainly be recovered with a moderate
00009   effort from the data available here.) It appears that the data
00010   recorded here is what's most relevant to representation theory.
00011 
00012   The classification of real forms amounts to the classification of
00013   W^\delta- orbits in the fundamental fiber of the one-sided parameter
00014   space for the adjoint group (see the "combinatorics" paper on the
00015   Atlas website, or the forthcoming "algorithms" paper by Jeff Adams
00016   and Fokko du Cloux.); this is a very small computation, depending
00017   only on the Lie algebra.
00018 
00019   The classifications of conjugacy classes of Cartan subgroups, for the
00020   various real forms, all embed into the classification of conjugacy classes
00021   of root data involutions for the given inner class, equivalent to the
00022   classification of twisted involutions in the Weyl group, which is a purely
00023   combinatorial Weyl group computation. Fokko's original code proceeded more
00024   or less by listing each of these conjugacy classes, checking each new
00025   twisted involution for membership of each class of previously generated
00026   ones. Here we find for each conjugacy class of twisted involutions a
00027   canonical representative, which is relatively easy to compute. In this way
00028   we avoid enumeration of each conjugacy class.
00029 
00030   The classification of real forms can be recovered in this picture as
00031   well, by looking at the unique most split Cartan class for each real
00032   form.
00033 
00034   The most delicate part is the "correlation" part: for each Cartan, tell
00035   which orbit in the corresponding fiber corresponds to which real form, the
00036   real forms being labelled by the orbits in the fundamental fiber. In the
00037   current version, the solution to this problem is cleaner then previously,
00038   and perfectly general: it is obtained by writing out a system of equations
00039   for the grading defining the real form; this system does not always have a
00040   unique solution, but all solutions correspond to the same real form.
00041 */
00042 /*
00043   This is cartanset.cpp
00044 
00045   Copyright (C) 2004,2005 Fokko du Cloux
00046   part of the Atlas of Reductive Lie Groups
00047 
00048   See file main.cpp for full copyright notice
00049 */
00050 
00051 #include "cartanset.h"
00052 #include "complexredgp.h"
00053 #include "setutils.h"
00054 #include <set>
00055 
00056 #include <cassert>
00057 #include "rootdata.h"
00058 #include "tags.h"
00059 
00060 
00061 namespace atlas {
00062 
00063 namespace cartanset{
00064 
00065   void crossPart(weyl::WeylWord&, const weyl::WeylWord&,
00066                    const weyl::WeylGroup&);
00067 
00068   void cayleyPart(rootdata::RootList&, const weyl::WeylWord&,
00069                     const rootdata::RootDatum&, const weyl::WeylGroup&);
00070 
00071   void crossTransform(rootdata::RootList&,
00072                       const weyl::WeylWord&, const rootdata::RootDatum&);
00073 
00074   unsigned long makeRepresentative(const gradings::Grading&,
00075                                    const rootdata::RootList&,
00076                                    const cartanclass::Fiber&);
00077 
00078   void transformGrading(gradings::Grading&,
00079                         const rootdata::RootList&,
00080                         const rootdata::RootList&,
00081                         const rootdata::RootDatum&);
00082 
00083   bool isImaginary(const latticetypes::LatticeElt& v,
00084                    const weyl::TwistedInvolution& tw,
00085                    const weyl::WeylGroup&,
00086                    const rootdata::RootDatum&,
00087                    const latticetypes::LatticeMatrix& distinguished);
00088 
00089   bool checkDecomposition(const weyl::TwistedInvolution& ti,
00090                           const weyl::WeylWord& cross,
00091                           const rootdata::RootList& cayley,
00092                           const weyl::WeylGroup&,
00093                           const rootdata::RootDatum&,
00094                           const latticetypes::LatticeMatrix& distinguished);
00095 
00096   const size_t UndefMostSplit = ~0ul;
00097   const realform::RealForm UndefRealForm = ~0ul;
00098 
00099 } // namespace cartanset
00100 
00101 /*****************************************************************************
00102 
00103         Chapter I --- The CartanClassSet class, construction
00104 
00105 ******************************************************************************/
00106 
00107 namespace cartanset {
00108 
00109 // the unique constructor
00110 CartanClassSet::CartanClassSet
00111   (const complexredgp::ComplexReductiveGroup& parent,
00112    const latticetypes::LatticeMatrix& q)
00113   : d_parent(parent) // fix reference to parent inner class
00114 
00115   // install the fundamental Cartan, with associated data (like numRealForms)
00116   , d_cartan(1,new cartanclass::CartanClass(parent.rootDatum(),q))
00117 
00118   // initalise following structures to correspond to just fundamental Cartan
00119   , d_twistedInvolution(1,TwistedInvolution(weyl::WeylElt()))
00120   , d_ordering(1) // Cartans for a one point poset for now
00121 
00122   // the fundamental fiber can be copied from the fundamental Cartan
00123   , d_fundamental(d_cartan[0]->fiber())
00124   /* for the dual fundamental fiber it is tempting to give arguments either
00125      (d_cartan[0]->dualFiber()) or (parent.rootDatum(),q,tags::DualTag()).
00126      Both would give the same, wrong, result; one needs |dualBasedInvolution|.
00127      This fiber will be equal to the dual fiber for the most split Cartan.
00128   */
00129   , d_dualFundamental(rootdata::RootDatum(parent.rootDatum(),tags::DualTag())
00130                      ,dualBasedInvolution(q,parent.rootDatum()))
00131 
00132   // for real form labels install single list (filled later)
00133   , d_realFormLabels(1,realform::RealFormList(d_fundamental.numRealForms()))
00134   // for dual real forms, |correlateDualForms| will add such a list
00135   , d_dualRealFormLabels()
00136 
00137   /* for now each (dual) real form knows about one Cartan (filled in later) */
00138   , d_support(numRealForms(),bitmap::BitMap(1))
00139   , d_dualSupport(numDualRealForms(),bitmap::BitMap(1))
00140 
00141   , d_status(numRealForms())
00142   , d_mostSplit(numRealForms(),UndefMostSplit)
00143 {
00144   /* since the fundamental Cartan is the reference for the numbering of real
00145      forms, each real form label for it just refers to itself */
00146   for (size_t i=0; i<numRealForms(); ++i)
00147     d_realFormLabels[0][i]=i;
00148 
00149   // for dual real forms, |correlateDualForms| adds the proper singleton list
00150   correlateDualForms(rootdata::RootDatum(parent.rootDatum(),tags::DualTag())
00151                     ,weyl::WeylGroup(parent.weylGroup(),tags::DualTag()));
00152 
00153   // mark the fundamental Cartan in each real form, and in one dual real form
00154   updateSupports(0); // take into account Cartan class number |0|
00155 
00156   /* mark the (compact) real form for which the fundamental Cartan is the most
00157      split one as done in |d_status|, and fill its value in |d_mostSplit| */
00158   updateStatus(0); // here the |0| means from Cartan |0| on.
00159 }
00160 
00161 /*!
00162   The only data explicitly allocated by the CartanClass is that for the
00163   CartanClass pointers.
00164 */
00165 CartanClassSet::~CartanClassSet()
00166 {
00167   for (size_t j = 0; j < d_cartan.size(); ++j)
00168     delete d_cartan[j];
00169 }
00170 
00171 /********* copy, assignment and swap *****************************************/
00172 
00173 // This should remain empty!
00174 
00175 /******** manipulators *******************************************************/
00176 
00177 /*!
00178   \brief Extends the CartanClassSet structure so that it contains all Cartans
00179   for the real form |rf|.
00180 
00181   This is done by traversing all the known Cartan classes |j| defined for the
00182   real form |rf| (which includes at least the distinguished Cartan for the
00183   inner class), and all non-compact positive imaginary roots \f$\alpha\f$ for
00184   |(rf,j)|; the twisted involution |tw| for the Cartan class |j| is then
00185   left-multiplied by \f$s_\alpha\f$ to obtain a new twisted involution |ti|, and
00186   if |ti| is not member of any of the known classes of twisted involutions, it
00187   starts a new Cartan class defined in |rf|, which will later itself be
00188   considered in the loop described here.
00189 
00190   While generating the Cartan classes, the ordering is extended by a link from
00191   the Cartan class |j| to the Cartan class of any twisted involution |ti|
00192   obtained directly from it.
00193 
00194 */
00195 void CartanClassSet::extend(realform::RealForm rf)
00196 {
00197   if (d_status.isMember(rf)) // nothing to be done
00198     return;
00199 
00200   size_t prev_Cartans=d_cartan.size(); // mark size for possible roll-back
00201   bitmap::BitMap prev_status=d_status; // save this one, is hard to roll back
00202 
00203   try
00204   {
00205     const rootdata::RootDatum dualRootDatum(rootDatum(),tags::DualTag());
00206     const weyl::WeylGroup dualWeylGroup(weylGroup(),tags::DualTag());
00207 
00208     std::set<poset::Link> lks;
00209 
00210     // d_cartan.size() may grow in the course of the loop
00211     for (size_t j = 0; j < d_cartan.size(); ++j)
00212     {
00213       if (not isDefined(rf,j))
00214         continue;
00215 
00216       rootdata::RootSet rs=noncompactPosRootSet(rf,j);
00217 
00218       for (rootdata::RootSet::iterator it = rs.begin(); it(); ++it)
00219       {
00220 
00221         // multipy |twistedInvolution(j)| on the left by the reflection |*it|
00222         TwistedInvolution tw=reflection(*it,d_twistedInvolution[j]);
00223 
00224         /* check if we have a new twisted involution;
00225            if so, extend the cartan structure */
00226 
00227         canonicalize(tw);
00228         size_t k = setutils::find_index(d_twistedInvolution,tw);
00229         lks.insert(std::make_pair(j,k)); // insert link in any case
00230         if (k == d_twistedInvolution.size()) // then class |k| is new
00231         {
00232           d_twistedInvolution.push_back(tw); // record new canonical form
00233           addCartan(tw); // and add corresponding Cartan class to |d_cartan|
00234           correlateForms();
00235           correlateDualForms(dualRootDatum,dualWeylGroup);
00236           updateSupports(k); // take into account Cartan class number |k|
00237         }
00238       } // for (it)
00239     } // for (j)
00240 
00241     // update the order relation
00242     std::vector<poset::Link> lk(lks.begin(),lks.end());
00243     d_ordering.resize(d_cartan.size());
00244     d_ordering.extend(lk);
00245 
00246     // update |d_status| and |d_mostSplit| values for now completed real forms
00247     updateStatus(prev_Cartans);
00248 
00249   } // try
00250 
00251   catch (...) // ensure roll-back on (for instance) memory overflow
00252   { // the restoring code below avoids having to copy everything on entry
00253     d_cartan.resize(prev_Cartans);
00254     d_twistedInvolution.resize(prev_Cartans);
00255     d_ordering.resize(prev_Cartans);
00256     d_realFormLabels.resize(prev_Cartans);
00257     d_dualRealFormLabels.resize(prev_Cartans);
00258 
00259     for (size_t i=0; i<numRealForms(); ++i)
00260     {
00261       d_support[i].set_capacity(prev_Cartans);
00262       d_dualSupport[i].set_capacity(prev_Cartans);
00263     }
00264     d_status.swap(prev_status); // restore set of completed real forms
00265     prev_status.andnot(d_status); // now |prev_status| flags "new" real forms
00266     for (bitmap::BitMap::iterator it=prev_status.begin(); it(); ++it)
00267       d_mostSplit[*it]=UndefMostSplit; // clear unsure most split Cartans
00268     throw; // rethrow same exception
00269   }
00270 }
00271 
00272 /*!
00273   \brief Returns the various conjugacy classes of twisted involutions
00274   for the currently known Cartans.
00275 
00276   This method is NO LONGER USED during constructiont of a |CartanClassSet|.
00277 
00278   Note: the lists come out sorted, to allow binary look-up; this is in fact
00279   dependent on the implementation of |weyl::WeylGroup::twistedConjugacyClass|
00280 */
00281 std::vector<weyl::WeylEltList> CartanClassSet::expand() const
00282 {
00283   const weyl::WeylGroup& W = weylGroup();
00284   std::vector<weyl::WeylEltList> result(d_cartan.size());
00285 
00286   for (size_t j = 0; j < d_cartan.size(); ++j) {
00287     W.twistedConjugacyClass(result[j],d_twistedInvolution[j]);
00288   }
00289 
00290   return result;
00291 }
00292 
00293 /*!
00294   \brief Adds a new cartan to |d_cartan|, obtained from cartan \#j by
00295   Cayley transform through root \#rn.
00296   NO LONGER USED
00297 */
00298 void CartanClassSet::addCartan(rootdata::RootNbr rn, size_t j)
00299 {
00300   const rootdata::RootDatum& rd = rootDatum();
00301   latticetypes::LatticeMatrix q;
00302   rd.rootReflection(q,rn);
00303   q *= cartan(j).involution();
00304   d_cartan.push_back(new cartanclass::CartanClass(rd,q));
00305 }
00306 
00307 
00308 } // namespace cartanset
00309 
00310 /*****************************************************************************
00311 
00312         Chapter II --- private (auxiliary) methods for CartanClassSet
00313 
00314 ******************************************************************************/
00315 
00316 namespace cartanset {
00317 
00318 /******** private accessors **************************************************/
00319 
00320 
00321 
00322 /*!
00323   \brief Returns |tw| composed to the left with the reflection |s_rn|
00324   corresponding to root \#rn
00325 
00326   This is a twisted involution if |s_rn| twisted-commutes with |tw|;
00327   in practice root \#rn will in fact be imaginary for |tw|
00328 */
00329 TwistedInvolution
00330 CartanClassSet::reflection(rootdata::RootNbr rn,const TwistedInvolution& tw)
00331   const
00332 {
00333   const weyl::WeylGroup& W = weylGroup();
00334 
00335   weyl::WeylWord rw=rootDatum().reflectionWord(rn);
00336 
00337   TwistedInvolution result=tw;
00338   for (size_t i=rw.size(); i-->0; ) // left multiply |tw| by |rw|
00339     W.leftMult(result,rw[i]);
00340 
00341   return result;
00342 }
00343 
00344 rootdata::RootSet CartanClassSet::noncompactPosRootSet
00345   (realform::RealForm rf, size_t j) const
00346 /*!
00347   \brief Flags in rs the set of noncompact positive roots for Cartan \#j.
00348 */
00349 
00350 {
00351   const cartanclass::Fiber& f = cartan(j).fiber();
00352   unsigned long x = CartanClassSet::representative(rf,j);
00353 
00354   rootdata::RootSet result=f.noncompactRoots(x);
00355   result &= rootDatum().posRootSet();
00356   return result;
00357 }
00358 
00359 /******** private manipulators **********************************************/
00360 
00361 void CartanClassSet::correlateForms()
00362 
00363 /*!
00364   \brief Adds a new real form label list to d_realFormLabels.
00365 
00366   Algorithm: the gradings of the imaginary root system corresponding to the
00367   various real forms for which the new cartan is defined are known. We find
00368   a cross-action followed by a composite Cayley transform, taking the
00369   fundamental cartan to the new one. Then for each real form, we take a
00370   representative grading, and compute a grading for the fundamental cartan
00371   transforming to it. This amounts to solving a system of linear equations
00372   mod 2.
00373 
00374   Explanation: this is called when a new cartan class has just been added
00375   to d_cartan. Then this function finds the labels corresponding to the
00376   real forms for which this cartan is defined (the labelling of real forms
00377   being defined by the adjoint orbit picture in the fundamental fiber.)
00378 */
00379 
00380 {
00381   using namespace cartanclass;
00382   using namespace gradings;
00383   using namespace partition;
00384   using namespace rootdata;
00385   using namespace weyl;
00386 
00387   const RootDatum& rd = rootDatum();
00388 
00389   const WeylGroup& W = weylGroup();
00390 
00391   const Fiber& fundf = fundamental();
00392   const Fiber& f = d_cartan.back()->fiber();
00393 
00394   const TwistedInvolution& ti = d_twistedInvolution.back();
00395 
00396   // find cayley part and cross part
00397   RootList so;
00398   WeylWord ww;
00399   cayley_and_cross_part(so,ww,ti,rd,W);
00400 
00401   assert(checkDecomposition(ti,ww,so,W,rd,distinguished()));
00402 
00403   const Partition& pi = f.weakReal();
00404   realform::RealFormList rfl(f.numRealForms());
00405 
00406   // transform gradings and correlate forms
00407   for (size_t j = 0; j < rfl.size(); ++j) {
00408     unsigned long y = pi.classRep(j);
00409     Grading gr=f.grading(y);
00410     RootList rl = f.simpleImaginary(); // the roots of which |gr| are a grading
00411 
00412     transformGrading(gr,rl,so,rd);
00413     for (size_t i = 0; i < so.size(); ++i)
00414       gr.set(rl.size()+i);             // make grading set for roots in |so|
00415     copy(so.begin(),so.end(),back_inserter(rl)); // extend |rl| with |so|
00416     crossTransform(rl,ww,rd);  // apply cross part of |ti| to roots in |rl|
00417 
00418     /* now |gr| grades the roots in |rl|,
00419        which are imaginary for the fundamental fiber |fundf| */
00420     for (size_t i = 0; i < rl.size(); ++i)
00421       assert(fundf.imaginaryRootSet().isMember(rl[i]));
00422 
00423     unsigned long x = makeRepresentative(gr,rl,fundf);
00424     realform::RealForm rf = fundf.weakReal()(x); // look up representative
00425     rfl[j] = rf;
00426   }
00427 
00428   d_realFormLabels.push_back(rfl);
00429 }
00430 
00431 void CartanClassSet::correlateDualForms(const rootdata::RootDatum& rd,
00432                                         const weyl::WeylGroup& W)
00433   // arguments are dual root datum and dual group
00434 {
00435   using namespace cartanclass;
00436   using namespace gradings;
00437   using namespace latticetypes;
00438   using namespace partition;
00439   using namespace rootdata;
00440   using namespace weyl;
00441 
00442   const Fiber& fundf = dualFundamental();
00443   const Fiber& f = d_cartan.back()->dualFiber();
00444 
00445   /* find dual twisted involution by right-multiplication of |f| by |fundf|.
00446      However since |word_of_inverse_matrix| is used, we compute |q=fundf*f|. */
00447   LatticeMatrix q = fundf.involution();
00448   q *= f.involution();
00449   WeylWord tiww=rd.word_of_inverse_matrix(q);
00450   TwistedInvolution ti(WeylElt(tiww,W));
00451 
00452   // find cayley part and cross part
00453   RootList so;
00454   WeylWord ww;
00455   cayley_and_cross_part(so,ww,ti,rd,W);
00456 // begin testing
00457   assert(checkDecomposition(ti,ww,so,W,rd,fundf.involution()));
00458 // end testing
00459 
00460   const Partition& pi = f.weakReal();
00461   realform::RealFormList rfl(f.numRealForms());
00462 
00463   // transform gradings and correlate forms
00464   for (size_t j = 0; j < rfl.size(); ++j) {
00465     unsigned long y = pi.classRep(j);
00466     Grading gr=f.grading(y);
00467     RootList rl = f.simpleImaginary();
00468     transformGrading(gr,rl,so,rd);
00469     for (size_t i = 0; i < so.size(); ++i)
00470       gr.set(rl.size()+i);
00471     copy(so.begin(),so.end(),back_inserter(rl));
00472     crossTransform(rl,ww,rd);
00473 
00474 // begin testing
00475     /* now |gr| grades the roots in |rl|,
00476        which are imaginary for the dual fundamental fiber |fundf| */
00477     for (size_t i = 0; i < rl.size(); ++i)
00478       assert(fundf.imaginaryRootSet().isMember(rl[i]));
00479 // end testing
00480 
00481     unsigned long x = makeRepresentative(gr,rl,fundf);
00482     realform::RealForm rf = fundf.weakReal()(x);
00483     rfl[j] = rf;
00484   }
00485 
00486   d_dualRealFormLabels.push_back(rfl);
00487 }
00488 
00489 void CartanClassSet::updateStatus(size_t prev)
00490 
00491 /*!
00492   \brief Updates d_status.
00493 
00494   Precondition: prev is the previous size of d_cartan;
00495 
00496   Explanation: d_status holds the subset of the set of real forms for
00497   which the full set of Cartan classes is constructed; equivalently, those
00498   for which the most split Cartan has been reached.
00499 */
00500 
00501 {
00502   for (size_t j = prev; j<d_cartan.size(); ++j) // traverse new Cartan classes
00503   {
00504 
00505     const cartanclass::Fiber& f = cartan(j).fiber();
00506     const partition::Partition& pi = f.weakReal();
00507     const realform::RealFormList& rfl = realFormLabels(j);
00508 
00509     for (unsigned long c = 0; c < pi.classCount(); ++c) // traverse weak reals
00510     {
00511       if (cartan(j).isMostSplit(c))
00512       { // flag the form identified by class |c| in fiber of Cartan |j|
00513         d_status.insert(rfl[c]);
00514         d_mostSplit[rfl[c]] = j;
00515         // might do |break|, since no two real forms share a most split Cartan
00516       }
00517     }
00518 
00519   }
00520 
00521   return;
00522 }
00523 
00524 void CartanClassSet::updateSupports(size_t last)
00525 
00526 /*!
00527   \brief Updates d_support and d_dualSupport.
00528 
00529   Explanation: for each real form rf, d_support[rf] contains the subset of the
00530   set of the currently defined cartans which are defined for rf; and
00531   analogously for d_dualSupport[rf]. This information is in fact a
00532   "cross-section" of the realFormLabels lists, which for each Cartan list the
00533   set of real forms for which the Cartan is defined. This function is called
00534   each time a new Cartan is added, and updates these lists.
00535 */
00536 
00537 {
00538   using namespace bitmap;
00539 
00540   for (size_t j = 0; j < d_support.size(); ++j)
00541     d_support[j].set_capacity(last+1);
00542 
00543   for (size_t j = 0; j < d_dualSupport.size(); ++j)
00544     d_dualSupport[j].set_capacity(last+1);
00545 
00546   const realform::RealFormList& rfl = realFormLabels(last);
00547 
00548   for (size_t j = 0; j < rfl.size(); ++j) {
00549     d_support[rfl[j]].insert(last);
00550   }
00551 
00552   const realform::RealFormList& drfl = dualRealFormLabels(last);
00553 
00554   for (size_t j = 0; j < drfl.size(); ++j) {
00555     d_dualSupport[drfl[j]].insert(last);
00556   }
00557 }
00558 
00559 void CartanClassSet::updateTwistedInvolutions
00560   (std::vector<weyl::WeylEltList>& known,
00561    const TwistedInvolution& tw)
00562 
00563 /*!
00564   \brief Updates the known list by adding the twisted class of tw to it.
00565 */
00566 
00567 {
00568 
00569   d_twistedInvolution.push_back(tw);
00570 
00571   weyl::WeylEltList wl; weylGroup().twistedConjugacyClass(wl,tw);
00572 
00573   known.push_back(weyl::WeylEltList());
00574   known.back().swap(wl);
00575 }
00576 
00577 /*****************************************************************************
00578 
00579         Chapter III --- public accessor methods for CartanClassSet
00580 
00581 ******************************************************************************/
00582 
00583 
00584 /******** accessors **********************************************************/
00585 
00586 /*!
00587   \brief Returns the size of the fiber orbits corresponding to the strong
00588   real forms lying over (weak) real form \#rf, in cartan \#cn.
00589 
00590   Precondition: Real form \#rf is defined for cartan \#cn.
00591 */
00592 unsigned long CartanClassSet::fiberSize(realform::RealForm rf, size_t cn) const
00593 {
00594   cartanclass::adjoint_fiber_orbit wrf = real_form_part(rf,cn);
00595   // |wrf| indexes a $W_{im}$ orbit on |cartan(cn).fiber().adjointFiberGroup()|
00596 
00597   const cartanclass::Fiber& f = cartan(cn).fiber();
00598   const cartanclass::StrongRealFormRep& srf = f.strongRepresentative(wrf);
00599 
00600   assert(srf.second==f.central_square_class(wrf));
00601 
00602   const partition::Partition& pi =f.strongReal(srf.second);
00603   /* |pi| is an (unnormalized) partition of |cartan(cn).fiber().fiberGroup()|
00604      whose identifying values label central square classes, and are elements
00605      of the quotient affine space $adjoint fiber/image of fiber group$
00606   */
00607 
00608   size_t c = pi(srf.first);
00609   return pi.classSize(c);
00610 }
00611 
00612 /*!
00613   \brief Returns the size of the dual fiber orbits corresponding to
00614   the dual strong real forms lying over dual real form \#rf, in Cartan
00615   \#cn.
00616 
00617   Precondition: real form \#rf is defined for cartan \#cn.
00618 */
00619 
00620 unsigned long CartanClassSet::dualFiberSize(realform::RealForm rf, size_t cn)
00621   const
00622 {
00623   cartanclass::adjoint_fiber_orbit wrf = dual_real_form_part(rf,cn);
00624 
00625   const cartanclass::Fiber& df = cartan(cn).dualFiber();
00626   const cartanclass::StrongRealFormRep& srf = df.strongRepresentative(wrf);
00627 
00628   assert(srf.second==df.central_square_class(wrf));
00629 
00630   const partition::Partition& pi = df.strongReal(srf.second);
00631 
00632   size_t c = pi(srf.first);
00633 
00634   return pi.classSize(c);
00635 }
00636 
00637 /*!
00638   \brief Returns the total number of involutions corresponding to the
00639   currently defined set of Cartans.
00640 */
00641 size_t CartanClassSet::numInvolutions() const
00642 {
00643   size_t count = 0;
00644 
00645   for (size_t cn = 0; cn < d_cartan.size(); ++cn)
00646     count += cartan(cn).orbitSize();
00647 
00648   return count;
00649 }
00650 
00651 /*!
00652   \brief Returns the total number of involutions corresponding to the
00653   indicated set of Cartans.
00654 */
00655 size_t CartanClassSet::numInvolutions(const bitmap::BitMap& Cartan_classes)
00656   const
00657 {
00658   size_t count = 0;
00659 
00660   for (bitmap::BitMap::iterator it=Cartan_classes.begin(); it(); ++it)
00661     count += cartan(*it).orbitSize();
00662 
00663   return count;
00664 }
00665 
00666 /*!
00667   \brief Returns a representative for real form \#rf in Cartan \#cn.
00668 
00669   Precondition: cartan \#cn occurs for that real form.
00670 
00671   Explanation: this amounts to searching for rf in d_realFormLabels[cn].
00672 */
00673 unsigned long CartanClassSet::representative(realform::RealForm rf, size_t cn)
00674   const
00675 {
00676   return cartan(cn).fiber().weakReal().classRep(real_form_part(rf,cn));
00677 }
00678 
00679 /*!
00680   \brief Returns a representative for dual real form \#rf in Cartan \#cn.
00681 
00682   Precondition: cartan \#cn occurs for that dual real form.
00683 
00684   Explanation: this amounts to searching for \#rf in d_dualRealFormLabels[cn].
00685 */
00686 unsigned long CartanClassSet::dualRepresentative(realform::RealForm rf,
00687                                                 size_t cn) const
00688 {
00689   return
00690     cartan(cn).dualFiber().weakReal().classRep(dual_real_form_part(rf,cn));
00691 }
00692 
00693 
00694 latticetypes::LatticeMatrix
00695 CartanClassSet::involutionMatrix(const weyl::TwistedInvolution& tw)
00696   const
00697 {
00698   weyl::WeylWord ww;
00699   weylGroup().out(ww,tw.w());
00700   latticetypes::LatticeMatrix result;
00701   rootdata::toMatrix(result, ww,rootDatum());
00702   result *= distinguished();
00703   return result;
00704 }
00705 
00706 /*!
00707 \brief Modify |v| through through involution associated to |tw|
00708 */
00709 void CartanClassSet::twistedAct
00710   (const weyl::TwistedInvolution& tw,latticetypes::LatticeElt& v) const
00711 {
00712   distinguished().apply(v,v);
00713   weylGroup().act(rootDatum(),tw.w(),v);
00714 }
00715 
00716 bool isImaginary (const latticetypes::LatticeElt& v,
00717                   const weyl::TwistedInvolution& tw,
00718                   const weyl::WeylGroup& W,
00719                   const rootdata::RootDatum& rd,
00720                   const latticetypes::LatticeMatrix& distinguished)
00721 {
00722   latticetypes::LatticeElt x=v;
00723   distinguished.apply(x,x);
00724   W.act(rd,tw.w(),x);
00725   return x==v;
00726 }
00727 
00728 /*!
00729 \brief Sum of the real roots.
00730 */
00731 latticetypes::LatticeElt
00732   CartanClassSet::posRealRootSum(const TwistedInvolution& tw) const
00733 {
00734   cartanclass::InvolutionData d(rootDatum(),involutionMatrix(tw));
00735   return rootDatum().twoRho(d.real_roots());
00736 }
00737 
00738   /*!
00739 \brief Sum of the imaginary roots.
00740   */
00741 latticetypes::LatticeElt
00742   CartanClassSet::posImaginaryRootSum(const TwistedInvolution& tw) const
00743 {
00744   cartanclass::InvolutionData d(rootDatum(),involutionMatrix(tw));
00745   return rootDatum().twoRho(d.imaginary_roots());
00746 }
00747 
00748 /*! \brief Make |sigma| canonical and return Weyl group |w| element that
00749     twisted conjugates the canonical representative back to original |sigma|.
00750 
00751     We find conjugating generators starting at the original `|sigma|' end, so
00752     these form the letters of |w| from left to right.
00753 */
00754 const weyl::WeylElt
00755 CartanClassSet::canonicalize(TwistedInvolution &sigma) const
00756 {
00757   const rootdata::RootDatum& rd=rootDatum();
00758 
00759   weyl::WeylElt w; // this will be the result
00760   latticetypes::LatticeElt rrs=posRealRootSum(sigma);
00761 
00762   {
00763     size_t i; // declare outside loop to allow inspection of final value
00764     do
00765       for (i=0; i<rd.semisimpleRank(); ++i)
00766         if (latticetypes::scalarProduct(rd.simpleCoroot(i),rrs) < 0 )
00767         {
00768           rd.reflection(rrs,rd.simpleRootNbr(i)); // apply $s_i$ to root sum
00769           weylGroup().twistedConjugate(sigma,i);  // adjust |sigma| accordingly
00770           weylGroup().mult(w,i);                  // and add generator to |w|
00771           break;     // after this change, continue the |do|-|while| loop
00772         }
00773     while (i!=rd.semisimpleRank());    // i.e., until no change occurs any more
00774   }
00775 
00776 
00777 /* now continue normalization, processing roots orthogonal to |rrs|. Since
00778    |rrs| is dominant, we can limit our attention to simple roots: any positive
00779    root orthogonal to |rrs| is a sum of simple roots orthogonal to |rrs|.
00780 */
00781 
00782   latticetypes::LatticeElt irs=posImaginaryRootSum(sigma);
00783 
00784   bitset::RankFlags simple_orth;
00785 
00786   for (size_t  i=0; i <  rd.semisimpleRank(); ++i)
00787     if (latticetypes::scalarProduct(rd.simpleCoroot(i),rrs) == 0)
00788       simple_orth.set(i);
00789 
00790   {
00791     bitset::RankFlags::iterator it;
00792     do
00793       for (it=simple_orth.begin(); it(); ++it)
00794         if (latticetypes::scalarProduct(rd.simpleCoroot(*it),irs) < 0)
00795         {
00796           rd.reflection(irs,rd.simpleRootNbr(*it)); // apply $s_i$ to root sum
00797           weylGroup().twistedConjugate(sigma,*it);  // adjust |sigma|
00798           weylGroup().mult(w,*it);                  // and add generator to |w|
00799           break;           // after this change, continue the |do|-|while| loop
00800         }
00801     while (it()); // i.e., until no change occurs any more
00802   }
00803 
00804 
00805   /* Finally deal with simple roots orthogonal to |rrs| and to |irs| */
00806 
00807 
00808   // clear those simple roots in |simp_orth| not orthogonal to |irs|
00809   for (bitset::RankFlags::iterator it=simple_orth.begin(); it(); ++it)
00810     if (latticetypes::scalarProduct(rd.simpleCoroot(*it),irs) > 0)
00811       simple_orth.reset(*it);
00812 
00813 
00814 /* Now ensure that the involution |theta| associated to the twisted involution
00815    |sigma| fixes the dominant chamber for the root subsystem indicated in
00816    |simple_orth| (which we shall call the complex root subsystem). The vector
00817    |x=rd.twoRho()| below is in the interior of the dominant for the whole root
00818    system, so is a fortiori dominant of the subsystem. If its image is not
00819    dominant for the complex root subsystem, (twisted) conjugating |sigma| by
00820    any generator that makes the image more dominant will improve the situation
00821    (but not in the same way as the action of that generator: the image of
00822    |rd.twoRho()| under twisted action of |sigma| will get \emph{two} steps
00823    closer to the dominant chamber!), which we repeat until the image of
00824    |rd.twoRho()| becomes dominant for the complex root subsystem.
00825 */
00826   {
00827     bitset::RankFlags::iterator it;
00828     do
00829     {
00830       latticetypes::LatticeElt x=rd.twoRho(); // take fresh dominant each time
00831       twistedAct(sigma,x); // and (re)compute the effect of |sigma| into |x|
00832 
00833       for (it=simple_orth.begin(); it(); ++it)
00834         if (latticetypes::scalarProduct(rd.simpleCoroot(*it),x) < 0)
00835         {
00836           weylGroup().twistedConjugate(sigma,*it); // adjust |sigma|
00837           weylGroup().mult(w,*it);                 // and add generator to |w|
00838           break;                             // and continue |do|-|while| loop
00839         }
00840     }
00841     while (it()); // i.e., while |for| loop was interrupted
00842   }
00843 
00844   return  w; // but the main result is the modfied value left in |sigma|
00845 }
00846 
00847   /*!
00848 \brief find index of canonical representative of |sigma| in
00849   |d_twistedInvolution|, under the assumption that it is (already) present
00850   */
00851 size_t CartanClassSet::classNumber(TwistedInvolution sigma) const
00852 {
00853   canonicalize(sigma);
00854   return setutils::find_index(d_twistedInvolution,sigma);
00855 }
00856 
00857 /*!
00858 
00859   \brief returns index of canonical form of the product of twisted involution
00860   |d_twistedInvolution[j]| with the reflection through its |i|-th imaginary
00861   simple root. If |conjugator| is non-null, the conjugating element as returnd
00862   by |canonicalize| is assigned to |conjugator|.
00863 
00864   Note that the mentioned reflection twisted-commutes with
00865   |d_twistedInvolution[j]|, so that the product is again a twisted involution.
00866 */
00867 size_t CartanClassSet::cayley(size_t j, size_t i, weyl::WeylElt* conjugator)
00868   const
00869 {
00870   cartanclass::InvolutionData d
00871     (rootDatum(),involutionMatrix(d_twistedInvolution[j]));
00872   atlas::rootdata::RootNbr rn = d.imaginary_basis()[i];
00873 
00874   weyl::WeylWord rw=rootDatum().reflectionWord(rn);
00875 
00876   TwistedInvolution ti=d_twistedInvolution[j]; weylGroup().leftMult(ti,rw);
00877 
00878   if (conjugator==NULL) canonicalize(ti);
00879   else *conjugator=canonicalize(ti);
00880 
00881   return setutils::find_index(d_twistedInvolution,ti);
00882 }
00883 
00884 
00885 /*!
00886   \brief Returns the cardinality of the subset of \f$K\backslash G/B\f$
00887    associated to |rf| whose twisted involutions belong to |Cartan_classes|.
00888 
00889   Precondition: the Cartan classes for this real form have been generated
00890 */
00891 unsigned long
00892 CartanClassSet::KGB_size(realform::RealForm rf,
00893                          const bitmap::BitMap& Cartan_classes) const
00894 {
00895   unsigned long result=0;
00896   for (bitmap::BitMap::iterator it = Cartan_classes.begin(); it(); ++it)
00897     result +=  cartan(*it).orbitSize() * fiberSize(rf,*it);
00898 
00899   return result;
00900 
00901 }
00902 
00903 unsigned long
00904 CartanClassSet::block_size(realform::RealForm rf, realform::RealForm drf,
00905                            const bitmap::BitMap& Cartan_classes) const
00906 {
00907   unsigned long result=0;
00908   for (bitmap::BitMap::iterator it = Cartan_classes.begin(); it(); ++it)
00909   {
00910     unsigned long cn=*it;
00911     result +=
00912       cartan(cn).orbitSize() * fiberSize(rf,cn) * dualFiberSize(drf,cn);
00913   }
00914 
00915   return result;
00916 
00917 }
00918 
00919 } // namespace cartanset
00920 
00921 
00922 
00923 
00924 /*****************************************************************************
00925 
00926         Chapter IV --- Functions declared in cartanset.h
00927 
00928 ******************************************************************************/
00929 
00930 namespace cartanset {
00931 
00932 unsigned long blockSize(realform::RealForm rf, realform::RealForm drf,
00933                         const CartanClassSet& ccl)
00934 
00935 /*!
00936   \brief Returns the size of the block defined by the real form rf and the
00937   dual real form drf.
00938 
00939   NOTE: rf and drf are _weak_ real forms; the datum of the underlying weak
00940   real forms suffices to determine the structure of the block defined by a
00941   pair of strong real forms.
00942 */
00943 
00944 {
00945   bitmap::BitMap b = ccl.support(rf);
00946   b &= ccl.dualSupport(drf);
00947 
00948   return ccl.block_size(rf,drf,b);
00949 }
00950 
00951 unsigned long kgbSize(realform::RealForm rf, const CartanClassSet& ccl)
00952 
00953 /*!
00954   \brief Returns the cardinality of K\\G/B for this real form.
00955 
00956   Precondition: the Cartan classes for this real form have been generated
00957 
00958   Explanation: this is the cardinality of the one-sided parameter set
00959   corresponding to any strong real form over rf.
00960 */
00961 
00962 {
00963   return ccl.KGB_size(rf,ccl.support(rf));
00964 }
00965 
00966 /*!
00967   \brief Puts into |so| the composite Cayley transform, and into |cross| the
00968    cross action corresponding to the twisted involution |ti|.
00969 
00970   Explanation: to each root datum involution |q|, we may associate a
00971   transformation from the fundamental involution to |q| that factors as the
00972   composition of a cross action (conjugation by the inverse of an element
00973   |cross| of |W|) and a composite Cayley transform (composition with
00974   (commuting) reflections for the roots of a strongly orthogonal set |so| of
00975   imaginary roots). This function computes |cross| and |so|, for the
00976   involution |q| corresponding to the twisted involution |ti|.
00977 
00978   Note that conjugation is by the inverse of |cross| only because conjugation
00979   uses the letters of a Weyl word successively from right to left, whereas we
00980   collect the letters of |cross| from left to right as we go from the (twisted
00981   ivolution representing) the fundamental involution back to |q|.
00982 */
00983 void cayley_and_cross_part(rootdata::RootList& so,
00984                            weyl::WeylWord& cross,
00985                            const weyl::TwistedInvolution& ti,
00986                            const rootdata::RootDatum& rd,
00987                            const weyl::WeylGroup& W)
00988 {
00989   std::vector<signed char> dec=W.involution_expr(ti);
00990   TwistedInvolution tw; // to reconstruct |ti| as a check
00991 
00992   so.clear();
00993 
00994   for (size_t j=dec.size(); j-->0; )
00995     if (dec[j]>=0)
00996     {
00997       weyl::Generator s=dec[j];
00998       so.push_back(rd.simpleRootNbr(s));
00999       W.leftMult(tw,s);
01000     }
01001     else
01002     {
01003       weyl::Generator s=~dec[j];
01004       cross.push_back(s); // record cross action
01005       W.twistedConjugate(tw,s); // and twisted-conjugate |tw|
01006       for (size_t i = 0; i < so.size(); ++i) // and conjugate roots in |so|:
01007         rd.rootReflect(so[i],s);
01008     }
01009 
01010   assert(tw==ti);
01011   rootdata::strongOrthogonalize(so,rd);
01012 }
01013 
01014 } // namespace cartanset
01015 
01016 /*****************************************************************************
01017 
01018         Chapter V --- Auxiliary functions local to this module
01019 
01020 ******************************************************************************/
01021 
01022 namespace cartanset {
01023 
01024 void cayleyPart(rootdata::RootList& so,
01025                 const weyl::WeylWord& wi,
01026                 const rootdata::RootDatum& rd,
01027                 const weyl::WeylGroup& W)
01028 
01029 /*!
01030   \brief Puts in so the composite Cayley transform corresponding to wi.
01031 
01032   Precondition: |wi| is a reduced expression for a twisted involution |tw|;
01033 
01034   Explanation: to each root datum involution, we may associate a transformation
01035   from the fundamental Cartan to the current Cartan, that factors as the
01036   composition of a cross action and a composite Cayley transform. This function
01037   puts in |so| a system of strongly orthogonal roots representing the Cayley
01038   transform.
01039 
01040   The interpretation of the result is that the involution corresponding to
01041   |tw| can be obtained from a conjugate of the distinguished involution by
01042   multiplication by the (commuting) reflections for the roots in the strongly
01043   orthogonal set. The element by which the distinguished involution should be
01044   conjugated (more precisely its inverse) is given by |crossPart(.,wi,W)|
01045 */
01046 
01047 {
01048   using namespace rootdata;
01049   using namespace weyl;
01050 
01051   TwistedInvolution tw;
01052   so.clear();
01053 
01054   for (size_t j = 0; j < wi.size(); ++j) {
01055     Generator s = wi[j];
01056     if (W.hasTwistedCommutation(s,tw)) { // add new root to |so|
01057       so.push_back(rd.simpleRootNbr(s));
01058       W.leftMult(tw,s);
01059     }
01060     else { // conjugate roots in |so|
01061       for (size_t i = 0; i < so.size(); ++i)
01062         so[i] = rd.rootPermutation(s)[so[i]];
01063       W.twistedConjugate(tw,s); // and twisted-conjugate |tw|
01064     }
01065   }
01066 
01067   strongOrthogonalize(so,rd);
01068 }
01069 
01070 void crossPart(weyl::WeylWord& ww, const weyl::WeylWord& wi,
01071                        const weyl::WeylGroup& W)
01072 
01073 /*!
01074   \brief Puts in ww the cross action corresponding to wi.
01075 
01076   Explanation: to each root datum involution, we may associate a transformation
01077   from the fundamental cartan to the current cartan, that factors as the
01078   composition of a cross action and a composite Cayley transform. This function
01079   puts in ww a weyl word representing the cross action part.
01080 */
01081 
01082 {
01083   using namespace weyl;
01084 
01085   TwistedInvolution tw;
01086   ww.clear();
01087 
01088   for (size_t j = 0; j < wi.size(); ++j) {
01089     Generator s = wi[j];
01090     if (W.hasTwistedCommutation(s,tw)) { // cayley transform
01091       W.leftMult(tw,s);
01092     } else { // cross action
01093       ww.push_back(s);
01094       W.twistedConjugate(tw,s);
01095     }
01096   }
01097 }
01098 
01099 void crossTransform(rootdata::RootList& rl,
01100                     const weyl::WeylWord& ww,
01101                     const rootdata::RootDatum& rd)
01102 
01103 /*!
01104   \brief Cross-transforms the roots in rl according to ww.
01105 
01106   NOTE: the cross-transformations are done in _reverse_ order.
01107 */
01108 
01109 {
01110 
01111   for (size_t j = ww.size(); j-->0;) {
01112     setutils::Permutation a = rd.rootPermutation(ww[j]);
01113     for (size_t i = 0; i < rl.size(); ++i)
01114       rl[i] = a[rl[i]];
01115   }
01116 }
01117 
01118 unsigned long makeRepresentative(const gradings::Grading& gr,
01119                                  const rootdata::RootList& rl,
01120                                  const cartanclass::Fiber& fundf)
01121 /*!
01122   \brief Returns an element |x| (interpreted as element of the adjoint fiber
01123   of |fundf|) such that it grades the elements in |rl| according to |gr|.
01124 
01125   The successive bits of |gr| give the desired grading of the successive roots
01126   in |rl|. At least one solution for |x| should be known to exist. The roots
01127   in |rl| should probably be linearly independent, since linearly dependent
01128   roots would only make the existence of a solution less likely.
01129 */
01130 
01131 {
01132   using namespace bitset;
01133   using namespace cartanclass;
01134   using namespace latticetypes;
01135   using namespace gradings;
01136   using namespace rootdata;
01137 
01138   RootSet brs =
01139     fundf.noncompactRoots(0); // noncompact roots for the base grading
01140   Grading bgr =
01141     restrictGrading(brs,rl);    // view it as a grading of the roots of |rl|
01142   SmallBitVector bc(bgr,rl.size()); // transform into binary vector
01143 
01144   // make right hand side
01145   SmallBitVector rhs(gr,rl.size()); // view |gr| as binary vector (same length)
01146   rhs += bc;                        // and add the one for the base grading
01147 
01148   // make grading shifts
01149   SmallBitVectorList cl(fundf.adjointFiberRank(),bc);
01150   for (size_t j = 0; j < cl.size(); ++j) {
01151     Grading gr1 = restrictGrading(fundf.noncompactRoots(1 << j),rl);
01152     cl[j] += SmallBitVector(gr1,rl.size()); // cl[j] is shift for vector e[j]
01153   }
01154 
01155   // set up equations
01156   RankFlags x;
01157   firstSolution(x,cl,rhs);
01158 
01159   return x.to_ulong();
01160 }
01161 
01162 void transformGrading(gradings::Grading& gr,
01163                       const rootdata::RootList& rl,
01164                       const rootdata::RootList& so,
01165                       const rootdata::RootDatum& rd)
01166 
01167 /*!
01168   \brief Transforms the grading |gr| of |rl| according to |so|.
01169 
01170   Precondition: |gr| is a grading of the roots in |rl|; |so| is a set of
01171   strongly orthogonal roots, orthogonal to the roots in |rl|.
01172 
01173   Assume that all roots in |rl| and |so| are imaginary for some involution,
01174   and that a grading is given that matches |gr| on |rl|, and for which all
01175   roots of |so| are noncompact (grading 1). Then by Cayley-transforming though
01176   the roots of |so| (in any order, since they are strongly orthogonal) one
01177   gets an involution for which the roots in |rl| are still imaginary (those in
01178   |so| have become real), and a grading of those roots that possibly differs
01179   from |gr|; this function transforms the grading |gr| into that new grading.
01180 
01181   Formula: the rule for Cayley-transforming a grading through an imaginary
01182   noncompact root \f$\alpha\f$ in |so| is that the grading of \f$\beta\f$ in |rl| is
01183   flipped if and only if \f$\alpha+\beta\f$ is a root. So in all the grading of
01184   \f$\beta\f$ changes iff this condition is met for an odd number of \f$\alpha\f$s.
01185 */
01186 
01187 {
01188   for (size_t i = 0; i < rl.size(); ++i)
01189     for (size_t j = 0; j < so.size(); ++j)
01190       if (rd.sumIsRoot(rl[i],so[j]))
01191         gr.flip(i);
01192 }
01193 
01194 /*!
01195   \brief Checks whether |ti| decomposes as the composition of the cross-action
01196   defined by |ww| followed by the Cayley transform defined by |so|. Arguments
01197   |W| and |rd| are needed for the check; giving in addition |q| allows to
01198   check that Cayley transforms involve imaginary roots. This function is only
01199   used in an |assert| statement anyway.
01200 */
01201 bool checkDecomposition(const weyl::TwistedInvolution& ti,
01202                         const weyl::WeylWord& ww,
01203                         const rootdata::RootList& so,
01204                         const weyl::WeylGroup& W,
01205                         const rootdata::RootDatum& rd,
01206                         const latticetypes::LatticeMatrix& q)
01207 {
01208   using namespace rootdata;
01209   using namespace weyl;
01210 
01211   TwistedInvolution tw;
01212 
01213   // cross action part
01214   for (size_t j = 0; j < ww.size(); ++j)
01215     W.twistedConjugate(tw,ww[j]);
01216 
01217   // cayley transform part
01218   for (size_t j = 0; j < so.size(); ++j) {
01219     assert(isImaginary(rd.root(so[j]),tw,W,rd,q));
01220     W.leftMult(tw,rd.reflectionWord(so[j]));
01221   }
01222 
01223   return tw == ti;
01224 }
01225 
01226 } // namespace cartanset
01227 } // namespace atlas

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