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

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

Go to the documentation of this file.
00001 /*!
00002 \file
00003 \brief Implementation of the class KLContext.
00004 
00005   This module contains code for the computation of the Kazhdan-Lusztig
00006   polynomials for a given block of representations. We have taken the radical
00007   approach of not using the Bruhat ordering at all, just ordering by length
00008   instead, and coping with the ensuing appearance of zero polynomials. It
00009   is expected that the simplification thus achieved will more than outweigh
00010   the additional polynomials computed.
00011 
00012   The general scheme is fairly similar to the one in Coxeter: there is a
00013   "KLSupport" structure, that holds the list of primitive pairs that makes it
00014   possible to read the d_kl list, plus some additional lists that allow for
00015   a fast primitivization algorithm, for instance; there are two main lists,
00016   d_kl (filled in for all primitive pairs), and d_mu (filled in only for
00017   non-zero mu coefficients.)
00018 */
00019 /*
00020   This is kl.cpp
00021 
00022   Copyright (C) 2004,2005 Fokko du Cloux
00023   part of the Atlas of Reductive Lie Groups
00024 
00025   See file main.cpp for full copyright notice
00026 */
00027 
00028 #include "kl.h"
00029 
00030 #ifdef VERBOSE
00031 #include <iostream>
00032 #include <fstream>
00033 #include <ctime>
00034 #include <sstream>
00035 #include <string>
00036 #endif
00037 
00038 #include <cassert>
00039 #include <map>
00040 #include <stack>
00041 #include <stdexcept>
00042 
00043 #include "bitmap.h"
00044 #include "basic_io.h"
00045 #include "blocks.h"
00046 #include "error.h"
00047 #include "hashtable.h"
00048 #include "kl_error.h"
00049 #include "prettyprint.h"
00050 
00051 /*
00052   [Fokko's original description, which referred to a slighly older
00053   version of the computation. Fokko implemented the change from using
00054   extremal pairs to the slightly large set of primitive pairs, but did
00055   not change all of the code comments. I am trying to do that now. DV
00056   8/26/06.]
00057 
00058   This module contains code for the computation of the Kazhdan-Lusztig
00059   polynomials for a given block of representations. We have taken the radical
00060   approach of not using the Bruhat ordering at all, just ordering by length
00061   instead, and coping with the ensuing appearance of zero polynomials. It
00062   is expected that the simplification thus achieved will more than outweigh
00063   the additional polynomials computed.
00064 
00065   The general scheme is fairly similar to the one in Coxeter: there is a
00066   "KLSupport" structure, that holds the list of extremal pairs that makes it
00067   possible to read the d_kl list, plus some additional lists that allow for
00068   a fast extremalization algorithm, for instance; there are two main lists,
00069   d_kl (filled in for all extremal pairs), and d_mu (filled in only for
00070   non-zero mu coefficients.)
00071 */
00072 
00073 namespace atlas {
00074 
00075   namespace kl {
00076 // we wrap |KLPol| into a class |KLPolEntry| that can be used in a |HashTable|
00077 
00078 /* This associates the type |KLStore| as underlying storage type to |KLPol|,
00079    and adds the methods |hashCode| (hash function) and |!=| (unequality), for
00080    use by the |HashTable| template.
00081  */
00082 class KLPolEntry : public KLPol
00083   {
00084   public:
00085     // constructors
00086     KLPolEntry() : KLPol() {} // default constructor builds zero polynomial
00087     KLPolEntry(const KLPol& p) : KLPol(p) {} // lift polynomial to this class
00088 
00089     // members required for an Entry parameter to the HashTable template
00090     typedef KLStore Pooltype;              // associated storage type
00091     size_t hashCode(size_t modulus) const; // hash function
00092 
00093     // compare polynomial with one from storage
00094     bool operator!=(Pooltype::const_reference e) const;
00095 
00096   };
00097 
00098 
00099   namespace helper {
00100 
00101   using namespace kl;
00102 
00103   size_t firstAscent(const descents::DescentStatus&,
00104                      const descents::DescentStatus&, size_t);
00105 
00106   size_t goodAscent(const descents::DescentStatus&,
00107                     const descents::DescentStatus&, size_t);
00108 
00109   class Thicket;
00110 
00111 
00112   typedef hashtable::HashTable<KLPolEntry,KLIndex> KLHashStore;
00113 
00114   class Helper
00115   : public KLContext
00116   {
00117 
00118     friend class Thicket;
00119 
00120     KLHashStore d_hashtable;
00121 
00122   // Members serving for statistics
00123 
00124     size_t prim_size;            // number of pairs stored in d_prim
00125     size_t nr_of_prim_nulls;     // number of zeroes suppressed from d_prim
00126 
00127   public:
00128 
00129     // constructors and destructors
00130     Helper(const KLContext&);
00131 
00132     ~Helper()
00133     {
00134 #ifdef VERBOSE
00135       std::cout << "\nNumber of primitive pairs stored:     "
00136                 << prim_size << ".\n";
00137       std::cout << "Number of unrecorded primitive pairs: "
00138                 << nr_of_prim_nulls << '.' << std::endl;
00139 #endif
00140     }
00141 
00142     //accessors
00143 
00144     /*!
00145  \brief Cayley transform of block element y through simple root s.
00146     */
00147     blocks::BlockEltPair cayley(size_t s, BlockElt y) const {
00148       return d_support->block().cayley(s,y);
00149     }
00150 
00151     /*!
00152  \brief Cross action of simple root s on block element y.
00153     */
00154     BlockElt cross(size_t s, BlockElt y) const {
00155       return d_support->block().cross(s,y);
00156     }
00157 
00158     /*!
00159  \brief Returns vector of RANK_MAX unsigned char; entry s gives
00160  descent status of simple root s for block element y.
00161     */
00162     const descents::DescentStatus& descent(BlockElt y) const {
00163       return d_support->block().descent(y);
00164     }
00165 
00166     /*!
00167 \brief Unsigned char whose value gives the descent status of
00168 simple root s for block element y.
00169     */
00170     descents::DescentStatus::Value descentValue(size_t s, BlockElt y) const {
00171       return d_support->descentValue(s,y);
00172     }
00173 
00174     size_t firstDirectRecursion(BlockElt y) const;
00175 
00176     blocks::BlockEltPair inverseCayley(size_t s, BlockElt y) const {
00177       return d_support->block().inverseCayley(s,y);
00178     }
00179 
00180     /* Declare that member function klPol from base class KLContext is also
00181        considered. This is necessary since it would otherwise be shadowed
00182        rather than overloaded by a new definition with different signature
00183        in the Helper class.
00184     */
00185     using KLContext::klPol;
00186 
00187     KLPolRef klPol(BlockElt x, BlockElt y, KLRow::const_iterator klv,
00188                    klsupport::PrimitiveRow::const_iterator p_begin,
00189                    klsupport::PrimitiveRow::const_iterator p_end) const;
00190 
00191     inline bool ascentMu(BlockElt x, BlockElt y, size_t s) const;
00192 
00193     inline MuCoeff goodDescentMu(BlockElt x, BlockElt y, size_t s) const;
00194 
00195     MuCoeff lengthOneMu(BlockElt x, BlockElt y) const;
00196 
00197     /*!
00198 \brief First coordinate (corresponding to K orbit on G/B) of pair of
00199 integers specifying block element y.
00200     */
00201     size_t orbit(BlockElt y) const {
00202       return d_support->block().x(y);
00203     }
00204     /*!
00205 \brief Second coordinate (corresponding to K^vee orbit on G^vee/B^vee)
00206 of pair of integers specifying block element y.
00207     */
00208     size_t dualOrbit(BlockElt y) const {
00209       return d_support->block().y(y);
00210     }
00211 
00212     MuCoeff type2Mu(BlockElt x, BlockElt y) const;
00213 
00214     // manipulators
00215     void completePacket(BlockElt y);
00216 
00217     void directRecursion(BlockElt y, size_t s);
00218 
00219     void fill();
00220 
00221     void fillKLRow(BlockElt y);
00222 
00223     void fillMuRow(BlockElt y);
00224 
00225     void fillThickets(BlockElt y);
00226 
00227     void muCorrection(std::vector<KLPol>& klv,
00228                       const klsupport::PrimitiveRow& e,
00229                       BlockElt y, size_t s);
00230 
00231     void recursionRow(std::vector<KLPol> & klv,
00232                       const klsupport::PrimitiveRow& e, BlockElt y, size_t s);
00233 
00234     void writeRow(const std::vector<KLPol>& klv,
00235                   const klsupport::PrimitiveRow& e, BlockElt y);
00236   }; // class Helper
00237 
00238 
00239 
00240 
00241     // class Thicket
00242 
00243     /*!
00244 \brief Collection of block elements y_j of the same length, differing
00245 by type II real cross actions, and having no other descents.
00246 
00247 A pair (y_j, s x y_j) (with s type II real) is an Edge of the
00248 thicket. Such an s is a descent for both y_j and s x y_j.  The pair is
00249 the image of the Cayley transform (type II imaginary) of a single
00250 element y_0, of length one less.  The first class of KL recursion
00251 relations used in a Thicket is this:
00252 
00253 P_{x,y_j} + P_{x,s x y_j} = [formula involving various P_{? , y_0}].
00254 
00255 The right hand side terms here are known by induction on y, and recorded in
00256 the recursion data member of the Edge. We can therefore compute P_{x,y} as
00257 soon as we know P_{x,y'} for a single element y' in the thicket. For that
00258 (given x) we find essentially three possibilities:
00259 
00260 1) x is equal to y', so P_{x,y'} = 1.
00261 
00262 2) There is an s that is a good ascent for x (not in tau(x), and
00263 leading to an x' of length one more than the length of x), but is type
00264 II real for y'.  In this case there is a recursion formula something
00265 like
00266 
00267 P_{x,y'} = P_{x' , y'}.
00268 
00269 (If s is type II imaginary for x, then there are two terms on the
00270 right.)  In any case the right side is known by downward induction on
00271 x, so finally we know all P_{x,y_j} for y_j in the Thicket.
00272 
00273 3) P_{x,y'} = 0.
00274 
00275 This computation is carried out in the member function fill().
00276     '*/
00277 
00278 class Thicket {
00279 
00280   public:
00281 
00282     struct Edge;
00283     typedef std::vector<Edge> EdgeList;
00284 
00285   private:
00286 
00287     typedef klsupport::PrimitiveRow::iterator PI;
00288     typedef KLRow::iterator KLI;
00289 
00290     /*!
00291 \brief List of elements y_j in Thicket.
00292     */
00293     std::vector<BlockElt> d_vertices;
00294 
00295     /*!
00296 \brief Entry j lists the edges ending at y_j.
00297     */
00298     std::vector<EdgeList> d_edges;
00299 
00300     /*!
00301 \brief List of all x that are extremal with respect to some y in Thicket.
00302     */
00303     std::vector<BlockElt> d_xlist;
00304 
00305     /*!
00306 \brief Entry j lists all x of length strictly less than l(y) that are
00307 extremal with respect to y_j.
00308 
00309 Extremal means that each descent for y_j is a descent for x.
00310     */
00311     std::vector<klsupport::PrimitiveRow> d_extr;
00312 
00313     /*!
00314 \brief Entry j lists all x of length strictly less than l(y) that are
00315 primitive with respect to y_j.
00316 
00317 Primitive means that each descent for y_j is either a descent for x or
00318 type II imaginary for x.
00319     */
00320     std::vector<klsupport::PrimitiveRow> d_prim;
00321     std::vector<KLRow> d_klr;
00322     std::vector<PI> d_firstPrim;
00323     std::vector<KLI> d_firstKL;
00324     Helper* d_helper;
00325 
00326   public:
00327 
00328     // constructors and destructors
00329     Thicket() {}
00330 
00331     Thicket(Helper&, BlockElt);
00332 
00333     ~Thicket() {}
00334 
00335     // accessors
00336 
00337     /*!
00338 \brief Cross action of simple reflection s on block element y.
00339     */
00340     BlockElt cross(size_t s, BlockElt y) const {
00341       return d_helper->cross(s,y);
00342     }
00343 
00344     /*!
00345 \brief List of RankMax unsigned chars; number s gives the descent
00346 status 0-7 of simple root s for y.
00347     */
00348     const descents::DescentStatus& descent(BlockElt y) const {
00349       return d_helper->descent(y);
00350     }
00351 
00352 
00353     /*!
00354 \brief Unsigned char between 0 and 7; gives the descent of
00355 simple root s for y.
00356     */
00357     descents::DescentStatus::Value descentValue(size_t s, BlockElt y) const {
00358       return d_helper->descentValue(s,y);
00359     }
00360 
00361     /*!
00362 \brief List of |Edge|s ending at y_j.
00363     */
00364     const EdgeList& edgeList(size_t j) const {
00365       return d_edges[j];
00366     }
00367 
00368     /*!
00369 \brief KL polynomial P_{x,y_pos}, for any y_pos in Thicket.
00370     */
00371     KLPolRef klPol(BlockElt x, size_t pos) const {
00372       return d_helper->klPol(x,d_vertices[pos],d_firstKL[pos],d_firstPrim[pos],
00373                              d_prim[pos].end());
00374     }
00375 
00376     /*!
00377 \brief List of all x of length strictly less than l(y) that are
00378 primitive with respect to y_j.
00379 
00380 Primitive means that each descent for y_j is either a descent for x or
00381 type II imaginary for x.
00382     */
00383     const klsupport::PrimitiveRow& primitiveRow(size_t j) const {
00384       return d_prim[j];
00385     }
00386 
00387     size_t nonExtremal(BlockElt x) const;
00388 
00389     /*!
00390 \brief Pointer to the KL polynomial one.
00391     */
00392     KLIndex one() const {
00393       return d_helper->d_one;
00394     }
00395 
00396     /*!
00397 \brief Semisimple rank.
00398     */
00399     size_t rank() const {
00400       return d_helper->rank();
00401     }
00402 
00403     /*!
00404 \brief Number of vertices in Thicket.
00405     */
00406     size_t size() const {
00407       return d_vertices.size();
00408     }
00409 
00410     /*!
00411 \brief List of vertices in Thicket.
00412     */
00413     const std::vector<BlockElt>& vertices() const {
00414       return d_vertices;
00415     }
00416 
00417     /*!
00418 \brief Pointer to the KL polynomial zero.
00419     */
00420     KLIndex zero() const {
00421       return d_helper->d_zero;
00422     }
00423 
00424     // manipulators
00425     bool ascentCompute(BlockElt x, size_t pos);
00426 
00427     void edgeCompute(BlockElt x, size_t pos, const Edge& e);
00428 
00429     void fill();
00430 
00431     void fillXList();
00432 
00433     KLRow& klRow(BlockElt y) {
00434       return d_helper->d_kl[y];
00435     }
00436 
00437     KLStore& store() {
00438       return d_helper->d_store;
00439     }
00440 
00441 }; // class Thicket
00442 
00443     /*!
00444 \brief Pair (y , s x y) (with s type II real) in a Thicket.
00445 
00446     */
00447 struct Thicket::Edge {
00448 
00449     /*!
00450 \brief Index in d_vertices of the block element at which the edge begins.
00451     */
00452     size_t source;
00453 
00454     /*!
00455 \brief Index in d_vertices of the block element at which the edge ends.
00456     */
00457     size_t y;
00458 
00459     /*!
00460 \brief Number of a simple root s, assumed to be type II real for y.
00461     */
00462     size_t s;
00463 
00464     /*!
00465 \brief List of formulas for P_{x_i,y} + P_{x_i,source}, for i in a
00466 list of elements primitive with respect to some y' in the Thicket.
00467     */
00468     std::vector<KLPol> recursion;
00469     // constructors and destructors
00470     Edge() {}
00471     Edge(BlockElt x, BlockElt y, size_t s, const std::vector<KLPol>& r)
00472       :source(x), y(y), s(s), recursion(r) {}
00473 }; // struct Thicket::Edge
00474 
00475 class ThicketIterator {
00476 
00477   private:
00478     typedef Thicket::EdgeList EdgeList;
00479 
00480     std::stack<size_t> d_stack;
00481     bitmap::BitMap d_done;
00482     EdgeList::const_iterator d_current;
00483     EdgeList::const_iterator d_currentEnd;
00484     size_t d_pos;
00485 
00486     const Thicket* d_thicket;
00487 
00488   public:
00489 
00490     // constructors and destructors
00491     ThicketIterator(const Thicket&, size_t);
00492 
00493     // accessors
00494     bool operator() () const {
00495       return not d_stack.empty();
00496     }
00497 
00498     size_t operator* () const { // current vertex index, or size() at end
00499       return d_pos;
00500     }
00501 
00502     const Thicket::Edge& edge() const { // current edge
00503       return *d_current;
00504     }
00505 
00506     // manipulators
00507     ThicketIterator& operator++();
00508 
00509 }; // class ThicketIterator
00510 
00511 } // namespace helper
00512 } // namespace kl
00513 
00514 /*****************************************************************************
00515 
00516         Chapter I -- Methods of the KLContext and KLPolEntry classes.
00517 
00518  *****************************************************************************/
00519 
00520 /* methods of KLContext */
00521 
00522 
00523 namespace kl {
00524   using namespace atlas::kl::helper;
00525 
00526 KLContext::KLContext(klsupport::KLSupport& kls)
00527   :d_state(),
00528    d_support(&kls),
00529    d_prim(),
00530    d_kl(),
00531    d_mu(),
00532    d_store(2),
00533    d_zero(0),
00534    d_one(1)
00535 {
00536   d_store[d_zero]=Zero;
00537   d_store[d_one]=One;
00538 }
00539 
00540 /******** copy, assignment and swap ******************************************/
00541 
00542 
00543 /*!
00544   \brief Copy constructor.
00545 
00546   Since we use indices instead of iterators, nothing gets invalidated any more
00547 */
00548 KLContext::KLContext(const KLContext& other)
00549   :d_state(other.d_state),
00550    d_support(other.d_support),
00551    d_prim(other.d_prim),
00552    d_kl(other.d_kl),
00553    d_mu(other.d_mu),
00554    d_store(other.d_store),
00555    d_zero(other.d_zero),
00556    d_one(other.d_one)
00557 {}
00558 
00559 
00560 /*!
00561   \brief Assignment operator.
00562 
00563   Use copy constructor. This requires a check for self-assignment, or the
00564   source would be destroyed!
00565 */
00566 KLContext& KLContext::operator= (const KLContext& other)
00567 {
00568   // handle self-assignment
00569   if (&other != this) {
00570     this->~KLContext();
00571     new(this) KLContext(other);
00572   }
00573 
00574   return *this;
00575 }
00576 
00577 void KLContext::swap(KLContext& other)
00578 {
00579   d_state.swap(other.d_state);
00580 
00581   std::swap(d_support,other.d_support);
00582 
00583   d_prim.swap(other.d_prim);
00584 
00585   d_kl.swap(other.d_kl);
00586   d_mu.swap(other.d_mu);
00587 
00588   d_store.swap(other.d_store);  // this puts the Helper store into base object
00589   std::swap(d_zero,other.d_zero);
00590   std::swap(d_one,other.d_one);
00591 }
00592 
00593 /******** accessors **********************************************************/
00594 
00595 
00596 /*!
00597   \brief Returns the Kazhdan-Lusztig-Vogan polynomial P_{x,y}
00598 
00599   Precondition: x and y are smaller than size();
00600 
00601   Explanation: since d_store holds all polynomials for primitive
00602   pairs (x,y), this is basically a lookup function. While x is not
00603   primitive w.r.t. y, it moves x up, using the "easy" induction
00604   relations. At that point, we look x up in the primitive list for
00605   y. If it is found, we get a pointer to the result.  If it is not
00606   found, the polynomial is zero.
00607 */
00608 KLPolRef KLContext::klPol(BlockElt x, BlockElt y) const
00609 {
00610   using namespace klsupport;
00611 
00612   const PrimitiveRow& pr = d_prim[y];
00613   const KLRow& klr = d_kl[y];
00614 
00615   x=d_support->primitivize(x,descentSet(y));
00616   if (x>y) return Zero; // includes case x==blocks::UndefBlock
00617   PrimitiveRow::const_iterator xptr = std::lower_bound(pr.begin(),pr.end(),x);
00618   if (xptr == pr.end() or *xptr != x) // not found
00619     return Zero;
00620   return d_store[klr[xptr - pr.begin()]];
00621 }
00622 
00623 
00624 /*!
00625   \brief Returns mu(x,y).
00626 
00627   Explanation: it is guaranteed that all the x'es such that mu(x,y) != 0
00628   occur in d_mu[y] (and in fact, that only those occur.) So it is a simple
00629   matter of looking up x.
00630 */
00631 MuCoeff KLContext::mu(BlockElt x, BlockElt y) const
00632 {
00633   const MuRow& mr = d_mu[y];
00634 
00635   std::vector<BlockElt>::const_iterator xloc=
00636     std::lower_bound(mr.first.begin(),mr.first.end(),x);
00637 
00638   if (xloc==mr.first.end() or *xloc!=x)
00639     return 0; // x not found in mr
00640 
00641   return mr.second[xloc-mr.first.begin()];
00642 }
00643 
00644 /* The following two methods were moved here form the Helper class, since
00645    they turn out to be useful even when no longer constructing the KLContext
00646 */
00647 
00648 /*!
00649   \brief Puts in e the list of all x extremal w.r.t. y.
00650 
00651   Explanation: this means that either x = y, or length(x) < length(y),
00652   and every descent for y is a descent for x.
00653 */
00654 void KLContext::makeExtremalRow(klsupport::PrimitiveRow& e, BlockElt y) const
00655 {
00656   using namespace bitmap;
00657 
00658   BitMap b(size());
00659   size_t c = lengthLess(length(y));
00660 
00661   b.fill(c);     // start with all elements < y in length
00662   b.insert(y);   // and y itself
00663 
00664   // extremalize (filter out those that are not extremal)
00665   d_support->extremalize(b,descentSet(y));
00666 
00667   // copy from bitset b to list e
00668   e.reserve(e.size()+b.size()); // ensure tight fit after copy
00669   std::copy(b.begin(),b.end(),back_inserter(e));
00670 
00671 }
00672 
00673 
00674 /*!
00675   \brief Puts in e the list of all x primitive w.r.t. y.
00676 
00677   Explanation: this means that either x = y, or length(x) < length(y),
00678   and every descent for y is either a descent, or an imaginary type II
00679   ascent for x.
00680 */
00681 void KLContext::makePrimitiveRow(klsupport::PrimitiveRow& e, BlockElt y) const
00682 {
00683   using namespace bitmap;
00684 
00685   BitMap b(size());
00686   size_t c = lengthLess(length(y));
00687 
00688   b.fill(c);     // start with all elements < y in length
00689   b.insert(y);   // and y itself
00690 
00691   // primitivize (filter out those that are not primitive)
00692   d_support->primitivize(b,descentSet(y));
00693   // copy to list
00694   e.reserve(e.size()+b.size()); // ensure tight fit after copy
00695   std::copy(b.begin(),b.end(),back_inserter(e));
00696 
00697 }
00698 
00699 
00700 /******** manipulators *******************************************************/
00701 
00702 /*!
00703   \brief Fills the KL- and mu-lists.
00704 
00705   Explanation: this is the main function in this module; all the work is
00706   deferred to the Helper class.
00707 */
00708 void KLContext::fill()
00709 {
00710 #ifdef VERBOSE
00711   std::cerr << "computing kazhdan-lusztig polynomials ..." << std::endl;
00712 #endif
00713 
00714   if (d_state.test(KLFilled))
00715     return;
00716 
00717   try
00718   {
00719     Helper help(*this);
00720 
00721     help.fill();
00722     swap(help); // swaps the base object, including the d_store
00723 
00724     d_state.set(KLFilled);
00725 
00726 #ifdef VERBOSE
00727     std::cerr << "done" << std::endl;
00728 #endif
00729   }
00730   catch (std::bad_alloc) { // transform failed allocation into MemoryOverflow
00731     std::cerr << "\n memory full, KL computation abondoned." << std::endl;
00732     throw error::MemoryOverflow();
00733   }
00734 
00735 }
00736 
00737 bitmap::BitMap KLContext::primMap (BlockElt y) const
00738 {
00739   bitmap::BitMap b(size()); // block-size bitmap
00740 
00741   // start with all elements < y in length
00742   b.fill(lengthLess(length(y)));
00743   b.insert(y);   // and y itself
00744 
00745   // primitivize (filter out those that are not primitive)
00746   d_support->primitivize(b,descentSet(y));
00747 
00748   // now b holds a bitmap indicating primitive elements for y
00749 
00750   // our result will be a bitmap of that size
00751   bitmap::BitMap result (b.size()); // initiallly all bits are cleared
00752 
00753  // the list of primitive elements with nonzero polynomials at y
00754   const klsupport::PrimitiveRow& row=d_prim[y];
00755 
00756   // traverse b, and for its elements that occur in row[i], set bits in result
00757 
00758   size_t position=0; // position among set bits in b (avoids using b.position)
00759   size_t j=0; // index into row;
00760   for (bitmap::BitMap::iterator i=b.begin(); i(); ++position,++i)
00761     if (*i==row[j]) // look if i points to current element of row
00762     {
00763       result.insert(position); ++j; // record position and advance in row
00764       if (j==row.size()) break; // stop when row is exhausted
00765     }
00766 
00767   return result;
00768 }
00769 
00770 
00771 /* methods of KLPolEntry */
00772 
00773 
00774 /*!
00775   \brief calculate a hash value in [0,modulus[, where modulus is a power of 2
00776 
00777   The function is in fact evaluation of the polynomial (with coefficients
00778   interpreted in Z) at the point 2^21+2^13+2^8+2^5+1=2105633, which can be
00779   calculated quickly (without multiplications) and which gives a good spread
00780   (which is not the case if 2105633 is replaced by a small number, because
00781   the evaluation values will not grow fast enough for low degree
00782   polynomials!).
00783 
00784 */
00785 inline size_t KLPolEntry::hashCode(size_t modulus) const
00786 { const polynomials::Polynomial<KLCoeff>& P=*this;
00787   if (P.isZero()) return 0;
00788   polynomials::Degree i=P.degree();
00789   size_t h=P[i]; // start with leading coefficient
00790   while (i-->0) h= ((h<<21)+(h<<13)+(h<<8)+(h<<5)+h+P[i]) & (modulus-1);
00791   return h;
00792 }
00793 
00794 bool KLPolEntry::operator!=(KLPolEntry::Pooltype::const_reference e) const
00795 {
00796   if (degree()!=e.degree()) return true;
00797   if (isZero()) return false; // since degrees match
00798   for (polynomials::Degree i=0; i<=degree(); ++i)
00799     if ((*this)[i]!=e[i]) return true;
00800   return false; // no difference found
00801 }
00802 
00803 } // namespace kl
00804 
00805 
00806 /*****************************************************************************
00807 
00808         Chapter II -- Methods of the Helper class.
00809 
00810  *****************************************************************************/
00811 
00812 namespace kl {
00813   namespace helper {
00814 
00815     // main constructor
00816 
00817 Helper::Helper(const KLContext& kl)
00818   : KLContext(kl)
00819   , d_hashtable(d_store) // hash table refers to our base object's d_store
00820   , prim_size(0), nr_of_prim_nulls(0)
00821 {}
00822 
00823 /******** accessors **********************************************************/
00824 
00825 
00826 /*!
00827   \brief Returns the first descent generator that is not real type II
00828 
00829   Explanation: those are the ones that give a direct recursion formula for
00830   the K-L basis element.
00831 */
00832 size_t Helper::firstDirectRecursion(BlockElt y) const
00833 {
00834   using namespace descents;
00835 
00836   const descents::DescentStatus& d = descent(y);
00837 
00838   for (size_t s = 0; s < rank(); ++s) {
00839     DescentStatus::Value v = d[s];
00840     if (DescentStatus::isDirectRecursion(v))
00841       return s;
00842   }
00843 
00844   return rank();
00845 }
00846 
00847 
00848 /*!
00849   \brief Returns the Kazhdan-Lusztig polynomial for x corresponding to
00850   the given row.
00851 
00852   Precondition: |klv| holds the tail of the set of primitive Kazhdan-Lusztig
00853   polynomials for |y|, enough to find the required one by elementary lookup;
00854   |[p_begin,p_end[| is the corresponding range of primitive elements.
00855 
00856   Algorithm: primitivize |x| with respect to the descents in |y|; if a real
00857   nonparity situation is encountered, return |Zero|; otherwise look up the
00858   primitive |x| in the range and return the corresponding element from |klv|
00859 */
00860 KLPolRef Helper::klPol(BlockElt x, BlockElt y,
00861                        KLRow::const_iterator klv,
00862                        klsupport::PrimitiveRow::const_iterator p_begin,
00863                        klsupport::PrimitiveRow::const_iterator p_end) const
00864 {
00865   BlockElt xp = d_support->primitivize(x,descentSet(y));
00866 
00867   if (xp>y) return Zero; // includes case |xp==blocks::UndefBlock|
00868   klsupport::PrimitiveRow::const_iterator xptr =
00869     std::lower_bound(p_begin,p_end,xp);
00870   if (xptr == p_end or *xptr != xp) return Zero;
00871   return d_store[klv[xptr-p_begin]];
00872 }
00873 
00874 
00875 /*!
00876   \brief Computes whether |mu(x,y)==1| in a good ascent situation
00877 
00878   Preconditions: $l(y)>0$; $l(x)=l(y)-1$; $s$ is an ascent for $x$ w.r.t. $y$
00879 
00880   Explanation: this is the situation where |mu(x,y)| is directly expressible.
00881   The point is that |x| will ascend to an element of the same length as |y|,
00882   so that the corresponding K-L polynomial is zero unless |x| ascends to |y|.
00883 */
00884 inline bool Helper::ascentMu(BlockElt x, BlockElt y, size_t s) const
00885 {
00886   using namespace blocks;
00887   using namespace descents;
00888 
00889   switch (descentValue(s,x)) {
00890   case DescentStatus::ComplexAscent:
00891     return cross(s,x) == y;
00892   case DescentStatus::RealNonparity:
00893     return false;
00894   case DescentStatus::ImaginaryTypeI:
00895     return cayley(s,x).first == y;
00896   case DescentStatus::ImaginaryTypeII:
00897     {
00898       BlockEltPair x1 = cayley(s,x);
00899       // mu(x,y) = mu(x1.first,y) + mu(x1.second,y)
00900       return x1.first == y or x1.second == y;
00901     }
00902   default: // this cannot happen
00903     assert(false);
00904     return false; // keep compiler happy
00905   }
00906 }
00907 
00908 
00909 /*!
00910   \brief Gets |mu(x,y)| by a good descent recursion.
00911 
00912   Precondition: $l(y)>0$; $l(x)=l(y)-1$; all previous mu-rows have been filled
00913   in; |s| is a good descent for |y|;
00914 
00915   Explanation: a good descent for |y| is a descent that is neither real type
00916   II nor imaginary compact (so it is either a complex or real type I); these
00917   are the cases where |mu(x,y)| is directly expressed by recursion.
00918 */
00919 inline MuCoeff Helper::goodDescentMu(BlockElt x, BlockElt y, size_t s) const
00920 {
00921   using namespace descents;
00922 
00923   blocks::BlockElt y1;
00924 
00925   if (descentValue(s,y) == DescentStatus::ComplexDescent)
00926     y1 = cross(s,y);
00927   else // s is real type I for y, chooise one of double-valued inverse Cayley
00928     y1 = inverseCayley(s,y).first;
00929 
00930   switch (descentValue(s,x))
00931   {
00932   case DescentStatus::ImaginaryCompact:
00933     return MuCoeff(0);
00934   case DescentStatus::ComplexDescent:
00935       return mu(cross(s,x),y1);
00936   case DescentStatus::RealTypeI:
00937     {
00938       blocks::BlockEltPair x1 = inverseCayley(s,x);
00939       return mu(x1.first,y1)+mu(x1.second,y1);
00940     }
00941   case DescentStatus::RealTypeII:
00942     return mu(inverseCayley(s,x).first,y1);
00943 
00944   default: // this cannot happen
00945     assert(false);
00946     return MuCoeff(0); // keep compiler happy
00947   }
00948 }
00949 
00950 
00951 /*!
00952   \brief Computes $\mu(x,y)$ in the special case that $l(y)-l(x) = 1$.
00953 
00954   Preconditions: $l(y) > 0$; $l(x) = l(y)-1$; the $\mu$-rows for all $y$
00955   of smaller lengths have already been filled in.
00956 
00957   Explanation: these are the $\mu$-values that can come up in possibly
00958   non-extremal situations. The value can be obtaind simply as the constant
00959   term of |klPol(x,y)|, but for efficiency reasons we handle some easy cases
00960   directly, avoiding the cost of calling |klPol|. In fact in all the cases
00961   these values of $\mu$ can be, and used to be, computed recursively by
00962   formulas using only other $\mu$-values of the same kind.
00963 */
00964 MuCoeff Helper::lengthOneMu(BlockElt x, BlockElt y) const
00965 {
00966   // look if x has any ascents that are descents for y
00967   bitset::RankFlags ascents=descentSet(y); ascents.andnot(descentSet(x));
00968   if (ascents.any())
00969     return ascentMu(x,y,ascents.firstBit()) ? MuCoeff(1) : MuCoeff(0);
00970 
00971   /* Doing the following case separately costs more time than it gains
00972 
00973   // if we get here, x is extremal w.r.t. y
00974   s = firstDirectRecursion(y);
00975   if (s != rank()) // the answer is another $\mu$
00976     return goodDescentMu(x,y,s);
00977   */
00978 
00979   // Now that the easy cases are gone, just lookup the KL polynomial
00980   KLPolRef p=klPol(x,y);
00981   return p.isZero() ? MuCoeff(0) : p[0];
00982 
00983   // the final case used to be: return type2Mu(x,y);
00984 
00985 }
00986 
00987 
00988 /*!
00989   \brief Gets mu(x,y) by type II recursion.
00990 
00991   This code is currently unused (see lengthOneMu above).
00992 
00993   Precondition: length(y) > 0; length(x) = length(y)-1; all previous
00994   mu-rows have been filled in; x is extremal w.r.t. y, and all descents
00995   of y are real type II;
00996 
00997   Explanation: in this situation, we have recursion formulas that will
00998   yield mu(x,y)+mu(x,s.y). It is known that proceeding in this way we must
00999   end up with a y' for which x is not extremal.
01000 
01001   Algorithm: we keep a stack of recursion formulas of the above kind, walking
01002   through the orbit of y under the simple descents, until we reach a y
01003   that (a) has a non-type-II descent, or (b) for which x is non-extremal.
01004 */
01005 MuCoeff Helper::type2Mu(BlockElt x, BlockElt y) const
01006 {
01007   using namespace descents;
01008 
01009   std::map<BlockElt,size_t> rel;
01010   std::stack<BlockElt> toDo;
01011 
01012   rel.insert(std::make_pair(y,rank()));
01013   toDo.push(y);
01014 
01015   size_t s;
01016   BlockElt y1 = y;
01017   MuCoeff mu = 0;
01018 
01019   while (not toDo.empty()) {
01020     y1 = toDo.top();
01021     toDo.pop();
01022     if (y1 < y) { // mu(x,y1) can be gotten recursively
01023       mu = KLContext::mu(x,y1);
01024       goto unwind;
01025     }
01026     s = firstAscent(descent(x),descent(y1),rank());
01027     if (s != rank()) { // done
01028       mu = ascentMu(x,y1,s);
01029       goto unwind;
01030     }
01031     for (s = 0; s < rank(); ++s) {
01032       DescentStatus::Value v = descentValue(s,y1);
01033       if (not DescentStatus::isDescent(v))
01034         continue;
01035       if (DescentStatus::isDirectRecursion(v)) {
01036         mu = goodDescentMu(x,y1,s);
01037         goto unwind;
01038       }
01039       // at this point s is either real type II or imaginary compact
01040       if (v == DescentStatus::ImaginaryCompact)
01041         continue;
01042       // at this point, there is no hope to resolve the situation at y1
01043       {
01044         BlockElt y2 = cross(s,y1);
01045         if (rel.insert(std::make_pair(y2,s)).second) // new element
01046           toDo.push(y2);
01047       }
01048     }
01049   }
01050 
01051  unwind:
01052   while (y1 != y) {
01053     std::map<BlockElt,size_t>::iterator i = rel.find(y1);
01054     s = i->second;
01055     y1 = cross(s,y1);
01056     // goodDescent() is mu + mu(x,y2)
01057     mu = goodDescentMu(x,y1,s) - mu;
01058   }
01059 
01060   return mu;
01061 }
01062 
01063 /******** manipulators *******************************************************/
01064 
01065 /*!
01066   \brief Finishes the filling of the R-packet starting at y.
01067 
01068   Precondition: all the rows in the packet capable of a direct recursion
01069   are filled; at least one row is of this form;
01070 
01071   Explanation: what we do here, is completing the rows that can be completed
01072   from the already filled ones, using real type II recursions. Whatever is left
01073   will constitute "thickets", and will be dealt with by another function.
01074 
01075   Algorithm: we traverse the set of y1 in the packet that can be obtained from
01076   one of the filled ones through real type II cross-actions.
01077 */
01078 void Helper::completePacket(BlockElt y)
01079 {
01080   using namespace descents;
01081   using namespace klsupport;
01082 
01083   std::pair<blocks::BlockElt,blocks::BlockElt> packet = block().R_packet(y);
01084   assert (packet.first==y);
01085   std::stack<BlockElt> filled;
01086   std::set<BlockElt> empty;
01087 
01088   for (BlockElt y1 = packet.first; y1<packet.second; ++y1) {
01089     if (d_kl[y1].size() != 0)
01090       filled.push(y1);
01091     else
01092       empty.insert(y1);
01093   }
01094 
01095   while (not filled.empty()) {
01096 
01097     BlockElt y1 = filled.top();
01098     filled.pop();
01099 
01100     for (size_t s = 0; s < rank(); ++s) {
01101      if (descentValue(s,y1) != DescentStatus::RealTypeII)
01102         continue;
01103       BlockElt y2 = cross(s,y1);
01104       std::set<BlockElt>::iterator i = empty.find(y2);
01105       if (i != empty.end()) { // found a new row
01106         // fill row y2
01107         std::vector<KLPol> klv;
01108         PrimitiveRow e;
01109         makeExtremalRow(e,y2);
01110         recursionRow(klv,e,y2,s);
01111         // klv[j] is P_{x,y2}+P_{x,y1}, for x = e[j]
01112         for (size_t j = 0; j < klv.size(); ++j) {
01113           BlockElt x = e[j];
01114           try {
01115             klv[j].safeSubtract(klPol(x,y1));
01116           }
01117           catch (error::NumericUnderflow& e){
01118             throw kl_error::KLError(x,y1,__LINE__,
01119                                     static_cast<const KLContext&>(*this));
01120           }
01121         }
01122         // write out row
01123         writeRow(klv,e,y2);
01124         // update empty and filled
01125         empty.erase(i);
01126         filled.push(y2);
01127       }
01128     }
01129   }
01130 
01131   if (not empty.empty()) // we are not done
01132     fillThickets(y);
01133 
01134 }
01135 
01136 
01137 /*!
01138   \brief Fills in the row for y using a direct recursion.
01139 
01140   Precondition: s is either a complex, or a real type I descent generator for
01141   y.
01142 
01143   The real work is done by the recursionRow function, that will be used also
01144   in the real type II descents.
01145 */
01146 void Helper::directRecursion(BlockElt y, size_t s)
01147 {
01148   using namespace klsupport;
01149 
01150   std::vector<KLPol> klv;
01151   PrimitiveRow e;
01152 
01153   // put result of recursion formula in klv
01154   makeExtremalRow(e,y);
01155   recursionRow(klv,e,y,s);
01156 
01157   // write result
01158   writeRow(klv,e,y);
01159 
01160 }
01161 
01162 
01163 /*!
01164   \brief Dispatches the work of filling the KL- and mu-lists.
01165 */
01166 void Helper::fill()
01167 {
01168   // make sure the support is filled
01169   d_support->fill();
01170 
01171   // resize the outer lists to the block size
01172   d_prim.resize(d_support->size());
01173   d_kl.resize(d_support->size());
01174   d_mu.resize(d_support->size());
01175 
01176   // fill the lists
01177   size_t minLength = length(0);
01178   size_t maxLength = length(d_kl.size() - 1);
01179 
01180   // do the minimal length cases; they come first in the enumeration
01181   for (BlockElt y = 0; y < lengthLess(minLength+1); ++y) {
01182     d_prim[y].push_back(y); // singleton list for this row
01183     ++prim_size;
01184     // the K-L polynomial is 1
01185     d_kl[y].push_back(d_one);
01186     // there are no mu-coefficients
01187   }
01188 
01189   //set timers for KL computation
01190 #ifdef VERBOSE
01191   std::time_t time0;
01192   std::time(&time0);
01193   std::time_t time;
01194 
01195   std::ifstream statm("/proc/self/statm"); // open file for memory status
01196 #endif
01197 
01198   // do the other cases
01199   for (size_t l=minLength+1; l<=maxLength; ++l)
01200   {
01201     for (BlockElt y=lengthLess(l);
01202          y<lengthLess(l+1); ++y) // |lengthLess(maxLength+1)| is OK
01203     {
01204 #ifdef VERBOSE
01205       std::cerr << y << "\r";
01206 #endif
01207       try
01208       {
01209         fillKLRow(y);
01210       }
01211       catch (kl_error::KLError& e)
01212       {
01213         e("error: negative coefficient in k-l construction");
01214       }
01215       fillMuRow(y);
01216     }
01217 
01218     // now length |l| is completed
01219 #ifdef VERBOSE
01220     {
01221       size_t p_capacity // currently used memory for polynomials storage
01222         =d_hashtable.capacity()*sizeof(KLIndex)
01223         + d_store.capacity()*sizeof(KLPol);
01224       for (size_t i=0; i<d_store.size(); ++i)
01225         p_capacity+= (d_store[i].degree()+1)*sizeof(KLCoeff);
01226 
01227       std::time(&time);
01228       double deltaTime = difftime(time, time0);
01229       std::cerr << "t="    << std::setw(5) << deltaTime
01230                 << "s. l=" << std::setw(3) << l // completed length
01231                 << ", y="  << std::setw(6)
01232                 << lengthLess(l+1)-1 // last y value done
01233                 << ", polys:"  << std::setw(11) << d_store.size()
01234                 << ", pmem:" << std::setw(11) << p_capacity
01235                 << ", mat:"  << std::setw(11) << prim_size
01236                 <<  std::endl;
01237 
01238       unsigned int size, resident,share,text,lib,data;
01239       statm.seekg(0,std::ios_base::beg);
01240       statm >> size >> resident >> share >> text >> lib >> data;
01241       std::cerr << "Current data size " << data*4 << "kB (" << data*4096
01242                 << "), resident " << resident*4 << "kB, total "
01243                 << size*4 << "kB.\n";
01244     }
01245 #endif
01246   } // for (l=min_length+1; l<=max_Length; ++l)
01247 
01248 #ifdef VERBOSE
01249   std::time(&time);
01250   double deltaTime = difftime(time, time0);
01251   std::cerr << std::endl;
01252   std::cerr << "Total elapsed time = " << deltaTime << "s." << std::endl;
01253   std::cerr << d_store.size() << " polynomials, "
01254             << prim_size << " matrix entries."<< std::endl;
01255 
01256   std::cerr << std::endl;
01257 #endif
01258 
01259 }
01260 
01261 
01262 /*!
01263   \brief Fills in the row for y in the KL-table.
01264 
01265   Precondition: all lower rows have been filled; y is of length > 0;
01266   R-packets are consecutively numbered;
01267 
01268   Explanation: this function actually fills out the whole R-packet to
01269   which y belongs (unless it returns immediately). This is done in two
01270   stages: first, we fill the rows for which there is a direct recursion
01271   relation. The second stage, if any, is forwarded to the completePacket
01272   function.
01273 */
01274 void Helper::fillKLRow(BlockElt y)
01275 {
01276   using namespace klsupport;
01277 
01278   if (d_kl[y].size()) // row has already been filled
01279     return;
01280 
01281   std::pair<blocks::BlockElt,blocks::BlockElt> packet = block().R_packet(y);
01282   assert (packet.first==y);
01283   bool done = true;
01284 
01285   // fill in the direct recursions in the R-packet
01286   for (BlockElt y1 = packet.first; y1<packet.second; ++y1) {
01287     size_t s = firstDirectRecursion(y1);
01288     if (s != rank()) { // direct recursion
01289       directRecursion(y1,s);
01290     } else
01291       done = false;
01292   }
01293 
01294   // deal with the others
01295   if (not done)
01296     completePacket(y);
01297 
01298 }
01299 
01300 
01301 /*!
01302   \brief Fills in the row for y in the mu-table.
01303 
01304   Precondition: the row for y in the KL-table has been filled; length(y) > 0;
01305 
01306   Explanation: for the elements of length < length(y) - 1, mu(x,y) can
01307   be non-zero only if x is extremal w.r.t. y; so we run through d_kl[y],
01308   and look at the cases where the polynomial is of degree (1/2)(l(y)-l(x)-1)
01309   (the biggest possible). For the elements of colength 1, in the classical
01310   case we always had mu(x,y)=1. Here that's not true anymore, zero might
01311   be a possibility, and also larger values I believe; but at any rate the
01312   mu-values can be computed in terms of other mu-values.
01313 
01314   NOTE: we are not using the hasse-list here, although it is probably a
01315   good idea to compute that; that will reduce the mu-computation.
01316 */
01317 void Helper::fillMuRow(BlockElt y)
01318 {
01319   using namespace klsupport;
01320 
01321   const PrimitiveRow& e = d_prim[y]; // list of nonzero polynomials
01322 
01323   size_t ly = length(y);
01324   if (ly==0) // we are in fact never called for |y| values of length 0
01325     return;  // but this is prudent, since next loop would fail for |ly==0|
01326 
01327   PrimitiveRow::const_iterator start= e.begin();
01328   // traverse lengths of opposite parity, up to ly-3
01329   for (size_t lx=(ly-1)%2,d = (ly-1)/2; d>0; --d,lx+=2) {// d=(ly-1-lx)/2
01330 
01331     PrimitiveRow::const_iterator stop =
01332       std::lower_bound(start,e.end(),lengthLess(lx+1));
01333     for (start= std::lower_bound(start,stop,lengthLess(lx));
01334          start<stop; ++start) {
01335       BlockElt x = *start;
01336       KLIndex klp = d_kl[y][start-e.begin()];
01337 
01338       KLPolRef p=d_store[klp];
01339       if (p.degree()== d) { // then we have found a mu-coefficient for x
01340         d_mu[y].first.push_back(x);
01341         d_mu[y].second.push_back(p[d]);
01342       }
01343     }
01344   }
01345 
01346   // do cases of length ly-1
01347   BlockElt x_begin = lengthLess(ly-1);
01348   BlockElt x_end = lengthLess(ly);
01349 
01350   for (BlockElt x = x_begin; x < x_end; ++x) {
01351     MuCoeff mu = lengthOneMu(x,y);
01352     if (mu!=MuCoeff(0)) {
01353       d_mu[y].first.push_back(x);
01354       d_mu[y].second.push_back(mu);
01355     }
01356   }
01357 
01358 }
01359 
01360 
01361 /*!
01362   \brief Finishes the filling of the R-packet starting at y.
01363 
01364   Precondition: all the rows in the packet that are not part of a "thicket"
01365   have already been filled.
01366 
01367   Explanation: a thicket is an element that has only real type II descents,
01368   and that moreover is such that all elements in its conected component for
01369   the relation of being connected by a sequence of real type II cross-actions,
01370   is of the same form (for instance, it happens quite often that the principal
01371   series representations are a thicket.) Then we must use the "structural fact"
01372   in Lemma 6.2 of David's Park City notes: for each x lower than y, there is
01373   an element y' of the thicket for which x has an ascent (or if there is no
01374   such y', the K-L polynomial is zero.)
01375 
01376   Algorithm: (a) for each y' in the R-packet that has not already been filled,
01377   we determine the thicket of y' via a traversal algorithm, as usual (b) we
01378   fill in all the P_{x,y} in that thicket by a downwards recursion. In order
01379   to do that, we put the union of all the x'es in the extremal lists in a
01380   common ordered list. Then we move down the list; for each x, by assumption
01381   there is an y' in the thicket for which it is not extremal, and starting
01382   from there we can fill in P_{x,y} in all the rows where it needs to be
01383   filled.
01384 
01385   NOTE: thickets are always small, at the very worst a few hundred elements,
01386   so we don't have to worry about efficiency here.
01387 
01388   NOTE: perhaps it might be expected that there is usually (always?) a "large"
01389   element in the thicket, that would provide ascents for all x'es. So it might
01390   be worthwhile to sort the elements in the thicket in order of number of
01391   descents.
01392 */
01393 void Helper::fillThickets(BlockElt y)
01394 {
01395   using namespace descents;
01396   using namespace klsupport;
01397 
01398   std::pair<blocks::BlockElt,blocks::BlockElt> packet = block().R_packet(y);
01399   assert (packet.first==y);
01400 
01401   for (BlockElt y1 = packet.first; y1<packet.second; ++y1)
01402     if (d_kl[y1].size() == 0) {
01403       Thicket thicket(*this,y1);
01404       thicket.fill();
01405     }
01406 
01407 }
01408 
01409 
01410 /*!
01411   \brief Subtracts from klv the correcting terms in the K-L recursion.
01412 
01413   Precondtion: klp contains the terms corresponding to c_s.c_y, for the x that
01414   are extremal w.r.t. y; the mu-table and KL-table has been filled in for
01415   elements of length <= y.
01416 
01417   Explanation: the recursion formula is of the form:
01418 
01419     lhs = c_s.c_{y1} - sum_{z} mu(z,y1)c_z
01420 
01421   where z runs over the elements < y such that s is a descent for z,
01422   y1 is s.y, and lhs is c_y when s is a complex descent or real type I for y,
01423   and c_{y}+c_{s.y} when s is real type II.
01424 */
01425 void Helper::muCorrection(std::vector<KLPol>& klv,
01426                           const klsupport::PrimitiveRow& e,
01427                           BlockElt y, size_t s)
01428 {
01429   using namespace descents;
01430   using namespace klsupport;
01431   using namespace polynomials;
01432 
01433   BlockElt y1;
01434 
01435   if (descentValue(s,y) == DescentStatus::ComplexDescent) {
01436     y1 = cross(s,y);
01437   } else { // s is real for y
01438     y1 = inverseCayley(s,y).first;
01439   }
01440 
01441   const MuRow& mrow = d_mu[y1];
01442   size_t l_y = length(y);
01443 
01444   for (size_t i = 0; i < mrow.first.size(); ++i) {
01445 
01446     BlockElt z = mrow.first[i];
01447     size_t l_z = length(z);
01448 
01449     DescentStatus::Value v = descentValue(s,z);
01450     if (not DescentStatus::isDescent(v))
01451       continue;
01452 
01453     MuCoeff mu = mrow.second[i]; // mu!=MuCoeff(0)
01454 
01455     Degree d = (l_y-l_z)/2; // power of q used in the loops below
01456 
01457     if (mu==MuCoeff(1)) // avoid useless multiplication by 1 if possible
01458 
01459       for (size_t j = 0; j < e.size(); ++j) {
01460         BlockElt x = e[j];
01461         if (length(x) > l_z) break;
01462 
01463         KLPolRef pol = klPol(x,z);
01464         try {
01465           klv[j].safeSubtract(pol,d); // subtract q^d.P_{x,z} from klv[j]
01466         }
01467         catch (error::NumericUnderflow& e){
01468           throw kl_error::KLError(x,y,__LINE__,
01469                                   static_cast<const KLContext&>(*this));
01470         }
01471       } // for (j)
01472 
01473     else // mu!=MuCoeff(1)
01474 
01475       for (size_t j = 0; j < e.size(); ++j) {
01476         BlockElt x = e[j];
01477         if (length(x) > l_z) break;
01478 
01479         KLPolRef pol = klPol(x,z);
01480         try{
01481           klv[j].safeSubtract(pol,d,mu); // subtract q^d.mu.P_{x,z} from klv[j]
01482         }
01483         catch (error::NumericUnderflow& e){
01484           throw kl_error::KLError(x,y,__LINE__,
01485                                   static_cast<const KLContext&>(*this));
01486         }
01487       } // for {j)
01488 
01489   } // for (i)
01490 
01491 }
01492 
01493 
01494 /*!
01495   \brief Puts in klv the right-hand side of the recursion formula for y
01496   corresponding to the descent s.
01497 
01498   Precondition: s is either a complex, or a real type I or type II descent
01499   generator for y.
01500 
01501   Explanation: the shape of the formula is:
01502 
01503     P_{x,y} = (c_s.c_{y1})-part - correction term
01504 
01505   where y1 = cross(s,y) when s is complex for y, one of the two elements in
01506   inverseCayley(s,y) when s is real. The (c_s.c_{y1})-part depends on the
01507   status of x w.r.t. s (we look only at extremal x, so we know it is a
01508   descent); the correction term, coming from sum_z mu(z,y1)c_z, depends only
01509   on y1.
01510 */
01511 void Helper::recursionRow(std::vector<KLPol>& klv,
01512                           const klsupport::PrimitiveRow& e,
01513                           BlockElt y,
01514                           size_t s)
01515 {
01516   using namespace blocks;
01517   using namespace descents;
01518   using namespace klsupport;
01519 
01520   BlockElt y1;
01521 
01522   if (descentValue(s,y) == DescentStatus::ComplexDescent) {
01523     y1 = cross(s,y);
01524   } else { // s is real type I or type II for y
01525     y1 = inverseCayley(s,y).first;
01526   }
01527 
01528   klv.resize(e.size());
01529 
01530   for (size_t j = 0; j < klv.size()-1; ++j) {
01531     BlockElt x = e[j];
01532     switch (descentValue(s,x)) {
01533     case DescentStatus::ImaginaryCompact: {
01534       // (q+1)P_{x,y1}
01535       klv[j] = klPol(x,y1);
01536       klv[j].safeAdd(klv[j],1);
01537     }
01538       break;
01539     case DescentStatus::ComplexDescent: {
01540       BlockElt x1 = cross(s,x);
01541       // P_{x1,y1}+q.P_{x,y1}
01542       klv[j] = klPol(x1,y1);
01543       klv[j].safeAdd(klPol(x,y1),1);
01544     }
01545       break;
01546     case DescentStatus::RealTypeI: {
01547       BlockEltPair x1 = inverseCayley(s,x);
01548       // P_{x1.first,y1}+P_{x1.second,y1}+(q-1)P_{x,y1}
01549       klv[j] = klPol(x1.first,y1);
01550       klv[j].safeAdd(klPol(x1.second,y1));
01551       klv[j].safeAdd(klPol(x,y1),1);
01552       try {
01553         klv[j].safeSubtract(klPol(x,y1));
01554       }
01555       catch (error::NumericUnderflow& e){
01556         throw kl_error::KLError(x,y,__LINE__,
01557                                 static_cast<const KLContext&>(*this));
01558       }
01559     }
01560       break;
01561     case DescentStatus::RealTypeII: {
01562       BlockElt x1 = inverseCayley(s,x).first;
01563       // P_{x_1,y_1}+qP_{x,y1}-P_{s.x,y1}
01564       klv[j] = klPol(x1,y1);
01565       klv[j].safeAdd(klPol(x,y1),1);
01566       try {
01567         klv[j].safeSubtract(klPol(cross(s,x),y1));
01568       }
01569       catch (error::NumericUnderflow& e){
01570         throw kl_error::KLError(x,y,__LINE__,
01571                                 static_cast<const KLContext&>(*this));
01572       }
01573     }
01574       break;
01575     default: // this cannot happen
01576       assert(false);
01577       break;
01578     }
01579   }
01580 
01581   // last K-L polynomial is 1
01582   klv.back() = One;
01583 
01584   // do mu-correction
01585   muCorrection(klv,e,y,s);
01586 
01587 }
01588 
01589 
01590 /*!
01591   \brief Writes down row y in d_kl and d_prim.
01592 
01593   Precondition: klv contains the polynomials corresponding to the
01594   extremal values in the row; er contains the corresponding (extremal
01595   with respect to y) block elements.
01596 
01597   Explanation: the difficulty is that we want to write down the _primitive_
01598   elements, i.e., those x for which all descents for y are either descents
01599   or imaginary type II ascents; and moreover, we write down only those values
01600   for which the polynomial is nonzero. The values for which there is an
01601   imaginary type II ascent are computed "on the fly", from higher up
01602   values in the row.
01603 */
01604 void Helper::writeRow(const std::vector<KLPol>& klv,
01605                       const klsupport::PrimitiveRow& er, BlockElt y)
01606 {
01607   using namespace blocks;
01608   using namespace klsupport;
01609 
01610   PrimitiveRow pr;
01611   makePrimitiveRow(pr,y);
01612 
01613   KLRow klr(pr.size());
01614   PrimitiveRow nzpr(pr.size());
01615   KLRow::iterator new_pol = klr.end();
01616   PrimitiveRow::iterator new_extr = nzpr.end();
01617   PrimitiveRow::iterator nzpr_end = nzpr.end();
01618 
01619   // set stops in pr at extremal elements
01620   std::vector<size_t> stop(er.size()+1);
01621   stop[0] = 0;
01622 
01623   for (size_t j = 0; j < er.size(); ++j) {
01624     size_t epos = std::lower_bound(pr.begin(),pr.end(),er[j]) - pr.begin() + 1;
01625     stop[j+1] = epos;
01626   }
01627 
01628   // write polynomials, beginning with largest x (which is y).
01629   for (size_t j = er.size(); j;) {
01630     --j;
01631     // insert extremal polynomial
01632     if (not klv[j].isZero()) {
01633       *--new_extr = er[j];
01634       *--new_pol  = d_hashtable.match(klv[j]);
01635     }
01636     // do the others
01637     for (size_t i = stop[j+1]-1; i > stop[j];) {
01638       --i;
01639       size_t s = firstAscent(descent(pr[i]),descent(y),rank());
01640       BlockEltPair x1 = cayley(s,pr[i]);
01641       KLPol pol = klPol(x1.first,y,new_pol,new_extr,nzpr_end);
01642       pol.safeAdd(klPol(x1.second,y,new_pol,new_extr,nzpr_end));
01643 
01644       if (not pol.isZero()) {
01645         *--new_extr = pr[i];
01646         *--new_pol  = d_hashtable.match(pol);
01647       }
01648     }
01649   }
01650 
01651   // commit
01652   d_prim[y].reserve(klr.end() - new_pol);
01653   d_kl[y].reserve(klr.end() - new_pol);
01654 
01655   copy(new_extr,nzpr.end(),back_inserter(d_prim[y]));
01656   copy(new_pol,klr.end(),back_inserter(d_kl[y]));
01657 
01658   prim_size        += nzpr.end()-new_extr;
01659   nr_of_prim_nulls += new_extr  -nzpr.begin(); // measure unused space
01660 }
01661 
01662 } // namespace helper
01663 } // namespace kl
01664 
01665 /*****************************************************************************
01666 
01667         Chapter III -- The Thicket class
01668 
01669  *****************************************************************************/
01670 
01671 namespace kl {
01672   namespace helper {
01673 
01674 
01675 /*!
01676   \brief Constructs a thicket from y.
01677 
01678   Explanation: the thicket of y is the connected component of y in the graph
01679   whose edges are the real type II cross-actions. It is therefore contained
01680   in the R-packet of y. The edges of the thicket are a spanning tree; each
01681   edge goes from y1 to y2, where y2 is obtained from y1 through real cross
01682   action by s (the position of y2 in the vertex list, and s, are recorded
01683   in the edge). The recursion recorded is the recursion for s as a descent of
01684   y2. In this way, we can move along a path of edges and have the required
01685   recursion formulas available for computing the polynomial for y2 from
01686   that of y1 (all edges are two-sided, i.e., we also make the corresponding
01687   edge from y2 to y1.)
01688 */
01689 Thicket::Thicket(Helper& h, BlockElt y)
01690   :d_helper(&h)
01691 {
01692   using namespace descents;
01693 
01694   typedef std::map<BlockElt,EdgeList> M;
01695   typedef M::iterator MI;
01696 
01697   std::stack<BlockElt> toDo; // used as a bag (a queue would do just as well)
01698   M thicket;
01699 
01700   toDo.push(y);
01701   thicket.insert(std::make_pair(y,EdgeList()));
01702 
01703   while (not toDo.empty()) {
01704     BlockElt y1 = toDo.top();
01705     toDo.pop();
01706     EdgeList& e1 = thicket.find(y1)->second; // y1 is known to exist in thicket
01707     for (size_t s = 0; s < rank(); ++s) {
01708       if (descentValue(s,y1) != DescentStatus::RealTypeII)
01709         continue;
01710       BlockElt y2 = cross(s,y1);
01711       std::pair<MI,bool> ins = thicket.insert(std::make_pair(y2,EdgeList()));
01712       if (ins.second) { // y2 was new (otherwise just ignore edge y1 -> y2)
01713         EdgeList& e2 = ins.first->second; // locate empty list just inserted
01714         e1.push_back(Edge(y1,y2,s,std::vector<KLPol>()));
01715         e2.push_back(Edge(y2,y1,s,std::vector<KLPol>()));
01716         toDo.push(y2);
01717       }
01718     }
01719   }
01720 
01721   // write out result
01722 
01723   // first flatten map to pair of vectors d_vertices, d_edges
01724   d_vertices.resize(thicket.size());
01725   d_edges.resize(thicket.size());
01726   size_t j = 0;
01727 
01728   for (MI i = thicket.begin(); i != thicket.end(); ++i) {
01729     d_vertices[j] = i->first;
01730     d_edges[j].swap(i->second);
01731     ++j;
01732   }
01733 
01734   // now modify d_egdes so that the source and y fields of its edges
01735   // are no longer interpreted as BlockElt, but as index into d_vertices
01736   for (size_t j = 0; j < d_edges.size(); ++j) {
01737     EdgeList& el = d_edges[j];
01738     for (size_t i = 0; i < el.size(); ++i) {
01739       // replace el[i].y and el[i].source by their positions in d_vertices
01740       el[i].source = std::lower_bound(d_vertices.begin(),d_vertices.end(),
01741                                       el[i].source) - d_vertices.begin();
01742       el[i].y = std::lower_bound(d_vertices.begin(),d_vertices.end(),el[i].y)
01743         - d_vertices.begin();
01744     }
01745   }
01746 
01747   // make extremal lists
01748   d_extr.resize(thicket.size());
01749 
01750   for (size_t j = 0; j < d_extr.size(); ++j)
01751     d_helper->makeExtremalRow(d_extr[j],d_vertices[j]);
01752 
01753   // make primitive lists
01754   d_prim.resize(thicket.size());
01755 
01756   for (size_t j = 0; j < d_prim.size(); ++j)
01757     d_helper->makePrimitiveRow(d_prim[j],d_vertices[j]);
01758 
01759   // fill in recursions
01760   for (size_t j = 0; j < size(); ++j) {
01761     EdgeList& el = d_edges[j];
01762     for (size_t i = 0; i < el.size(); ++i) {
01763       BlockElt y2 = d_vertices[el[i].y];
01764       d_helper->recursionRow(el[i].recursion,d_extr[el[i].y],y2,el[i].s);
01765     }
01766   }
01767 
01768   // resize kl lists
01769   d_klr.resize(size());
01770   d_firstKL.resize(size());
01771   d_firstPrim.resize(size());
01772 }
01773 
01774 /******** accessors **********************************************************/
01775 
01776 /*!
01777   \brief Returns the position in d_vertices of the first y that is not
01778   extremal w.r.t. x, size() if there is no such y.
01779 */
01780 size_t Thicket::nonExtremal(BlockElt x) const
01781 {
01782   for (size_t j = 0; j < d_vertices.size(); ++j) {
01783     BlockElt y = d_vertices[j];
01784     size_t s = firstAscent(descent(x),descent(y),rank());
01785     if (s != rank()) // y was found
01786       return j;
01787   }
01788 
01789   return size();
01790 }
01791 
01792 /******** manipulators *******************************************************/
01793 
01794 
01795 /*!
01796   \brief Checks if x has an ascent in row y_pos, and computes the K-L pol in
01797   that case.
01798 
01799   Precondition: x is primitive in the row;
01800 
01801   Explanation: If the ascent exists, it will be imaginary type II. if
01802   x1 = (x1.first,x1.second) is the corresponding Cayley transform, the
01803   formula is P_x = P_x1.first + P_x1.second, both of which can be read off
01804   from the known part of the row.
01805 */
01806 bool Thicket::ascentCompute(BlockElt x, size_t pos)
01807 {
01808   using namespace blocks;
01809 
01810   BlockElt y = d_vertices[pos];
01811   size_t s = firstAscent(descent(x),descent(y),rank());
01812 
01813   if (s == rank()) // no ascent
01814     return false;
01815 
01816   BlockEltPair x1 = d_helper->cayley(s,x);
01817   KLPol pol = klPol(x1.first,pos);
01818   pol.safeAdd(klPol(x1.second,pos));
01819 
01820   if (not pol.isZero()) { // write pol
01821     *--d_firstKL[pos] = d_helper->d_hashtable.match(pol);
01822     *--d_firstPrim[pos] = x;
01823   }
01824 
01825   return true;
01826 }
01827 
01828 
01829 /*!
01830   \brief Computes the K-L polynomial for x in row pos, using the recurrence
01831   relation from e.
01832 
01833   Precondition: x is extremal in the row; e points towards pos; the polynomial
01834   for x for the source of e is known.
01835 
01836   Explanation: P_{x,pos} + P_{x,source} will be given by the recurrence
01837   relation corresponding to x.
01838 */
01839 void Thicket::edgeCompute(BlockElt x, size_t pos, const Edge& e)
01840 {
01841   using namespace klsupport;
01842 
01843   const PrimitiveRow& er = d_extr[pos];
01844   size_t xpos = std::lower_bound(er.begin(),er.end(),x) - er.begin();
01845 
01846   KLPol pol = e.recursion[xpos];
01847 
01848   try {
01849     pol.safeSubtract(klPol(x,e.source));
01850   }
01851   catch (error::NumericUnderflow& err){
01852     throw kl_error::KLError(x,d_vertices[pos],__LINE__,
01853                             static_cast<const KLContext&>(*d_helper));
01854   }
01855 
01856   if (not pol.isZero()) { // write pol
01857     *--d_firstKL[pos]   = d_helper->d_hashtable.match(pol);
01858     *--d_firstPrim[pos] = x;
01859   }
01860 
01861 }
01862 
01863 
01864 /*!
01865   \brief Fills in the K-L polynomials for the elements of the thicket.
01866 
01867   Algorithm: for each element y_j of the thicket, we have the list of
01868   primitive elements pr[j], and a list of K-L polynomials klv[j]. We
01869   are going to fill in the polynomials downwards from the top (the top
01870   elements being all ones); at the end of the process, we will have
01871   iterators pointing into each pr[j] and each klv[j], where the
01872   extremal list from that iterator on will contain all x'es for which
01873   the klpol is non zero (in other words, the other ones have been
01874   "weeded out" from pr[j]), and klv[j] from the iterator on contains
01875   the corresponding polynomials. Then all that remains to do is copy
01876   these onto the corresponding lists of the context.  In order to
01877   achieve this, we put in d_xlist an ordered list of all elements that
01878   are primitive for _some_ y_j, not equal to y_j, and we move
01879   downwards in that list. It is guaranteed by Lemma 6.2 in David's
01880   notes, that for each x in d_xlist there is a y_j for which there is
01881   an easy reduction (i.e., x might be primitive for y_j, but not
01882   extremal.) So we can deduce P_{x,y_j} from the already known part of
01883   klv[j], and then traversing the tree structure of edge relations
01884   imposed on the thicket, we can compute all the other P_{x,y_i} that
01885   need to be (i.e., those for which x is in pr[j].) We record the
01886   result only if the corresponding polynomial is non-zero.
01887 */
01888 void Thicket::fill()
01889 {
01890   using namespace klsupport;
01891 
01892   fillXList();
01893 
01894   // initialize rows, fill in last element, initialize iterators
01895   for (size_t j = 0; j < size(); ++j) {
01896     const PrimitiveRow& pr = primitiveRow(j); // last element is y_j
01897     d_klr[j].resize(pr.size());
01898     d_klr[j].back() = d_helper->d_one;
01899     d_firstPrim[j] = d_prim[j].end()-1;
01900     d_firstKL[j] = d_klr[j].end()-1;
01901   }
01902 
01903   // fill in rows
01904   for (size_t j = d_xlist.size(); j>0;) {
01905     --j;
01906     BlockElt x = d_xlist[j];
01907     // find a vertex s.t. x is not extremal
01908     size_t iy = nonExtremal(x);
01909     if (iy == size()) // do nothing; zero polynomials are ignored
01910       continue;
01911     for (ThicketIterator i(*this,iy); i(); ++i) {
01912       size_t pos = *i;
01913       const PrimitiveRow& pr = primitiveRow(pos);
01914       if (not std::binary_search(pr.begin(),pr.end(),x))
01915         // x is not primitive
01916         continue;
01917       if (ascentCompute(x,pos)) // x is not extremal
01918         continue;
01919       // if we get here, x is extremal
01920       edgeCompute(x,pos,i.edge());
01921     }
01922   }
01923 
01924   // write result
01925 
01926   for (size_t j = 0; j < size(); ++j) {
01927     BlockElt y = d_vertices[j];
01928 
01929     d_helper->d_prim[y].reserve(d_prim[j].end() - d_firstPrim[j]);
01930     d_helper->d_kl[y].reserve(d_prim[j].end() - d_firstPrim[j]);
01931 
01932     copy(d_firstPrim[j],d_prim[j].end(),back_inserter(d_helper->d_prim[y]));
01933     copy(d_firstKL[j],d_klr[j].end(),back_inserter(d_helper->d_kl[y]));
01934 
01935     d_helper->prim_size        += d_prim[j].end()-d_firstPrim[j];
01936     d_helper->nr_of_prim_nulls += d_firstPrim[j]-d_prim[j].begin();
01937   }
01938 
01939 }
01940 
01941 
01942 /*!
01943   \brief Puts in d_xlist the union of the extremal lists for the elements
01944   of the thicket, top element excluded.
01945 */
01946 void Thicket::fillXList()
01947 {
01948   using namespace klsupport;
01949 
01950   std::set<BlockElt> xs;
01951 
01952   for (size_t j = 0; j < size(); ++j) {
01953     const PrimitiveRow& p = primitiveRow(j);
01954     for (size_t i = 0; i < p.size()-1; ++i)
01955       xs.insert(p[i]);
01956   }
01957 
01958   d_xlist.reserve(xs.size());
01959   copy(xs.begin(),xs.end(),std::back_inserter(d_xlist));
01960 
01961 }
01962 
01963   }
01964 }
01965 
01966 /*****************************************************************************
01967 
01968         Chapter IV -- The ThicketIterator class implementation
01969 
01970  *****************************************************************************/
01971 
01972 namespace kl {
01973   namespace helper {
01974 
01975 ThicketIterator::ThicketIterator(const Thicket& th, size_t j)
01976   : d_thicket(&th)
01977 
01978 {
01979   d_stack.push(j);
01980   d_done.set_capacity(th.size()); // all bits unset initially
01981   d_done.insert(j);
01982   d_current = th.edgeList(j).begin();
01983   d_currentEnd = th.edgeList(j).end();
01984   d_pos = j;
01985 }
01986 
01987 /******** manipulators *******************************************************/
01988 
01989 /*!
01990   \brief Pre-increment operator.
01991 
01992   Incrementing the iterator means going to the next new element, obtained as
01993   destination vertex of one of the remaining edges in the current edgelist, or
01994   in an edgelist for a vertex popped from the stack if necessary; here 'new'
01995   meaning the vertex has not yet been recorded in d_done. If no new
01996   destination vertex can be obtained even after trying all lists on the stack
01997   we return the thicket size as indication that no vertices are left. In the
01998   contrary case the vertex returned is recorded in d_done and pushed onto the
01999   stack for later processing of its neighbors.
02000 */
02001 ThicketIterator& ThicketIterator::operator++ ()
02002 {
02003   for (; d_current != d_currentEnd; ++d_current) {
02004     // get index of destination of current edge in vertices
02005     size_t j = d_current->y;
02006     if (not d_done.isMember(j)) { // j is new
02007       d_pos = j;
02008       d_stack.push(j);
02009       d_done.insert(j);
02010       return *this;
02011     }
02012   }
02013 
02014   // if we get here, we have exhausted the current row
02015 
02016   while (not d_stack.empty()) {
02017     size_t j = d_stack.top();
02018     d_stack.pop();
02019 
02020     // make edge list of element just popped the current one
02021     d_current = d_thicket->edgeList(j).begin();
02022     d_currentEnd = d_thicket->edgeList(j).end();
02023 
02024     // and do exactly what was done
02025     for (; d_current != d_currentEnd; ++d_current) {
02026       size_t i = d_current->y;
02027       if (not d_done.isMember(i)) { // i is new
02028         d_pos = i;
02029         d_stack.push(i);
02030         d_done.insert(i);
02031         return *this;
02032       }
02033     }
02034   }
02035 
02036   // if we get here, we have exhausted the thicket
02037   d_pos = d_thicket->size();
02038 
02039   return *this;
02040 }
02041 
02042 } //namespace helper
02043 } //namespace kl
02044 
02045 
02046 /*****************************************************************************
02047 
02048         Chapter V -- Functions declared in kl.h
02049 
02050  *****************************************************************************/
02051 
02052 namespace kl {
02053 
02054 
02055 /*!
02056   \brief Puts in wg the W-graph for this block.
02057 
02058   Explanation: the W-graph is a graph with one vertex for each element of the
02059   block; the corresponding descent set is the tau-invariant, i.e. the set of
02060   generators s that are either complex descents, real type I or II, or
02061   imaginary compact. Let x < y in the block such that mu(x,y) != 0, and
02062   descent(x) != descent(y). Then there is an edge from x to y unless
02063   descent(x) is contained in descent(y), and an edge from y to x unless
02064   descent(y) is contained in descent(x). Note that the latter containment
02065   always holds when the length difference is > 1, so that in that case there
02066   will only be an edge from x to y (the edge must be there because we already
02067   assumed that the descent sets were not equal.) In both cases, the
02068   coefficient corresponding to the edge is mu(x,y).
02069 
02070   NOTE: if I'm not mistaken, the edgelists come already out sorted.
02071 */
02072 void wGraph(wgraph::WGraph& wg, const KLContext& klc)
02073 {
02074   using namespace bitset;
02075   using namespace graph;
02076   using namespace kl;
02077   using namespace wgraph;
02078 
02079   wg.reset();
02080   wg.resize(klc.size());
02081 
02082   // fill in descent sets
02083   for (BlockElt y = 0; y < klc.size(); ++y)
02084     wg.descent(y) = klc.descentSet(y);
02085 
02086   // fill in edges and coefficients
02087   for (BlockElt y = 0; y < klc.size(); ++y) {
02088     const RankFlags& d_y = wg.descent(y);
02089     const MuRow& mrow = klc.muRow(y);
02090     for (size_t j = 0; j < mrow.first.size(); ++j) {
02091       BlockElt x = mrow.first[j];
02092       const RankFlags& d_x = wg.descent(x);
02093       if (d_x == d_y)
02094         continue;
02095       MuCoeff mu = mrow.second[j];
02096       if (klc.length(y) - klc.length(x) > 1) { // add edge from x to y
02097         wg.edgeList(x).push_back(y);
02098         wg.coeffList(x).push_back(mu);
02099         continue;
02100       }
02101       // if we get here, the length difference is 1
02102       if (not d_y.contains(d_x)) { // then add edge from x to y
02103         wg.edgeList(x).push_back(y);
02104         wg.coeffList(x).push_back(mu);
02105       }
02106       if (not d_x.contains(d_y)) { // then add edge from y to x
02107         wg.edgeList(y).push_back(x);
02108         wg.coeffList(y).push_back(mu);
02109       }
02110     }
02111   }
02112 
02113 }
02114 
02115 } // namespace kl
02116 
02117 /*****************************************************************************
02118 
02119         Chapter VI -- Functions local to this module
02120 
02121  *****************************************************************************/
02122 
02123 namespace kl {
02124   namespace helper {
02125 
02126 
02127 /*!
02128   \brief Returns the first s that is an ascent for d1, and a descent for d2;
02129   rank if there is none such.
02130 
02131   Precondition: rank is the number of valid fields in d1 and d2.
02132 */
02133 size_t firstAscent(const descents::DescentStatus& d1,
02134                    const descents::DescentStatus& d2, size_t rank)
02135 {
02136 
02137   using namespace descents;
02138 
02139   for (size_t s = 0; s < rank; ++s) {
02140     if ((DescentStatus::isDescent(d2[s])) and
02141         (not DescentStatus::isDescent(d1[s])))
02142       return s;
02143   }
02144 
02145   return rank;
02146 }
02147 
02148 
02149 /*!
02150   \brief Returns the first s that is a non-ImaginaryTypeII ascent for
02151   d1, and a descent for d2; rank if there is none such.
02152 
02153   Precondition: rank is the number of valid fields in d1 and d2.
02154 */
02155 size_t goodAscent(const descents::DescentStatus& d1,
02156                   const descents::DescentStatus& d2, size_t rank)
02157 {
02158   using namespace descents;
02159 
02160   for (size_t s = 0; s < rank; ++s) {
02161     if ((not DescentStatus::isDescent(d2[s])) or
02162         (DescentStatus::isDescent(d1[s])))
02163       continue;
02164     if (d1[s] != DescentStatus::ImaginaryTypeII)
02165       return s;
02166   }
02167 
02168   return rank;
02169 }
02170 
02171 } // namespace helper
02172 } // namespace kl
02173 } // namespace atlas

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