41 #include <LEP/mcb/config.h> 43 #include <LEP/mcb/spanner.h> 44 #include <LEP/mcb/ushortpath.h> 48 #include <LEDA/graph/edge_map.h> 49 #include <LEDA/graph/node_map.h> 51 #include <LEDA/edge_map.h> 52 #include <LEDA/node_map.h> 58 #if defined(LEDA_NAMESPACE) 62 using leda::edge_array;
67 template<
typename W,
class Container>
70 typedef W result_type;
72 mcb_approx(
const graph& g_,
74 array< Container >& mcb_,
76 : g(g_), k(k_),
mcb(mcb_), enumb(enumb_), Tcycles(0.0), Tsubgraph(0.0)
80 virtual ~mcb_approx() {}
83 checkGraphPreconditions();
84 checkEdgeLengthPreconditions();
89 edge_num spanner_enumb( spanner );
90 array< Container > spanner_mcb;
91 constructSpannerMCB( spanner_enumb, spanner_mcb );
93 constructPartialMCBfromSpanner( spanner_enumb, spanner_mcb );
94 translateSpannerMCBToGraphPartialMCB( spanner_enumb, spanner_mcb );
101 void checkGraphPreconditions() {
102 #if ! defined(LEDA_CHECKING_OFF) 103 if ( Is_Loopfree( g ) ==
false )
104 error_handler(999,
"UMCB_APPROX: illegal graph (loops?)");
106 error_handler(999,
"UMCB_APPROX: illegal value of k, non-positive?");
110 virtual void checkEdgeLengthPreconditions() {}
114 N = enumb.dim_cycle_space();
118 virtual void constructSpanner() = 0;
120 virtual void constructSpannerMCB(
const edge_num& spanner_enumb, array< Container >& spanner_mcb ) = 0;
122 virtual void constructPartialMCBfromSpanner(
const edge_num& spanner_enumb,
const array< Container >& spanner_mcb ) = 0;
124 virtual void translateSpannerMCBToGraphPartialMCB(
const edge_num& spanner_enumb,
125 const array<Container>& spanner_mcb ) = 0;
130 array< Container >&
mcb;
137 edge_array<W> spanner_len;
138 node_map<node> node_g_to_spanner;
139 node_map<node> node_spanner_to_g;
140 edge_map<edge> edge_g_to_spanner;
141 edge_map<edge> edge_spanner_to_g;
144 float Tcycles, Tsubgraph, Ttemp;
149 template<
typename W,
class Container>
150 class umcb_approx :
public mcb_approx< W, Container >
153 typedef mcb_approx<W,Container> base_type;
155 umcb_approx(
const graph& g_,
157 array< Container >& mcb_,
159 : base_type( g_, k_, mcb_, enumb_ )
167 virtual void constructSpannerMCB(
const edge_num& spanner_enumb, array<Container>& spanner_mcb )
169 array< Container > spanner_proof;
171 #ifdef LEP_DEBUG_OUTPUT 172 std::cout <<
"Computing " << spanner_enumb.dim_cycle_space() <<
" cycles";
173 std::cout <<
" by the MCB of spanner..." << std::endl;
176 length += UMCB_SVA<W,Container>( spanner, spanner_len,
177 spanner_mcb, spanner_proof, spanner_enumb );
180 virtual void translateSpannerMCBToGraphPartialMCB(
const edge_num& spanner_enumb,
181 const array<Container>& spanner_mcb )
184 int extracycles = spanner_enumb.dim_cycle_space();
185 for(
int i = 0; i < extracycles; ++i )
187 mcb[ N - extracycles + i ] = Container();
190 forall( j, spanner_mcb[ i ] )
194 e = edge_spanner_to_g[ spanner_enumb(j) ];
195 mcb[ N - extracycles + i ].insert( enumb( e ) );
198 mcb[ N - extracycles + i ].sort();
202 Tsubgraph += leda::used_time( Ttemp );
203 std::cout <<
"LEP_STATS: spanner cycles time: " << Tcycles << std::endl;
204 std::cout <<
"LEP_STATS: subgraph MCB time : " << Tsubgraph << std::endl;
208 using base_type::length;
209 using base_type::spanner;
210 using base_type::spanner_len;
212 using base_type::mcb;
213 using base_type::edge_spanner_to_g;
214 using base_type::enumb;
219 class dmcb_approx :
public mcb_approx<W,mcb::spvecfp>
222 typedef mcb_approx<W,mcb::spvecfp> base_type;
224 dmcb_approx(
const graph& g_,
226 array< mcb::spvecfp >& mcb_,
230 : base_type( g_, k_, mcb_, enumb_ ), error(error_), prime(3), minimizeErrorProb(true)
234 dmcb_approx(
const graph& g_,
236 array< mcb::spvecfp >& mcb_,
240 : base_type( g_, k_, mcb_, enumb_ ), error(0.375), prime(prime_), minimizeErrorProb(false)
248 ptype getPrime(
const edge_num& spanner_enumb,
const array<mcb::spvecfp>& spanner_mcb )
250 return ( spanner_enumb.dim_cycle_space() > 0 ) ? spanner_mcb[0].pvalue() : 3;
255 virtual void constructSpannerMCB(
const edge_num& spanner_enumb, array<mcb::spvecfp>& spanner_mcb )
257 array<spvecfp> spanner_proof;
259 #ifdef LEP_DEBUG_OUTPUT 260 std::cout <<
"Computing " << spanner_enumb.dim_cycle_space() <<
" cycles";
261 std::cout <<
" by the MCB of spanner..." << std::endl;
264 if ( minimizeErrorProb )
265 length += DMCB<W>( spanner, spanner_len,
266 spanner_mcb, spanner_proof, spanner_enumb, error );
268 length += DMCB<W>( spanner, spanner_len,
269 spanner_mcb, spanner_proof, spanner_enumb, prime );
273 virtual void translateSpannerMCBToGraphPartialMCB(
const edge_num& spanner_enumb,
274 const array<spvecfp>& spanner_mcb )
277 int extracycles = spanner_enumb.dim_cycle_space();
278 for(
int i = 0; i < extracycles; ++i )
280 mcb[ N - extracycles + i] =
mcb::spvecfp( getPrime( spanner_enumb, spanner_mcb ) );
282 leda::list_item it = spanner_mcb[i].first();
284 e = edge_spanner_to_g[ spanner_enumb( spanner_mcb[i].index( it ) ) ];
285 mcb[ N - extracycles + i ].append( enumb(e), spanner_mcb[i].inf( it ) );
286 it = spanner_mcb[i].succ( it );
288 mcb[ N - extracycles + i ].sort();
292 Tsubgraph += leda::used_time( Ttemp );
293 std::cout <<
"LEP_STATS: spanner cycles time: " << Tcycles << std::endl;
294 std::cout <<
"LEP_STATS: subgraph MCB time : " << Tsubgraph << std::endl;
298 using base_type::length;
299 using base_type::spanner;
300 using base_type::spanner_len;
302 using base_type::mcb;
303 using base_type::edge_spanner_to_g;
304 using base_type::enumb;
309 bool minimizeErrorProb;
316 template<
typename W,
class Container>
317 class weighted_umcb_approx :
public umcb_approx<W,Container>
320 typedef umcb_approx<W,Container> base_type;
322 weighted_umcb_approx(
const graph& g_,
323 const edge_array<W>& len_,
325 array< Container >& mcb_,
327 : base_type( g_, k_, mcb_, enumb_ ), len(len_)
331 weighted_umcb_approx(
const graph& g_,
333 array< Container >& mcb_,
335 : base_type( g_, k_, mcb_, enumb_ ), len(g_,1)
339 virtual ~weighted_umcb_approx() {}
343 virtual void checkEdgeLengthPreconditions() {
344 #if ! defined(LEDA_CHECKING_OFF) 346 forall_edges( e , g ) {
348 error_handler(999,
"UMCB_APPROX: illegal edge (negative weight?)");
353 virtual void constructSpanner()
356 leda::used_time( Ttemp );
358 mcb::detail::SPANNER( g, len, k, spanner,
359 node_g_to_spanner, node_spanner_to_g,
360 edge_g_to_spanner, edge_spanner_to_g,
365 spanner_len.init( spanner );
366 forall_edges( e, spanner ) {
367 spanner_len[ e ] = len[ edge_spanner_to_g[ e ] ];
371 virtual void constructPartialMCBfromSpanner(
const edge_num& spanner_enumb,
const array< Container >& spanner_mcb )
373 detail::ushortestpaths<W> usp( spanner, spanner_len );
376 forall_edges( e, g ) {
377 if ( edge_g_to_spanner[e] == nil ) {
378 mcb[i] = Container();
381 node spanner_s = node_g_to_spanner[ g.source(e) ];
382 node spanner_t = node_g_to_spanner[ g.target(e) ];
383 usp.compute_shortest_path( spanner_s, spanner_t );
385 #if ! defined(LEDA_CHECKING_OFF) 386 assert( usp.is_reachable( spanner_t ) && usp.pred( spanner_s ) == nil );
391 node spanner_w = spanner_t;
392 while( usp.pred( spanner_w ) != nil ) {
393 f = usp.pred( spanner_w );
394 mcb[i].insert( enumb( edge_spanner_to_g[ f ] ) );
395 cycle_len += len[ edge_spanner_to_g[ f ] ];
396 spanner_w = spanner.opposite( f, spanner_w );
398 mcb[i].insert( enumb( e ) );
399 cycle_len += len[ e ];
403 #if ! defined(LEDA_CHECKING_OFF) 405 error_handler(999,
"UMCB_APPROX: computed cycle with negative length!");
414 Tcycles += leda::used_time( Ttemp );
416 #ifdef LEP_DEBUG_OUTPUT 417 std::cout <<
"Spanner has " << spanner.number_of_edges() <<
" edges..." << std::endl;
418 std::cout <<
"Computed " << i <<
" cycles fast..." << std::endl;
423 const edge_array<W> len;
427 using base_type::length;
428 using base_type::enumb;
429 using base_type::mcb;
430 using base_type::spanner;
431 using base_type::spanner_len;
432 using base_type::node_g_to_spanner;
433 using base_type::node_spanner_to_g;
434 using base_type::edge_g_to_spanner;
435 using base_type::edge_spanner_to_g;
440 class weighted_dmcb_approx :
public dmcb_approx<W>
443 typedef dmcb_approx<W> base_type;
445 weighted_dmcb_approx(
const graph& g_,
446 const edge_array<W>& len_,
448 array< spvecfp >& mcb_,
451 : base_type( g_, k_, mcb_, enumb_, error ), len(len_)
455 weighted_dmcb_approx(
const graph& g_,
457 array< spvecfp >& mcb_,
460 : base_type( g_, k_, mcb_, enumb_, error ), len(g_,1)
464 weighted_dmcb_approx(
const graph& g_,
465 const edge_array<W>& len_,
467 array< spvecfp >& mcb_,
470 : base_type( g_, k_, mcb_, enumb_, prime ), len(len_)
474 weighted_dmcb_approx(
const graph& g_,
476 array< spvecfp >& mcb_,
479 : base_type( g_, k_, mcb_, enumb_, prime ), len(g_,1)
483 virtual ~weighted_dmcb_approx() {}
487 virtual void checkEdgeLengthPreconditions() {
488 #if ! defined(LEDA_CHECKING_OFF) 490 forall_edges( e , g ) {
492 error_handler(999,
"DMCB_APPROX: illegal edge (negative weight?)");
497 virtual void constructSpanner()
500 leda::used_time( Ttemp );
502 mcb::detail::SPANNER( g, len, k, spanner,
503 node_g_to_spanner, node_spanner_to_g,
504 edge_g_to_spanner, edge_spanner_to_g,
509 spanner_len.init( spanner );
510 forall_edges( e, spanner ) {
511 spanner_len[ e ] = len[ edge_spanner_to_g[ e ] ];
515 virtual void constructPartialMCBfromSpanner(
const edge_num& spanner_enumb,
const array< spvecfp >& spanner_mcb )
517 detail::ushortestpaths<W> usp( spanner, spanner_len );
520 forall_edges( e, g ) {
521 if ( edge_g_to_spanner[e] == nil ) {
522 mcb[i] =
mcb::spvecfp( base_type::getPrime( spanner_enumb, spanner_mcb ) );
525 node spanner_s = node_g_to_spanner[ g.source(e) ];
526 node spanner_t = node_g_to_spanner[ g.target(e) ];
527 usp.compute_shortest_path( spanner_s, spanner_t );
529 #if ! defined(LEDA_CHECKING_OFF) 530 assert( usp.is_reachable( spanner_t ) && usp.pred( spanner_s ) == nil );
534 node spanner_w = spanner_t;
535 while( usp.pred( spanner_w ) != nil ) {
536 f = usp.pred( spanner_w );
537 if ( spanner_w == spanner.source(f) ) {
538 mcb[i].append( enumb( edge_spanner_to_g[ f ] ), 1 );
541 mcb[i].append( enumb( edge_spanner_to_g[ f ] ), -1 );
543 length += len[ edge_spanner_to_g[ f ] ];
544 spanner_w = spanner.opposite( f, spanner_w );
546 mcb[i].append( enumb( e ) , 1 );
556 Tcycles += leda::used_time( Ttemp );
558 #ifdef LEP_DEBUG_OUTPUT 559 std::cout <<
"Spanner has " << spanner.number_of_edges() <<
" edges..." << std::endl;
560 std::cout <<
"Computed " << i <<
" cycles fast..." << std::endl;
565 const edge_array<W> len;
569 using base_type::length;
570 using base_type::enumb;
571 using base_type::mcb;
572 using base_type::spanner;
573 using base_type::spanner_len;
574 using base_type::node_g_to_spanner;
575 using base_type::node_spanner_to_g;
576 using base_type::edge_g_to_spanner;
577 using base_type::edge_spanner_to_g;
583 template<
class Container>
584 class unweighted_umcb_approx :
public weighted_umcb_approx<int,Container>
587 typedef weighted_umcb_approx<int,Container> base_type;
589 unweighted_umcb_approx(
const graph& g_,
591 array< Container >& mcb_,
593 : base_type( g_, k_, mcb_, enumb_ )
597 ~unweighted_umcb_approx() {}
601 virtual void checkEdgeLengthPreconditions() {}
603 virtual void constructPartialMCBfromSpanner(
const edge_num& spanner_enumb,
const array< Container >& spanner_mcb )
605 detail::ubfs usp( spanner );
608 forall_edges( e, g ) {
609 if ( edge_g_to_spanner[e] == nil ) {
610 mcb[i] = Container();
613 node spanner_s = node_g_to_spanner[ g.source(e) ];
614 node spanner_t = node_g_to_spanner[ g.target(e) ];
615 usp.compute_shortest_path( spanner_s, spanner_t, 2*k-1 );
617 #if ! defined(LEDA_CHECKING_OFF) 618 assert( usp.is_reachable( spanner_t ) && usp.pred( spanner_s ) == nil );
622 node spanner_w = spanner_t;
623 while( usp.pred( spanner_w ) != nil ) {
624 f = usp.pred( spanner_w );
625 mcb[i].insert( enumb( edge_spanner_to_g[ f ] ) );
627 spanner_w = spanner.opposite( f, spanner_w );
629 mcb[i].insert( enumb( e ) );
638 Tcycles += leda::used_time( Ttemp );
640 #ifdef LEP_DEBUG_OUTPUT 641 std::cout <<
"Spanner has " << spanner.number_of_edges() <<
" edges..." << std::endl;
642 std::cout <<
"Computed " << i <<
" cycles fast..." << std::endl;
647 using base_type::enumb;
648 using base_type::mcb;
650 using base_type::length;
651 using base_type::spanner;
652 using base_type::edge_g_to_spanner;
653 using base_type::edge_spanner_to_g;
654 using base_type::node_g_to_spanner;
691 const edge_array<W>& len,
693 array< mcb::spvecgf2 >&
mcb,
697 weighted_umcb_approx<W,mcb::spvecgf2> tmp( g, len, k, mcb, enumb );
731 array< mcb::spvecgf2 >&
mcb,
777 const edge_array<W>& len,
779 array< mcb::spvecfp >& mcb,
784 weighted_dmcb_approx<W> tmp( g, len, k, mcb, enumb, error );
820 const edge_array<W>& len,
822 array< mcb::spvecfp >& mcb,
827 weighted_dmcb_approx<W> tmp( g, len, k, mcb, enumb, prime );
869 const edge_array<W>& len,
870 array< mcb::spvecgf2 >& mcb,
874 return UMCB_APPROX<W>( g, len, 1, mcb, enumb );
900 int UMCB(
const graph& g,
901 array< mcb::spvecgf2 >& mcb,
908 #endif // UMCB_APPROX_H W UMCB_APPROX(const graph &g, const edge_array< W > &len, const int k, array< mcb::spvecgf2 > &mcb, const mcb::edge_num &enumb)
Compute an undirected approximate MCB of a weighted graph.
Definition: mcb_approx.h:690
An edge numbering class.
Definition: edge_num.h:75
The main package namespace.
Algorithms for undirected MCB.
W DMCB_APPROX(const graph &g, const edge_array< W > &len, const int k, array< mcb::spvecfp > &mcb, const mcb::edge_num &enumb, double error=0.375)
Compute a directed approximate MCB of a weighted graph.
Definition: mcb_approx.h:776
A sparse vector with elements in .
Definition: spvecfp.h:87
leda::integer ptype
Definition: arithm.h:58
Algorithms for directed MCB.
W UMCB(const graph &g, const edge_array< W > &len, array< mcb::spvecgf2 > &mcb, const mcb::edge_num &enumb)
Compute an MCB of an undirected graph (possible a multigraph) using the most general implementation o...
Definition: mcb_approx.h:868