00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00040 #ifndef UMCB_APPROX_H
00041 #define UMCB_APPROX_H
00042
00043 #include <LEP/mcb/config.h>
00044 #include <LEP/mcb/umcb.h>
00045 #include <LEP/mcb/spanner.h>
00046 #include <LEP/mcb/ushortpath.h>
00047 #include <LEP/mcb/dmcb.h>
00048
00049 #ifdef LEDA_GE_V5
00050 #include <LEDA/graph/edge_map.h>
00051 #include <LEDA/graph/node_map.h>
00052 #else
00053 #include <LEDA/edge_map.h>
00054 #include <LEDA/node_map.h>
00055 #endif
00056
00057 namespace mcb
00058 {
00059
00060 #if defined(LEDA_NAMESPACE)
00061 using leda::node;
00062 using leda::node_map;
00063 using leda::edge;
00064 using leda::edge_array;
00065 using leda::edge_map;
00066 #endif
00067
00068
00069 template<typename W, class Container>
00070 class mcb_approx {
00071 public:
00072 typedef W result_type;
00073
00074 mcb_approx( const graph& g_,
00075 int k_,
00076 array< Container >& mcb_,
00077 const mcb::edge_num& enumb_ )
00078 : g(g_), k(k_), mcb(mcb_), enumb(enumb_), Tcycles(0.0), Tsubgraph(0.0)
00079 {
00080 }
00081
00082 virtual ~mcb_approx() {}
00083
00084 W run() {
00085 checkGraphPreconditions();
00086 checkEdgeLengthPreconditions();
00087 initialize();
00088
00089 constructSpanner();
00090
00091 edge_num spanner_enumb( spanner );
00092 array< Container > spanner_mcb;
00093 constructSpannerMCB( spanner_enumb, spanner_mcb );
00094
00095 constructPartialMCBfromSpanner( spanner_enumb, spanner_mcb );
00096 translateSpannerMCBToGraphPartialMCB( spanner_enumb, spanner_mcb );
00097
00098 return length;
00099 }
00100
00101 private:
00102
00103 void checkGraphPreconditions() {
00104 #if ! defined(LEDA_CHECKING_OFF)
00105 if ( Is_Loopfree( g ) == false )
00106 error_handler(999,"UMCB_APPROX: illegal graph (loops?)");
00107 if ( k <= 0 )
00108 error_handler(999,"UMCB_APPROX: illegal value of k, non-positive?");
00109 #endif
00110 }
00111
00112 virtual void checkEdgeLengthPreconditions() {}
00113
00114 void initialize() {
00115 length = W();
00116 N = enumb.dim_cycle_space();
00117 mcb.resize( N );
00118 }
00119
00120 virtual void constructSpanner() = 0;
00121
00122 virtual void constructSpannerMCB( const edge_num& spanner_enumb, array< Container >& spanner_mcb ) = 0;
00123
00124 virtual void constructPartialMCBfromSpanner( const edge_num& spanner_enumb, const array< Container >& spanner_mcb ) = 0;
00125
00126 virtual void translateSpannerMCBToGraphPartialMCB( const edge_num& spanner_enumb,
00127 const array<Container>& spanner_mcb ) = 0;
00128
00129 protected:
00130 const graph& g;
00131 int k;
00132 array< Container >& mcb;
00133 const mcb::edge_num& enumb;
00134 W length;
00135 int N;
00136
00137
00138 graph spanner;
00139 edge_array<W> spanner_len;
00140 node_map<node> node_g_to_spanner;
00141 node_map<node> node_spanner_to_g;
00142 edge_map<edge> edge_g_to_spanner;
00143 edge_map<edge> edge_spanner_to_g;
00144
00145
00146 float Tcycles, Tsubgraph, Ttemp;
00147 };
00148
00149
00150
00151 template<typename W, class Container>
00152 class umcb_approx : public mcb_approx< W, Container >
00153 {
00154 public:
00155 typedef mcb_approx<W,Container> base_type;
00156
00157 umcb_approx( const graph& g_,
00158 int k_,
00159 array< Container >& mcb_,
00160 const mcb::edge_num& enumb_ )
00161 : base_type( g_, k_, mcb_, enumb_ )
00162 {
00163 }
00164
00165 ~umcb_approx() {}
00166
00167 private:
00168
00169 virtual void constructSpannerMCB( const edge_num& spanner_enumb, array<Container>& spanner_mcb )
00170 {
00171 array< Container > spanner_proof;
00172
00173 #ifdef LEP_DEBUG_OUTPUT
00174 std::cout << "Computing " << spanner_enumb.dim_cycle_space() << " cycles";
00175 std::cout << " by the MCB of spanner..." << std::endl;
00176 #endif
00177
00178 length += UMCB_SVA<W,Container>( spanner, spanner_len,
00179 spanner_mcb, spanner_proof, spanner_enumb );
00180 }
00181
00182 virtual void translateSpannerMCBToGraphPartialMCB( const edge_num& spanner_enumb,
00183 const array<Container>& spanner_mcb )
00184 {
00185 edge e;
00186 int extracycles = spanner_enumb.dim_cycle_space();
00187 for( int i = 0; i < extracycles; ++i )
00188 {
00189 mcb[ N - extracycles + i ] = Container();
00190
00191 int j = 0;
00192 forall( j, spanner_mcb[ i ] )
00193 {
00194
00195
00196 e = edge_spanner_to_g[ spanner_enumb(j) ];
00197 mcb[ N - extracycles + i ].insert( enumb( e ) );
00198 }
00199
00200 mcb[ N - extracycles + i ].sort();
00201 }
00202
00203 #ifdef LEP_STATS
00204 Tsubgraph += leda::used_time( Ttemp );
00205 std::cout << "LEP_STATS: spanner cycles time: " << Tcycles << std::endl;
00206 std::cout << "LEP_STATS: subgraph MCB time : " << Tsubgraph << std::endl;
00207 #endif
00208 }
00209
00210 using base_type::length;
00211 using base_type::spanner;
00212 using base_type::spanner_len;
00213 using base_type::N;
00214 using base_type::mcb;
00215 using base_type::edge_spanner_to_g;
00216 using base_type::enumb;
00217 };
00218
00219
00220 template<typename W>
00221 class dmcb_approx : public mcb_approx<W,mcb::spvecfp>
00222 {
00223 public:
00224 typedef mcb_approx<W,mcb::spvecfp> base_type;
00225
00226 dmcb_approx( const graph& g_,
00227 int k_,
00228 array< mcb::spvecfp >& mcb_,
00229 const mcb::edge_num& enumb_,
00230 double error_
00231 )
00232 : base_type( g_, k_, mcb_, enumb_ ), error(error_), prime(3), minimizeErrorProb(true)
00233 {
00234 }
00235
00236 dmcb_approx( const graph& g_,
00237 int k_,
00238 array< mcb::spvecfp >& mcb_,
00239 const mcb::edge_num& enumb_,
00240 ptype prime_
00241 )
00242 : base_type( g_, k_, mcb_, enumb_ ), error(0.375), prime(prime_), minimizeErrorProb(false)
00243 {
00244 }
00245
00246 ~dmcb_approx() {}
00247
00248 protected:
00249
00250 ptype getPrime( const edge_num& spanner_enumb, const array<mcb::spvecfp>& spanner_mcb )
00251 {
00252 return ( spanner_enumb.dim_cycle_space() > 0 ) ? spanner_mcb[0].pvalue() : 3;
00253 }
00254
00255 private:
00256
00257 virtual void constructSpannerMCB( const edge_num& spanner_enumb, array<mcb::spvecfp>& spanner_mcb )
00258 {
00259 array<spvecfp> spanner_proof;
00260
00261 #ifdef LEP_DEBUG_OUTPUT
00262 std::cout << "Computing " << spanner_enumb.dim_cycle_space() << " cycles";
00263 std::cout << " by the MCB of spanner..." << std::endl;
00264 #endif
00265
00266 if ( minimizeErrorProb )
00267 length += DMCB<W>( spanner, spanner_len,
00268 spanner_mcb, spanner_proof, spanner_enumb, error );
00269 else
00270 length += DMCB<W>( spanner, spanner_len,
00271 spanner_mcb, spanner_proof, spanner_enumb, prime );
00272
00273 }
00274
00275 virtual void translateSpannerMCBToGraphPartialMCB( const edge_num& spanner_enumb,
00276 const array<spvecfp>& spanner_mcb )
00277 {
00278 edge e;
00279 int extracycles = spanner_enumb.dim_cycle_space();
00280 for( int i = 0; i < extracycles; ++i )
00281 {
00282 mcb[ N - extracycles + i] = mcb::spvecfp( getPrime( spanner_enumb, spanner_mcb ) );
00283
00284 leda::list_item it = spanner_mcb[i].first();
00285 while( it != nil ) {
00286 e = edge_spanner_to_g[ spanner_enumb( spanner_mcb[i].index( it ) ) ];
00287 mcb[ N - extracycles + i ].append( enumb(e), spanner_mcb[i].inf( it ) );
00288 it = spanner_mcb[i].succ( it );
00289 }
00290 mcb[ N - extracycles + i ].sort();
00291 }
00292
00293 #ifdef LEP_STATS
00294 Tsubgraph += leda::used_time( Ttemp );
00295 std::cout << "LEP_STATS: spanner cycles time: " << Tcycles << std::endl;
00296 std::cout << "LEP_STATS: subgraph MCB time : " << Tsubgraph << std::endl;
00297 #endif
00298 }
00299
00300 using base_type::length;
00301 using base_type::spanner;
00302 using base_type::spanner_len;
00303 using base_type::N;
00304 using base_type::mcb;
00305 using base_type::edge_spanner_to_g;
00306 using base_type::enumb;
00307
00308 private:
00309 double error;
00310 ptype prime;
00311 bool minimizeErrorProb;
00312 };
00313
00314
00315
00316
00317
00318 template<typename W, class Container>
00319 class weighted_umcb_approx : public umcb_approx<W,Container>
00320 {
00321 public:
00322 typedef umcb_approx<W,Container> base_type;
00323
00324 weighted_umcb_approx( const graph& g_,
00325 const edge_array<W>& len_,
00326 int k_,
00327 array< Container >& mcb_,
00328 const mcb::edge_num& enumb_ )
00329 : base_type( g_, k_, mcb_, enumb_ ), len(len_)
00330 {
00331 }
00332
00333 weighted_umcb_approx( const graph& g_,
00334 int k_,
00335 array< Container >& mcb_,
00336 const mcb::edge_num& enumb_ )
00337 : base_type( g_, k_, mcb_, enumb_ ), len(g_,1)
00338 {
00339 }
00340
00341 virtual ~weighted_umcb_approx() {}
00342
00343 private:
00344
00345 virtual void checkEdgeLengthPreconditions() {
00346 #if ! defined(LEDA_CHECKING_OFF)
00347 edge e;
00348 forall_edges( e , g ) {
00349 if ( len[e] < 0 )
00350 error_handler(999,"UMCB_APPROX: illegal edge (negative weight?)");
00351 }
00352 #endif
00353 }
00354
00355 virtual void constructSpanner()
00356 {
00357 #ifdef LEP_STATS
00358 leda::used_time( Ttemp );
00359 #endif
00360 mcb::detail::SPANNER( g, len, k, spanner,
00361 node_g_to_spanner, node_spanner_to_g,
00362 edge_g_to_spanner, edge_spanner_to_g,
00363 enumb);
00364
00365
00366 edge e;
00367 spanner_len.init( spanner );
00368 forall_edges( e, spanner ) {
00369 spanner_len[ e ] = len[ edge_spanner_to_g[ e ] ];
00370 }
00371 }
00372
00373 virtual void constructPartialMCBfromSpanner( const edge_num& spanner_enumb, const array< Container >& spanner_mcb )
00374 {
00375 detail::ushortestpaths<W> usp( spanner, spanner_len );
00376 int i = 0;
00377 edge e, f;
00378 forall_edges( e, g ) {
00379 if ( edge_g_to_spanner[e] == nil ) {
00380 mcb[i] = Container();
00381
00382
00383 node spanner_s = node_g_to_spanner[ g.source(e) ];
00384 node spanner_t = node_g_to_spanner[ g.target(e) ];
00385 usp.compute_shortest_path( spanner_s, spanner_t );
00386
00387 #if ! defined(LEDA_CHECKING_OFF)
00388 assert( usp.is_reachable( spanner_t ) && usp.pred( spanner_s ) == nil );
00389 #endif
00390
00391
00392 W cycle_len = W();
00393 node spanner_w = spanner_t;
00394 while( usp.pred( spanner_w ) != nil ) {
00395 f = usp.pred( spanner_w );
00396 mcb[i].insert( enumb( edge_spanner_to_g[ f ] ) );
00397 cycle_len += len[ edge_spanner_to_g[ f ] ];
00398 spanner_w = spanner.opposite( f, spanner_w );
00399 }
00400 mcb[i].insert( enumb( e ) );
00401 cycle_len += len[ e ];
00402 mcb[i].sort();
00403
00404
00405 #if ! defined(LEDA_CHECKING_OFF)
00406 if ( cycle_len < 0 )
00407 error_handler(999,"UMCB_APPROX: computed cycle with negative length!");
00408 #endif
00409 length += cycle_len;
00410
00411 i++;
00412 }
00413 }
00414
00415 #ifdef LEP_STATS
00416 Tcycles += leda::used_time( Ttemp );
00417 #endif
00418 #ifdef LEP_DEBUG_OUTPUT
00419 std::cout << "Spanner has " << spanner.number_of_edges() << " edges..." << std::endl;
00420 std::cout << "Computed " << i << " cycles fast..." << std::endl;
00421 #endif
00422 }
00423
00424 private:
00425 const edge_array<W> len;
00426
00427 using base_type::g;
00428 using base_type::k;
00429 using base_type::length;
00430 using base_type::enumb;
00431 using base_type::mcb;
00432 using base_type::spanner;
00433 using base_type::spanner_len;
00434 using base_type::node_g_to_spanner;
00435 using base_type::node_spanner_to_g;
00436 using base_type::edge_g_to_spanner;
00437 using base_type::edge_spanner_to_g;
00438 };
00439
00440
00441 template<typename W>
00442 class weighted_dmcb_approx : public dmcb_approx<W>
00443 {
00444 public:
00445 typedef dmcb_approx<W> base_type;
00446
00447 weighted_dmcb_approx( const graph& g_,
00448 const edge_array<W>& len_,
00449 int k_,
00450 array< spvecfp >& mcb_,
00451 const mcb::edge_num& enumb_,
00452 double error )
00453 : base_type( g_, k_, mcb_, enumb_, error ), len(len_)
00454 {
00455 }
00456
00457 weighted_dmcb_approx( const graph& g_,
00458 int k_,
00459 array< spvecfp >& mcb_,
00460 const mcb::edge_num& enumb_,
00461 double error )
00462 : base_type( g_, k_, mcb_, enumb_, error ), len(g_,1)
00463 {
00464 }
00465
00466 weighted_dmcb_approx( const graph& g_,
00467 const edge_array<W>& len_,
00468 int k_,
00469 array< spvecfp >& mcb_,
00470 const mcb::edge_num& enumb_,
00471 ptype prime )
00472 : base_type( g_, k_, mcb_, enumb_, prime ), len(len_)
00473 {
00474 }
00475
00476 weighted_dmcb_approx( const graph& g_,
00477 int k_,
00478 array< spvecfp >& mcb_,
00479 const mcb::edge_num& enumb_,
00480 ptype prime )
00481 : base_type( g_, k_, mcb_, enumb_, prime ), len(g_,1)
00482 {
00483 }
00484
00485 virtual ~weighted_dmcb_approx() {}
00486
00487 private:
00488
00489 virtual void checkEdgeLengthPreconditions() {
00490 #if ! defined(LEDA_CHECKING_OFF)
00491 edge e;
00492 forall_edges( e , g ) {
00493 if ( len[e] < 0 )
00494 error_handler(999,"DMCB_APPROX: illegal edge (negative weight?)");
00495 }
00496 #endif
00497 }
00498
00499 virtual void constructSpanner()
00500 {
00501 #ifdef LEP_STATS
00502 leda::used_time( Ttemp );
00503 #endif
00504 mcb::detail::SPANNER( g, len, k, spanner,
00505 node_g_to_spanner, node_spanner_to_g,
00506 edge_g_to_spanner, edge_spanner_to_g,
00507 enumb);
00508
00509
00510 edge e;
00511 spanner_len.init( spanner );
00512 forall_edges( e, spanner ) {
00513 spanner_len[ e ] = len[ edge_spanner_to_g[ e ] ];
00514 }
00515 }
00516
00517 virtual void constructPartialMCBfromSpanner( const edge_num& spanner_enumb, const array< spvecfp >& spanner_mcb )
00518 {
00519 detail::ushortestpaths<W> usp( spanner, spanner_len );
00520 int i = 0;
00521 edge e, f;
00522 forall_edges( e, g ) {
00523 if ( edge_g_to_spanner[e] == nil ) {
00524 mcb[i] = mcb::spvecfp( base_type::getPrime( spanner_enumb, spanner_mcb ) );
00525
00526
00527 node spanner_s = node_g_to_spanner[ g.source(e) ];
00528 node spanner_t = node_g_to_spanner[ g.target(e) ];
00529 usp.compute_shortest_path( spanner_s, spanner_t );
00530
00531 #if ! defined(LEDA_CHECKING_OFF)
00532 assert( usp.is_reachable( spanner_t ) && usp.pred( spanner_s ) == nil );
00533 #endif
00534
00535
00536 node spanner_w = spanner_t;
00537 while( usp.pred( spanner_w ) != nil ) {
00538 f = usp.pred( spanner_w );
00539 if ( spanner_w == spanner.source(f) ) {
00540 mcb[i].append( enumb( edge_spanner_to_g[ f ] ), 1 );
00541 }
00542 else {
00543 mcb[i].append( enumb( edge_spanner_to_g[ f ] ), -1 );
00544 }
00545 length += len[ edge_spanner_to_g[ f ] ];
00546 spanner_w = spanner.opposite( f, spanner_w );
00547 }
00548 mcb[i].append( enumb( e ) , 1 );
00549 length += len[ e ];
00550 mcb[i].sort();
00551
00552 i++;
00553
00554 }
00555 }
00556
00557 #ifdef LEP_STATS
00558 Tcycles += leda::used_time( Ttemp );
00559 #endif
00560 #ifdef LEP_DEBUG_OUTPUT
00561 std::cout << "Spanner has " << spanner.number_of_edges() << " edges..." << std::endl;
00562 std::cout << "Computed " << i << " cycles fast..." << std::endl;
00563 #endif
00564 }
00565
00566 private:
00567 const edge_array<W> len;
00568
00569 using base_type::g;
00570 using base_type::k;
00571 using base_type::length;
00572 using base_type::enumb;
00573 using base_type::mcb;
00574 using base_type::spanner;
00575 using base_type::spanner_len;
00576 using base_type::node_g_to_spanner;
00577 using base_type::node_spanner_to_g;
00578 using base_type::edge_g_to_spanner;
00579 using base_type::edge_spanner_to_g;
00580 };
00581
00582
00583
00584
00585 template<class Container>
00586 class unweighted_umcb_approx : public weighted_umcb_approx<int,Container>
00587 {
00588 public:
00589 typedef weighted_umcb_approx<int,Container> base_type;
00590
00591 unweighted_umcb_approx( const graph& g_,
00592 int k_,
00593 array< Container >& mcb_,
00594 const mcb::edge_num& enumb_ )
00595 : base_type( g_, k_, mcb_, enumb_ )
00596 {
00597 }
00598
00599 ~unweighted_umcb_approx() {}
00600
00601 private:
00602
00603 virtual void checkEdgeLengthPreconditions() {}
00604
00605 virtual void constructPartialMCBfromSpanner( const edge_num& spanner_enumb, const array< Container >& spanner_mcb )
00606 {
00607 detail::ubfs usp( spanner );
00608 int i = 0;
00609 edge e, f;
00610 forall_edges( e, g ) {
00611 if ( edge_g_to_spanner[e] == nil ) {
00612 mcb[i] = Container();
00613
00614
00615 node spanner_s = node_g_to_spanner[ g.source(e) ];
00616 node spanner_t = node_g_to_spanner[ g.target(e) ];
00617 usp.compute_shortest_path( spanner_s, spanner_t, 2*k-1 );
00618
00619 #if ! defined(LEDA_CHECKING_OFF)
00620 assert( usp.is_reachable( spanner_t ) && usp.pred( spanner_s ) == nil );
00621 #endif
00622
00623
00624 node spanner_w = spanner_t;
00625 while( usp.pred( spanner_w ) != nil ) {
00626 f = usp.pred( spanner_w );
00627 mcb[i].insert( enumb( edge_spanner_to_g[ f ] ) );
00628 ++length;
00629 spanner_w = spanner.opposite( f, spanner_w );
00630 }
00631 mcb[i].insert( enumb( e ) );
00632 ++length;
00633 mcb[i].sort();
00634
00635 ++i;
00636 }
00637 }
00638
00639 #ifdef LEP_STATS
00640 Tcycles += leda::used_time( Ttemp );
00641 #endif
00642 #ifdef LEP_DEBUG_OUTPUT
00643 std::cout << "Spanner has " << spanner.number_of_edges() << " edges..." << std::endl;
00644 std::cout << "Computed " << i << " cycles fast..." << std::endl;
00645 #endif
00646 }
00647
00648 using base_type::g;
00649 using base_type::enumb;
00650 using base_type::mcb;
00651 using base_type::k;
00652 using base_type::length;
00653 using base_type::spanner;
00654 using base_type::edge_g_to_spanner;
00655 using base_type::edge_spanner_to_g;
00656 using base_type::node_g_to_spanner;
00657 };
00658
00691 template<class W>
00692 W UMCB_APPROX( const graph& g,
00693 const edge_array<W>& len,
00694 const int k,
00695 array< mcb::spvecgf2 >& mcb,
00696 const mcb::edge_num& enumb
00697 )
00698 {
00699 weighted_umcb_approx<W,mcb::spvecgf2> tmp( g, len, k, mcb, enumb );
00700 return tmp.run();
00701 }
00702
00703
00731 int UMCB_APPROX( const graph& g,
00732 const int k,
00733 array< mcb::spvecgf2 >& mcb,
00734 const mcb::edge_num& enumb
00735 );
00737
00738
00739
00777 template<class W>
00778 W DMCB_APPROX( const graph& g,
00779 const edge_array<W>& len,
00780 const int k,
00781 array< mcb::spvecfp >& mcb,
00782 const mcb::edge_num& enumb,
00783 double error = 0.375
00784 )
00785 {
00786 weighted_dmcb_approx<W> tmp( g, len, k, mcb, enumb, error );
00787 return tmp.run();
00788 }
00789
00820 template<class W>
00821 W DMCB_APPROX( const graph& g,
00822 const edge_array<W>& len,
00823 const int k,
00824 array< mcb::spvecfp >& mcb,
00825 const mcb::edge_num& enumb,
00826 mcb::ptype prime
00827 )
00828 {
00829 weighted_dmcb_approx<W> tmp( g, len, k, mcb, enumb, prime );
00830 return tmp.run();
00831 }
00832
00833
00835
00836
00844
00869 template<class W>
00870 W UMCB( const graph& g,
00871 const edge_array<W>& len,
00872 array< mcb::spvecgf2 >& mcb,
00873 const mcb::edge_num& enumb
00874 )
00875 {
00876 return UMCB_APPROX<W>( g, len, 1, mcb, enumb );
00877 }
00878
00902 int UMCB( const graph& g,
00903 array< mcb::spvecgf2 >& mcb,
00904 const mcb::edge_num& enumb
00905 );
00907
00908 }
00909
00910 #endif // UMCB_APPROX_H
00911
00912
00913
00914