dmcb.h

Go to the documentation of this file.
00001 //
00002 // This program can be freely used in an academic environment
00003 // ONLY for research purposes, subject to the following restrictions:
00004 //
00005 // 1. The origin of this software must not be misrepresented; you must not
00006 //    claim that you wrote the original software. If you use this software
00007 //    an acknowledgment in the product documentation is required.
00008 // 2. Altered source versions must be plainly marked as such, and must not be
00009 //    misrepresented as being the original software.
00010 // 3. This notice may not be removed or altered from any source distribution.
00011 //
00012 // Any other use is strictly prohibited by the author, without an explicit 
00013 // permission.
00014 //
00015 // Note that this program uses the LEDA library, which is NOT free. For more 
00016 // details visit Algorithmic Solutions at http://www.algorithmic-solutions.com/
00017 // There is also a free version of LEDA 6.0 or newer.
00018 //
00019 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00020 // ! Any commercial use of this software is strictly !
00021 // ! prohibited without explicit permission by the   !
00022 // ! author.                                         !
00023 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00024 //
00025 // This software is distributed in the hope that it will be useful,
00026 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00027 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00028 //
00029 // Copyright (C) 2004-2008 - Dimitris Michail <dmixdim@googlemail.com>, <michail@mpi-inf.mpg.de>
00030 //
00031 // $Id: dmcb.h 7005 2008-04-15 09:25:45Z dmichail $ 
00032 //
00033 
00072 #ifndef DMCB_H
00073 #define DMCB_H
00074 
00075 #include <LEP/mcb/config.h>
00076 
00077 
00078 #ifdef LEDA_GE_V5
00079 #include <LEDA/graph/graph.h>
00080 #include <LEDA/graph/edge_array.h>
00081 #include <LEDA/core/array.h>
00082 #include <LEDA/core/random_source.h>
00083 #include <LEDA/numbers/integer.h>
00084 #else
00085 #include <LEDA/graph.h>
00086 #include <LEDA/array.h>
00087 #include <LEDA/edge_array.h>
00088 #include <LEDA/integer.h>
00089 #include <LEDA/random_source.h>
00090 #endif
00091 
00092 #include <LEP/mcb/edge_num.h>
00093 #include <LEP/mcb/fp.h>
00094 #include <LEP/mcb/spvecfp.h>
00095 #include <LEP/mcb/arithm.h>
00096 #include <LEP/mcb/transform.h>
00097 #include <LEP/mcb/dsigned.h>
00098 
00099 namespace mcb { 
00100 
00101 #if defined(LEDA_NAMESPACE)
00102     using leda::graph;
00103     using leda::edge;
00104     using leda::edge_array;
00105     using leda::node;
00106     using leda::node_array;
00107     using leda::array;
00108     using leda::integer;
00109     using leda::random_source;
00110     using leda::pq_item;
00111 #endif
00112 
00117     // W = weight type
00118     // ptype = type of prime p
00119 
00120     /*  \brief Compute a cycle basis of a weighted directed graph modulo a prime number.
00121      * 
00122      *  The function computes a directed Cycle Basis \f$B\f$ of \f$g\f$, that 
00123      *  is a cycle basis of \f$g\f$ with the smallest length (sum of lengths of cycles). The 
00124      *  basis is returned as an array of sparse vectors spvecfp, called mcb. 
00125      * 
00126      *  Every edge is represented by some integer, by a fixed and arbitrary numbering. This
00127      *  numbering is represented by enumb. 
00128      * 
00129      *  The function also returns a certificate of optimality of the minimum cycle basis. 
00130      *  More precisely a set of linearly independent vectors for which cycle \f$i\f$ is the 
00131      *  shortest cycle in \f$g\f$ with non-zero intersection with the proof vector \f$i\f$. 
00132      * 
00133      *  The returned cycle basis might not be a minimum cycle basis.
00134      *  
00135      *  The function returns the weight of the cycle basis or is undefined
00136      *  if there were any errors. 
00137      *
00138      *  The running time is \f$O( m^3 )\f$ where \f$m\f$ are the number of edges of \f$g\f$. 
00139      *
00140      *  \param g A directed graph.
00141      *  \param len The edge lengths.
00142      *  \param mcb A leda::array of spvecfp to return the cycle basis.
00143      *  \param proof A leda::array of spvecfp to return the proof.
00144      *  \param enumb An edge numbering.
00145      *  \param p A leda::integer prime number.
00146      *  \pre g is simple and loop-free
00147      *  \pre len is positive
00148      *  \pre enumb is already initialized with g
00149      *  \pre p is a prime number
00150      *  \ingroup exactmcb
00151      */
00152     template<class W>
00153         W DMCB( const graph& g, 
00154                 const edge_array<W>& len,
00155                 array< mcb::spvecfp >& mcb,
00156                 array< mcb::spvecfp >& proof,
00157                 const mcb::edge_num& enumb,
00158                 ptype& p
00159               )
00160         { 
00161 #if ! defined(LEDA_CHECKING_OFF)
00162             if ( Is_Simple( g ) == false ) 
00163                 error_handler(999,"DMCB: illegal graph (non-simple?)");
00164             if ( Is_Loopfree( g ) == false ) 
00165                 error_handler(999,"DMCB: illegal graph (has loops?)");
00166 
00167             edge e1;
00168             forall_edges( e1 , g ) {
00169                 if ( len[e1] <= 0 )
00170                     error_handler(999,"MIN_CYCLE_BASIS: illegal edge (non-positive weight)");
00171             }
00172 
00173             if ( ! primes<ptype>::is_prime( p ) ) 
00174                 error_handler(999,"DMCB: p is not a prime number!");
00175 
00176 #endif
00177             int d = enumb.dim_cycle_space();
00178             if ( d <= 0 ) return W(0);
00179 
00180             mcb.resize( d );
00181             array< spvecfp >& B = mcb;
00182             proof.resize( d );
00183             array< spvecfp >& X = proof;
00184 
00185             // initialize shortest paths
00186             dirsp<W,ptype> SP( g, len, p, enumb );
00187 
00188 #if  defined(LEP_DEBUG_OUTPUT)
00189             std::cout << "executing with prime p = " << p << std::endl;
00190 #endif
00191 
00192             // initialize X_i's and $B_i$'s
00193             // assume that $p$ fits in ptype
00194             // and $d$ in indextype
00195             indextype i,j;
00196             for( i = 0; i < d; i++ ) { 
00197                 X[i] = spvecfp( p );
00198                 X[i] = i;
00199                 B[i] = spvecfp( p );
00200             }
00201 
00202             // now execute main loop
00203             spvecfp tmp = spvecfp( p );
00204             ptype tmpi;
00205             W min = W(0);
00206             for( i = 0; i < d; i++ ) { 
00207 
00208                 // compute B_i
00209                 W mini;
00210                 B[i] = SP.get_shortest_cycle( X[i], mini );
00211                 min += mini;
00212 
00213                 // precompute part
00214                 // NOTE: we do not precompute inverses, since we don't want
00215                 //       to have a dependency on the maximum size of an 
00216                 //       array that will store these values
00217                 //       p is O(d^2 logd) and thus O(logd) to compute inverse
00218                 //       at most d times, thus O(d logd) = O(m logm) in total
00219                 tmpi = X[i]*B[i];
00220                 while( tmpi < 0 ) tmpi += p; // make [-i]_p = [p-i]_p
00221                 while( tmpi >= p ) tmpi -= p; // make [i+p]_p = [i]_p
00222                 tmp = X[i] * fp<ptype>::get_mult_inverse( tmpi, p );
00223 
00224                 // update sets X_j, j > i
00225                 for( j = i+1; j < d; j++ ) 
00226                     X[j] -=  tmp * (B[i] * X[j]) ;
00227             }
00228 
00229             return min;            
00230 
00231         } // end of DMCB
00232 
00267     template<class W>
00268         W DMCB( const graph& g, 
00269                 const edge_array<W>& len,
00270                 array< mcb::spvecfp >& mcb,
00271                 array< mcb::spvecfp >& proof,
00272                 const mcb::edge_num& enumb,
00273                 double error = 0.375
00274               )
00275         { 
00276 #if ! defined(LEDA_CHECKING_OFF)
00277             if ( Is_Simple( g ) == false ) 
00278                 error_handler(999,"MIN_CYCLE_BASIS: illegal graph (non-simple?)");
00279             if ( Is_Loopfree( g ) == false ) 
00280                 error_handler(999,"MIN_CYCLE_BASIS: illegal graph (has loops?)");
00281             if ( error <= 0 || error >= 1 ) 
00282                 error_handler(999,"MIN_CYCLE_BASIS: error probability is out of range");
00283 
00284             edge e1;
00285             forall_edges( e1 , g ) {
00286                 if ( len[e1] <= 0 )
00287                     error_handler(999,"MIN_CYCLE_BASIS: illegal edge (non-positive weight)");
00288             }
00289 #endif
00290             int d = enumb.dim_cycle_space();
00291             if ( d <= 0 ) return W(0);
00292 
00293             mcb.resize( d );
00294             proof.resize( d );
00295 
00296             // decide how many times to execute the algorithm ( perror <= 3/8 = 0.375 )
00297             int times = (int) ceil(  log(error)/log(0.375) );
00298 
00299 #if  defined(LEP_DEBUG_OUTPUT)
00300             std::cout << "Executing " << times; 
00301             std::cout << " number of times to achieve error probability ";
00302             std::cout << error << std::endl;
00303 #endif
00304 
00305             // create X and B matrices
00306             array< spvecfp > X ( d );
00307             array< spvecfp > B ( d );
00308             W min_so_far = W(0);
00309             bool min_so_far_inf = true;
00310 
00311             // loop necessary times, for error probability to be correct
00312             while( times-- > 0 ) { 
00313 
00314                 // pick random prime
00315                 ptype p;
00316                 {
00317                     int logd = log( integer( d + 1 ) );
00318                     int loglogd = log( integer( logd + 1 ) );
00319                     int randbits = 7 + 2 * logd + loglogd;
00320                     int failsafe = 50 * randbits;
00321                     int count = 0;
00322 
00323                     while( true ) { 
00324                         // loop failsafe, increase random bits
00325                         if ( count++ > failsafe ) { 
00326                             randbits++;
00327                             failsafe += 50;
00328                             count = 0;
00329                         }
00330 
00331                         // get random number
00332                         p = ptype::random( randbits );
00333                         p += d*d;
00334                         //std::cout << "testing p = " << p << std::endl;
00335 
00336                         // if is > 1 and prime break
00337                         if ( p > 1 && primes<ptype>::is_prime( p ) ) break;
00338                     }
00339                 }
00340 
00341 #if  defined(LEP_DEBUG_OUTPUT)
00342                 std::cout << "executing with prime p = " << p << std::endl;
00343 #endif
00344 
00345                 W min = DMCB( g, len, B, X, enumb, p );
00346 
00347                 // if found better, update
00348                 if ( ( min_so_far_inf == true ) || 
00349                         ( min_so_far_inf == false && min < min_so_far ) ) { 
00350 #if  defined(LEP_DEBUG_OUTPUT)
00351                     if ( min_so_far_inf == false )
00352                         std::cout << "found better solution with weight " << min << std::endl;
00353 #endif
00354                     mcb = B;
00355                     proof = X;
00356                     min_so_far_inf = false;
00357                     min_so_far = min;
00358                 }
00359 
00360             }
00361             return min_so_far;
00362         } // end of DMCB
00363 
00393     template<class W>
00394         W DMCB( const graph& g, 
00395                 const edge_array<W>& len,
00396                 array< mcb::spvecfp >& mcb,
00397                 const mcb::edge_num& enumb,
00398                 double error = 0.375
00399               )
00400         {
00401             array< spvecfp > proof_tmp;
00402             return DMCB(g, len, mcb, proof_tmp, enumb, error ); 
00403         }
00404 
00434     template<class W>
00435         W DMCB( const graph& g, 
00436                 const edge_array<W>& len,
00437                 array< array<etype> >& mcb,
00438                 const mcb::edge_num& enumb,
00439                 double error = 0.375
00440               )
00441         {
00442             array< spvecfp > mcb_tmp;
00443             array< spvecfp > proof_tmp;
00444 
00445             int d = enumb.dim_cycle_space();
00446 
00447             // run the general version
00448             W min = DMCB<W>( g, len, mcb_tmp, \
00449                     proof_tmp, enumb, error );
00450 
00451             // get p used
00452             ptype p = proof_tmp[0].pvalue(); 
00453 
00454             // transform
00455             mcb.resize( d );
00456             for ( int i = 0; i < d; i++ )
00457                 spvecfp_to_array_ints( g, enumb, p, mcb_tmp[i], mcb[i] );       
00458 
00459             return min;
00460         }
00461 
00463 
00464 } // end of mcb namespace
00465 
00466 #endif // DMCB_H
00467 
00468 /* ex: set ts=4 sw=4 sts=4 et: */

Generated on Tue Apr 22 13:40:09 2008 for mcb LEDA Extension Package by  doxygen 1.4.6