00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #ifndef VCSN_ALGORITHMS_EPS_REMOVAL_HXX
00018 # define VCSN_ALGORITHMS_EPS_REMOVAL_HXX
00019
00020 # include <vaucanson/algorithms/eps_removal.hh>
00021
00022 # include <vaucanson/automata/concept/automata_base.hh>
00023 # include <vaucanson/algebra/concept/freemonoid_product.hh>
00024 # include <vaucanson/misc/usual_macros.hh>
00025
00026 # include <list>
00027 # include <map>
00028 # include <utility>
00029
00030 namespace vcsn {
00031
00032
00033 template <class A, typename M, typename AI>
00034 bool
00035 do_is_proper(const AutomataBase<A>&, const M&, const Element<A, AI>& a)
00036 {
00037 BENCH_TASK_SCOPED("is_proper (automaton)");
00038 typedef Element<A, AI> automaton_t;
00039 AUTOMATON_TYPES(automaton_t);
00040
00041 for_all_const_transitions(e, a)
00042 {
00043
00044
00045
00046 series_set_elt_t label = a.series_of(*e);
00047 for_all_const_(series_set_elt_t::support_t, it, label.supp())
00048 if ((*it).empty())
00049 return false;
00050 }
00051 return true;
00052 }
00053
00054
00055 template <class A, typename F, typename S, typename AI>
00056 bool
00057 do_is_proper(const AutomataBase<A>&,
00058 const algebra::FreeMonoidProduct<F, S>&,
00059 const Element<A, AI>& a)
00060 {
00061 BENCH_TASK_SCOPED("is_proper (FMP)");
00062 typedef Element<A, AI> automaton_t;
00063 AUTOMATON_TYPES(automaton_t);
00064
00065 for_all_const_transitions(e, a)
00066 {
00067 series_set_elt_t label = a.series_of(*e);
00068 for_all_const_(series_set_elt_t::support_t, it, label.supp())
00069 if ((*it).first.empty() && (*it).second.empty())
00070 return false;
00071 }
00072 return true;
00073 }
00074
00075 template <typename A, typename AI>
00076 bool
00077 is_proper(const Element<A, AI>& a)
00078 {
00079 return do_is_proper(a.structure(), a.series().monoid(), a);
00080 }
00081
00082
00083
00084 template <class A_, typename Auto, typename Weight>
00085 class EpsilonRemover;
00086
00087 template <class A_, typename Auto, typename Weight, int>
00088 struct test_for_non_positive_semiring
00089 {
00090 bool run(const Auto&) const
00091 {
00092 return true;
00093 }
00094 };
00095
00096 template <class A_, typename Auto, typename Weight>
00097 struct test_for_non_positive_semiring<A_, Auto, Weight, 0>
00098 {
00099 bool run(const Auto& a) const;
00100 };
00101
00102
00103
00104
00105
00106 template <class A_, typename Auto, typename Weight>
00107 class EpsilonRemover
00108 {
00109 AUTOMATON_TYPES(Auto);
00110 typedef typename series_set_elt_t::support_t support_t;
00111
00112 friend struct test_for_non_positive_semiring
00113 <A_, Auto, Weight, semiring_traits<semiring_t,
00114 semiring_elt_value_t>::is_positive>;
00115
00116
00117 automaton_t& a;
00118
00119 series_set_elt_t null_series;
00120 semiring_elt_t semiring_elt_zero,
00121 semiring_elt_unit;
00122 monoid_elt_t monoid_identity;
00123
00124
00125 public:
00126 EpsilonRemover(const AutomataBase<A_>&,
00127 Auto& aut)
00128 : a(aut),
00129 null_series(aut.series().zero_),
00130 semiring_elt_zero(aut.series().semiring().wzero_),
00131 semiring_elt_unit(aut.series().semiring().wone_),
00132 monoid_identity(aut.series().monoid().VCSN_EMPTY_)
00133 {}
00134
00135 void operator()(misc::direction_type dir)
00136 {
00137 test_for_non_positive_semiring
00138 <A_, Auto, Weight, semiring_traits<semiring_t,
00139 semiring_elt_value_t>::is_positive>
00140 nps;
00141 result_not_computable_if(!nps.run(a));
00142 std::list<hstate_t> eps_states;
00143 if (dir == misc::backward)
00144 this->epsilon_covering(eps_states);
00145 else
00146 this->epsilon_co_covering(eps_states);
00147 result_not_computable_if(!spontaneous_suppression(eps_states));
00148 merge_transitions();
00149 }
00150
00151 private:
00152
00153
00154
00155
00156
00157
00158
00159 void epsilon_covering(std::list<hstate_t>& spontaneous_states)
00160 {
00161
00162 std::list<hstate_t> split_states;
00163 for_all_states(s, a)
00164 {
00165 bool eps_in = false;
00166 bool other_in = a.is_initial(*s);
00167
00168
00169
00170 std::list<htransition_t> transitions;
00171 for (rdelta_iterator e(a.value(), *s); ! e.done(); e.next())
00172 transitions.push_back(*e);
00173 for_all_(std::list<htransition_t>, e, transitions)
00174 {
00175 series_set_elt_t t = a.series_of(*e);
00176 semiring_elt_t eps_weight= t.get(monoid_identity);
00177 if (eps_weight == semiring_elt_zero)
00178 other_in = true ;
00179 else
00180 {
00181 eps_in=true;
00182 if (t.supp().size() > 1)
00183 other_in = true;
00184 }
00185 }
00186 if (eps_in)
00187 {
00188 if (other_in)
00189 split_states.push_back(*s);
00190 else
00191 spontaneous_states.push_back(*s);
00192 }
00193 }
00194
00195 for_all_(std::list<hstate_t>, s, split_states)
00196 {
00197 hstate_t eps_state = a.add_state();
00198 spontaneous_states.push_back(eps_state);
00199
00200 std::list<htransition_t> transitions;
00201 for (rdelta_iterator e(a.value(), *s); ! e.done(); e.next())
00202 transitions.push_back(*e);
00203 for_all_(std::list<htransition_t>, e, transitions)
00204 {
00205 series_set_elt_t t = a.series_of(*e);
00206 semiring_elt_t eps_weight= t.get(monoid_identity);
00207 if (eps_weight == semiring_elt_zero)
00208 continue;
00209 series_set_elt_t eps_label(a.structure().series());
00210 eps_label.assoc(monoid_identity.value(), eps_weight.value());
00211
00212 t.assoc(monoid_identity.value(), semiring_elt_zero.value());
00213 hstate_t source=a.src_of(*e);
00214 a.add_series_transition(source, eps_state, eps_label);
00215 if (t != null_series)
00216 a.add_series_transition(source, *s, t);
00217 a.del_transition(*e);
00218 }
00219
00220 if (a.is_final(*s))
00221 a.set_final(eps_state,a.get_final(*s));
00222 for (delta_iterator e(a.value(), *s); ! e.done(); e.next())
00223 a.add_series_transition(eps_state, a.dst_of(*e), a.series_of(*e));
00224
00225
00226
00227
00228
00229
00230
00231 }
00232 }
00233
00234
00235
00236
00237
00238 void initial_final_cleaner()
00239 {
00240 {
00241
00242 std::list<hstate_t> initial_states;
00243 for_all_initial_states(s, a)
00244 initial_states.push_back(*s);
00245 hstate_t new_initial=a.add_state();
00246 for_all_(std::list<hstate_t>, s, initial_states)
00247 {
00248 series_set_elt_t t = a.get_initial(*s);
00249 semiring_elt_t eps_weight= t.get(monoid_identity);
00250 t.assoc(monoid_identity, semiring_elt_zero.value());
00251 if (t != null_series)
00252 {
00253 a.unset_initial(*s);
00254 a.add_series_transition(new_initial, *s, t);
00255 if (eps_weight != semiring_elt_zero)
00256 {
00257 series_set_elt_t cst(a.structure().series());
00258 cst.assoc(monoid_identity, eps_weight.value());
00259 a.set_initial(*s, cst);
00260 }
00261 }
00262 }
00263 delta_iterator test(a.value(), new_initial);
00264 if (test.done())
00265 a.del_state(new_initial);
00266 else
00267 a.set_initial(new_initial);
00268 }
00269 {
00270
00271 std::list<hstate_t> final_states;
00272 for_all_final_states(s, a)
00273 final_states.push_back(*s);
00274 hstate_t new_final=a.add_state();
00275 for_all_(std::list<hstate_t>, s, final_states)
00276 {
00277 series_set_elt_t t = a.get_final(*s);
00278 semiring_elt_t eps_weight= t.get(monoid_identity);
00279 t.assoc(monoid_identity, semiring_elt_zero.value());
00280 if (t != null_series)
00281 {
00282 a.unset_final(*s);
00283 a.add_series_transition(*s, new_final, t);
00284 if(eps_weight != semiring_elt_zero)
00285 {
00286 series_set_elt_t cst(a.structure().series());
00287 cst.assoc(monoid_identity, eps_weight.value());
00288 a.set_final(*s, cst);
00289 }
00290 }
00291 }
00292 rdelta_iterator test(a.value(), new_final);
00293 if (test.done())
00294 a.del_state(new_final);
00295 else
00296 a.set_final(new_final);
00297 }
00298 }
00299
00300
00301
00302
00303
00304
00305
00306 void epsilon_co_covering(std::list<hstate_t>& spontaneous_states)
00307 {
00308
00309 std::list<hstate_t> split_states;
00310 for_all_states(s, a)
00311 {
00312 bool eps_out = false;
00313 bool other_out = a.is_final(*s);
00314
00315
00316
00317 std::list<htransition_t> transitions;
00318 for (delta_iterator e(a.value(), *s); !e.done(); e.next())
00319 transitions.push_back(*e);
00320 for_all_(std::list<htransition_t>, e, transitions)
00321 {
00322 series_set_elt_t t = a.series_of(*e);
00323 semiring_elt_t eps_weight= t.get(monoid_identity);
00324 if(eps_weight == semiring_elt_zero)
00325 other_out=true ;
00326 else
00327 {
00328 eps_out=true;
00329 if (t.supp().size() > 1)
00330 other_out=true;
00331 }
00332 }
00333 if (eps_out)
00334 {
00335 if (other_out)
00336 split_states.push_back(*s);
00337 else
00338 spontaneous_states.push_back(*s);
00339 }
00340 }
00341
00342 for_all_(std::list<hstate_t>, s, split_states)
00343 {
00344 hstate_t eps_state = a.add_state();
00345 spontaneous_states.push_back(eps_state);
00346
00347 std::list<htransition_t> transitions;
00348 for (delta_iterator e(a.value(), *s); !e.done(); e.next())
00349 transitions.push_back(*e);
00350 for_all_(std::list<htransition_t>, e, transitions)
00351 {
00352 series_set_elt_t t = a.series_of(*e);
00353 semiring_elt_t eps_weight= t.get(monoid_identity);
00354 if (eps_weight == semiring_elt_zero)
00355 continue;
00356 series_set_elt_t eps_label(a.structure().series());
00357 eps_label.assoc(monoid_identity.value(), eps_weight.value());
00358
00359 t.assoc(monoid_identity.value(), semiring_elt_zero.value());
00360 hstate_t target=a.dst_of(*e);
00361 a.add_series_transition(eps_state, target, eps_label);
00362 if (t != null_series)
00363 a.add_series_transition(*s, target, t);
00364 a.del_transition(*e);
00365 }
00366
00367 if (a.is_initial(*s))
00368 a.set_initial(eps_state,a.get_initial(*s));
00369 for (rdelta_iterator e(a.value(), *s); ! e.done(); e.next())
00370 a.add_series_transition(a.src_of(*e), eps_state, a.series_of(*e));
00371
00372
00373
00374
00375
00376
00377
00378 }
00379 }
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389 void positive_path_covering()
00390 {
00391 std::map<hstate_t,hstate_t> clones;
00392 std::list<hstate_t> states;
00393 for_all_states(s, a)
00394 states.push_back(*s);
00395 for_all_(std::list<hstate_t>, s, states)
00396 clones[*s]=a.add_state();
00397 hstate_t pos_final_state=a.add_state();
00398 hstate_t neg_final_state=a.add_state();
00399 std::list<htransition_t> transitions;
00400 for_all_transitions(e, a)
00401 transitions.push_back(*e);
00402 for_all_(std::list<htransition_t>, e, transitions)
00403 {
00404 series_set_elt_t posit = a.series_of(*e);
00405 series_set_elt_t negat(a.structure().series());
00406 support_t su = posit.supp();
00407 for_all_(support_t, x, su)
00408 {
00409 semiring_elt_t weight=posit.get(*x);
00410 if (weight < semiring_elt_zero)
00411 {
00412 negat.assoc(*x,-weight.value());
00413 posit.assoc(*x,semiring_elt_zero.value());
00414 }
00415 }
00416 hstate_t src=a.src_of(*e), dst=a.dst_of(*e);
00417 if (posit != null_series)
00418 a.add_series_transition(clones[src], clones[dst], posit);
00419 if (negat != null_series)
00420 {
00421 a.add_series_transition(src, clones[dst], negat);
00422 a.add_series_transition(clones[src], dst, negat);
00423 if (posit != null_series)
00424 a.add_series_transition(src, dst, posit);
00425 a.del_transition(*e);
00426 }
00427 }
00428 states.clear();
00429 for_all_initial_states(s, a)
00430 states.push_back(*s);
00431 for_all_(std::list<hstate_t>, s, states)
00432 {
00433 series_set_elt_t posit = a.get_initial(*s);
00434 series_set_elt_t negat(a.structure().series());
00435 support_t su = posit.supp();
00436 for_all_(support_t, x, su)
00437 {
00438 semiring_elt_t weight = posit.get(*x);
00439 if (weight < semiring_elt_zero)
00440 {
00441 negat.assoc(*x,-weight.value());
00442 posit.assoc(*x,semiring_elt_zero.value());
00443 }
00444 }
00445 if (negat != null_series)
00446 {
00447 a.set_initial(clones[*s], negat);
00448 a.unset_initial(*s);
00449 if (posit != null_series)
00450 a.set_initial(*s,posit);
00451 }
00452 }
00453 states.clear();
00454 for_all_final_states(s, a)
00455 states.push_back(*s);
00456 for_all_(std::list<hstate_t>, s, states)
00457 {
00458 series_set_elt_t posit = a.get_final(*s);
00459 series_set_elt_t negat(a.structure().series());
00460 support_t su = posit.supp();
00461 for_all_(support_t, x, su)
00462 {
00463 semiring_elt_t weight=posit.get(*x);
00464 if (weight < semiring_elt_zero)
00465 {
00466 negat.assoc(*x,-weight.value());
00467 posit.assoc(*x,semiring_elt_zero.value());
00468 }
00469 }
00470 if (negat != null_series)
00471 {
00472 a.add_series_transition(*s, neg_final_state, negat);
00473 a.add_series_transition(clones[*s], pos_final_state, negat);
00474 }
00475 a.unset_final(*s);
00476 if (posit != null_series)
00477 {
00478 a.add_series_transition(*s, pos_final_state, posit);
00479 a.add_series_transition(clones[*s], neg_final_state, posit);
00480 }
00481 }
00482 a.set_final(pos_final_state);
00483 series_set_elt_t mss = a.get_final(pos_final_state);
00484 mss.assoc(monoid_identity,-semiring_elt_unit.value());
00485 a.set_final(neg_final_state,mss);
00486 accessible_here(a);
00487 }
00488
00489
00490
00491 void absolute_weight()
00492 {
00493 std::list<htransition_t> transitions;
00494 for_all_transitions(e, a)
00495 transitions.push_back(*e);
00496 for_all_(std::list<htransition_t>, e, transitions)
00497 {
00498 series_set_elt_t label = a.series_of(*e);
00499 support_t support = label.supp();
00500 for_all_(support_t, x, support)
00501 {
00502 semiring_elt_t weight=label.get(*x);
00503 if (weight < semiring_elt_zero)
00504 label.assoc(*x,-weight.value());
00505 }
00506 hstate_t src=a.src_of(*e), dst=a.dst_of(*e);
00507 a.del_transition(*e);
00508 a.add_series_transition(src, dst, label);
00509 }
00510 std::list<hstate_t> states;
00511 for_all_initial_states(s, a)
00512 states.push_back(*s);
00513 for_all_(std::list<hstate_t>, s, states)
00514 {
00515 series_set_elt_t label = a.get_initial(*s);
00516 support_t support = label.supp();
00517 for_all_(support_t, x, support)
00518 {
00519 semiring_elt_t weight = label.get(*x);
00520 if (weight < semiring_elt_zero)
00521 label.assoc(*x,-weight.value());
00522 }
00523 a.set_initial(*s,label);
00524 }
00525 states.clear();
00526 for_all_final_states(s, a)
00527 states.push_back(*s);
00528 for_all_(std::list<hstate_t>, s, states)
00529 {
00530 series_set_elt_t label = a.get_final(*s);
00531 support_t support = label.supp();
00532 for_all_(support_t, x, support)
00533 {
00534 semiring_elt_t weight = label.get(*x);
00535 if (weight < semiring_elt_zero)
00536 label.assoc(*x,-weight.value());
00537 }
00538 a.set_final(*s,label);
00539 }
00540 }
00541
00542
00543
00544
00545
00546
00547
00548
00549 bool spontaneous_suppression(std::list<hstate_t>& sp_states)
00550 {
00551 for_all_(std::list<hstate_t>, s, sp_states)
00552 {
00553 std::list<htransition_t> incoming_transitions;
00554
00555 for (rdelta_iterator e(a.value(), *s); ! e.done(); e.next())
00556 {
00557 if (a.src_of(*e) == a.dst_of(*e))
00558 incoming_transitions.push_front(*e);
00559 else
00560 incoming_transitions.push_back(*e);
00561 }
00562 bool hasloop=false;
00563 series_set_elt_t loop_series(a.structure().series());
00564
00565 while (!incoming_transitions.empty())
00566 {
00567 htransition_t& loop=incoming_transitions.front();
00568 if(a.src_of(loop)==a.dst_of(loop))
00569 {
00570 hasloop=true;
00571 loop_series += a.series_of(loop);
00572 incoming_transitions.pop_front();
00573 }
00574 else
00575 break;
00576 }
00577 if (hasloop)
00578 {
00579 if (!loop_series.get(monoid_identity).starable())
00580 return false;
00581 loop_series = loop_series.star();
00582 }
00583 std::list<htransition_t> outgoing_transitions;
00584 for (delta_iterator e(a.value(), *s); ! e.done(); e.next())
00585 if (a.src_of(*e)!=a.dst_of(*e))
00586 outgoing_transitions.push_back(*e);
00587 for_all_(std::list<htransition_t>, e, incoming_transitions)
00588 for_all_(std::list<htransition_t>, f, outgoing_transitions)
00589 if (hasloop)
00590 a.add_series_transition(a.src_of(*e), a.dst_of(*f),
00591 a.series_of(*e)*loop_series*a.series_of(*f));
00592 else
00593 a.add_series_transition(a.src_of(*e), a.dst_of(*f),
00594 a.series_of(*e)*a.series_of(*f));
00595 if (a.is_final(*s))
00596 {
00597 series_set_elt_t final_s = a.get_final(*s);
00598 for_all_(std::list<htransition_t>, e, incoming_transitions)
00599 {
00600 hstate_t p = a.src_of(*e);
00601 series_set_elt_t t = a.get_final(p);
00602 if (hasloop)
00603 t += a.series_of(*e)*loop_series*final_s;
00604 else
00605 t += a.series_of(*e)*final_s;
00606 a.unset_final(p);
00607 if (t != null_series)
00608 a.set_final(p,t);
00609 }
00610 }
00611 if (a.is_initial(*s))
00612 {
00613 series_set_elt_t initial_s=a.get_initial(*s);
00614 for_all_(std::list<htransition_t>, f, outgoing_transitions)
00615 {
00616 hstate_t p = a.dst_of(*f);
00617 series_set_elt_t t = a.get_initial(p);
00618 if (hasloop)
00619 t += initial_s*loop_series*a.series_of(*f);
00620 else
00621 t += initial_s*a.series_of(*f);
00622 a.unset_initial(p);
00623 if (t != null_series)
00624 a.set_initial(p,t);
00625 }
00626 }
00627 a.del_state(*s);
00628 }
00629 return true;
00630 }
00631
00632
00633 void merge_transitions()
00634 {
00635 typedef std::map<hstate_t, series_set_elt_t> map_t;
00636 for_all_states(s, a)
00637 {
00638 map_t map;
00639 std::list<htransition_t> transitions;
00640 for (delta_iterator e(a.value(), *s); ! e.done(); e.next())
00641 {
00642 hstate_t target = a.dst_of(*e);
00643 transitions.push_back(*e);
00644 typename map_t::iterator it = map.find(target);
00645 if (it == map.end())
00646 map.insert(std::pair<hstate_t, series_set_elt_t>(target,
00647 a.series_of(*e)));
00648 else
00649 it->second += a.series_of(*e);
00650 }
00651 for_all_(std::list<htransition_t>, e, transitions)
00652 a.del_transition(*e);
00653 for_all_(map_t, it, map)
00654 if(it->second != null_series)
00655 a.add_series_transition(*s, it->first, it->second);
00656 }
00657 }
00658
00659 };
00660
00661
00662 template <class A_, typename Auto, typename Weight>
00663 bool test_for_non_positive_semiring<A_, Auto, Weight, 0>::run(const Auto& a) const
00664 {
00665 AUTOMATON_TYPES(Auto);
00666
00667 std::list<hstate_t> eps_states;
00668 automaton_t test(a);
00669 EpsilonRemover<A_, Auto, Weight> epsTest(test.structure(), test);
00670 epsTest.absolute_weight();
00671 epsTest.epsilon_covering(eps_states);
00672 return epsTest.spontaneous_suppression(eps_states);
00673 }
00674
00675
00676
00677
00678
00679
00680
00681
00682 template<class A_, typename Auto, typename Weight>
00683 void
00684 do_eps_removal_here(const AutomataBase<A_>& a_set,
00685 const Weight&,
00686 Auto& a,
00687 misc::direction_type dir)
00688 {
00689 BENCH_TASK_SCOPED("eps_removal");
00690 AUTOMATON_TYPES(Auto);
00691 EpsilonRemover<A_, Auto, Weight> algo(a_set, a);
00692 algo(dir);
00693 }
00694
00695 template<typename A, typename AI>
00696 void
00697 eps_removal_here(Element<A, AI>& a, misc::direction_type dir)
00698 {
00699 typedef Element<A, AI> automaton_t;
00700 AUTOMATON_TYPES(automaton_t);
00701
00702 do_eps_removal_here(a.structure(),
00703 SELECT(semiring_elt_value_t),
00704 a, dir);
00705 }
00706
00707 template<typename A, typename AI>
00708 Element<A, AI>
00709 eps_removal(const Element<A, AI>& a, misc::direction_type dir)
00710 {
00711 typedef Element<A, AI> automaton_t;
00712 AUTOMATON_TYPES(automaton_t);
00713
00714 automaton_t ret(a);
00715 do_eps_removal_here(ret.structure(),
00716 SELECT(semiring_elt_value_t),
00717 ret, dir);
00718 return ret;
00719 }
00720
00721 template<typename A, typename AI>
00722 void
00723 backward_eps_removal_here(Element<A, AI>& a)
00724 {
00725 typedef Element<A, AI> automaton_t;
00726 AUTOMATON_TYPES(automaton_t);
00727
00728 do_eps_removal_here(a.structure(),
00729 SELECT(semiring_elt_value_t),
00730 a, misc::backward);
00731 }
00732
00733 template<typename A, typename AI>
00734 Element<A, AI>
00735 backward_eps_removal(const Element<A, AI>& a)
00736 {
00737 typedef Element<A, AI> automaton_t;
00738 AUTOMATON_TYPES(automaton_t);
00739
00740 automaton_t ret(a);
00741 do_eps_removal_here(ret.structure(),
00742 SELECT(semiring_elt_value_t),
00743 ret, misc::backward);
00744 return ret;
00745 }
00746
00747 template<typename A, typename AI>
00748 void
00749 forward_eps_removal_here(Element<A, AI>& a)
00750 {
00751 typedef Element<A, AI> automaton_t;
00752 AUTOMATON_TYPES(automaton_t);
00753
00754 do_eps_removal_here(a.structure(),
00755 SELECT(semiring_elt_value_t),
00756 a, misc::forward);
00757 }
00758
00759 template<typename A, typename AI>
00760 Element<A, AI>
00761 forward_eps_removal(const Element<A, AI>& a)
00762 {
00763 typedef Element<A, AI> automaton_t;
00764 AUTOMATON_TYPES(automaton_t);
00765
00766 automaton_t ret(a);
00767 do_eps_removal_here(ret.structure(),
00768 SELECT(semiring_elt_value_t),
00769 ret, misc::forward);
00770 return ret;
00771 }
00772
00773 }
00774
00775 #endif // ! VCSN_ALGORITHMS_EPS_REMOVAL_HXX