00001
00002
00156
00157
00158
00159 #include "pbori_defs.h"
00160
00161
00162 #include "pbori_func.h"
00163 #include "pbori_traits.h"
00164
00165
00166 #include "cudd.h"
00167 #include "cuddInt.h"
00168 #include "CCuddInterface.h"
00169
00170 #ifndef pbori_algo_h_
00171 #define pbori_algo_h_
00172
00173 BEGIN_NAMESPACE_PBORI
00174
00175
00177 template< class NaviType, class TermType,
00178 class TernaryOperator,
00179 class TerminalOperator >
00180 TermType
00181 dd_backward_transform( NaviType navi, TermType init, TernaryOperator newNode,
00182 TerminalOperator terminate ) {
00183
00184 TermType result = init;
00185
00186 if (navi.isConstant()) {
00187 if (navi.terminalValue()){
00188 result = terminate();
00189 }
00190 }
00191 else {
00192 result = dd_backward_transform(navi.thenBranch(), init, newNode, terminate);
00193 result = newNode(*navi, result,
00194 dd_backward_transform(navi.elseBranch(), init, newNode,
00195 terminate) );
00196 }
00197 return result;
00198 }
00199
00200
00202 template< class NaviType, class TermType, class OutIterator,
00203 class ThenBinaryOperator, class ElseBinaryOperator,
00204 class TerminalOperator >
00205 OutIterator
00206 dd_transform( NaviType navi, TermType init, OutIterator result,
00207 ThenBinaryOperator then_binop, ElseBinaryOperator else_binop,
00208 TerminalOperator terminate ) {
00209
00210
00211 if (navi.isConstant()) {
00212 if (navi.terminalValue()){
00213 *result = terminate(init);
00214 ++result;
00215 }
00216 }
00217 else {
00218 result = dd_transform(navi.thenBranch(), then_binop(init, *navi), result,
00219 then_binop, else_binop, terminate);
00220 result = dd_transform(navi.elseBranch(), else_binop(init, *navi), result,
00221 then_binop, else_binop, terminate);
00222 }
00223 return result;
00224 }
00225
00228 template< class NaviType, class TermType, class OutIterator,
00229 class ThenBinaryOperator, class ElseBinaryOperator,
00230 class TerminalOperator, class FirstTermOp >
00231 OutIterator
00232 dd_transform( NaviType navi, TermType init, OutIterator result,
00233 ThenBinaryOperator then_binop, ElseBinaryOperator else_binop,
00234 TerminalOperator terminate, FirstTermOp terminate_first ) {
00235
00236 if (navi.isConstant()) {
00237 if (navi.terminalValue()){
00238 *result = terminate_first(init);
00239 ++result;
00240 }
00241 }
00242 else {
00243 result = dd_transform(navi.thenBranch(), then_binop(init, *navi), result,
00244 then_binop, else_binop, terminate, terminate_first);
00245 result = dd_transform(navi.elseBranch(), else_binop(init, *navi), result,
00246 then_binop, else_binop, terminate);
00247 }
00248 return result;
00249 }
00250
00252 template< class NaviType, class TermType, class OutIterator,
00253 class ThenBinaryOperator, class ElseBinaryOperator >
00254 void
00255 dd_transform( const NaviType& navi, const TermType& init,
00256 const OutIterator& result,
00257 const ThenBinaryOperator& then_binop,
00258 const ElseBinaryOperator& else_binop ) {
00259
00260 dd_transform(navi, init, result, then_binop, else_binop,
00261 project_ith<1>() );
00262 }
00263
00265 template< class NaviType, class TermType, class OutIterator,
00266 class ThenBinaryOperator >
00267 void
00268 dd_transform( const NaviType& navi, const TermType& init,
00269 const OutIterator& result,
00270 const ThenBinaryOperator& then_binop ) {
00271
00272 dd_transform(navi, init, result, then_binop,
00273 project_ith<1, 2>(),
00274 project_ith<1>() );
00275 }
00276
00277
00278 template <class InputIterator, class OutputIterator,
00279 class FirstFunction, class UnaryFunction>
00280 OutputIterator
00281 special_first_transform(InputIterator first, InputIterator last,
00282 OutputIterator result,
00283 UnaryFunction op, FirstFunction firstop) {
00284 InputIterator second(first);
00285 if (second != last) {
00286 ++second;
00287 result = std::transform(first, second, result, firstop);
00288 }
00289 return std::transform(second, last, result, op);
00290 }
00291
00292
00294 template <class InputIterator, class Intermediate, class OutputIterator>
00295 OutputIterator
00296 reversed_inter_copy( InputIterator start, InputIterator finish,
00297 Intermediate& inter, OutputIterator output ) {
00298
00299 std::copy(start, finish, inter.begin());
00300
00301 return std::copy( const_cast<const Intermediate&>(inter).rbegin(),
00302 const_cast<const Intermediate&>(inter).rend(),
00303 output );
00304 }
00305
00308 template <class NaviType>
00309 bool
00310 dd_on_path(NaviType navi) {
00311
00312 if (navi.isConstant())
00313 return navi.terminalValue();
00314
00315 return dd_on_path(navi.thenBranch()) || dd_on_path(navi.elseBranch());
00316 }
00317
00320 template <class NaviType, class OrderedIterator>
00321 bool
00322 dd_owns_term_of_indices(NaviType navi,
00323 OrderedIterator start, OrderedIterator finish) {
00324
00325 if (!navi.isConstant()) {
00326 bool not_at_end;
00327
00328 while( (not_at_end = (start != finish)) && (*start < *navi) )
00329 ++start;
00330
00331 NaviType elsenode = navi.elseBranch();
00332
00333 if (elsenode.isConstant() && elsenode.terminalValue())
00334 return true;
00335
00336
00337 if (not_at_end){
00338
00339 if ( (*start == *navi) &&
00340 dd_owns_term_of_indices(navi.thenBranch(), start, finish))
00341 return true;
00342 else
00343 return dd_owns_term_of_indices(elsenode, start, finish);
00344 }
00345 else {
00346
00347 while(!elsenode.isConstant())
00348 elsenode.incrementElse();
00349 return elsenode.terminalValue();
00350 }
00351
00352 }
00353 return navi.terminalValue();
00354 }
00355
00359 template <class NaviType, class OrderedIterator, class NodeOperation>
00360 NaviType
00361 dd_intersect_some_index(NaviType navi,
00362 OrderedIterator start, OrderedIterator finish,
00363 NodeOperation newNode ) {
00364
00365 if (!navi.isConstant()) {
00366 bool not_at_end;
00367 while( (not_at_end = (start != finish)) && (*start < *navi) )
00368 ++start;
00369
00370 if (not_at_end) {
00371 NaviType elseNode =
00372 dd_intersect_some_index(navi.elseBranch(), start, finish,
00373 newNode);
00374
00375 if (*start == *navi) {
00376
00377 NaviType thenNode =
00378 dd_intersect_some_index(navi.thenBranch(), start, finish,
00379 newNode);
00380
00381 return newNode(*start, navi, thenNode, elseNode);
00382 }
00383 else
00384 return elseNode;
00385 }
00386 else {
00387
00388 while(!navi.isConstant())
00389 navi = navi.elseBranch();
00390 return newNode(navi);
00391 }
00392
00393 }
00394
00395 return newNode(navi);
00396 }
00397
00398
00399
00401 template <class NaviType>
00402 void
00403 dd_print(NaviType navi) {
00404
00405 if (!navi.isConstant()) {
00406
00407 std::cout << std::endl<< "idx " << *navi <<" addr "<<
00408 ((DdNode*)navi)<<" ref "<<
00409 int(Cudd_Regular((DdNode*)navi)->ref) << std::endl;
00410
00411 dd_print(navi.thenBranch());
00412 dd_print(navi.elseBranch());
00413
00414 }
00415 else {
00416 std::cout << "const isvalid? "<<navi.isValid()<<" addr "
00417 <<((DdNode*)navi)<<" ref "<<
00418 int(Cudd_Regular((DdNode*)navi)->ref)<<std::endl;
00419
00420 }
00421 }
00422
00423
00424 template <class IteratorType, class SizeType>
00425 SizeType
00426 limited_distance(IteratorType start, IteratorType finish, SizeType limit) {
00427
00428 SizeType result = 0;
00429
00430 while ((result < limit) && (start != finish)) {
00431 ++start, ++result;
00432 }
00433
00434 return result;
00435 }
00436
00437 #if 0
00438
00439 template <class, class, class, class, class, class> class CTermIter;
00440
00441
00442 template <class NaviType, class SizeType>
00443 SizeType
00444 limited_length(NaviType navi, SizeType limit) {
00445
00446
00447 typedef CTermIter<dummy_iterator, NaviType,
00448 project_ith<1>, project_ith<1>, project_ith<1, 2>,
00449 project_ith<1> >
00450 iterator;
00451
00452 return limited_distance(iterator(navi), iterator(), limit);
00453 }
00454 #endif
00455
00457 template <class NaviType>
00458 bool owns_one(NaviType navi) {
00459 while (!navi.isConstant() )
00460 navi.incrementElse();
00461
00462 return navi.terminalValue();
00463 }
00464
00465 template <class CacheMgr, class NaviType, class SetType>
00466 SetType
00467 dd_modulo_monomials(const CacheMgr& cache_mgr,
00468 NaviType navi, NaviType rhs, const SetType& init){
00469
00470
00471 if (owns_one(rhs)) return cache_mgr.zero();
00472
00473 if (navi.isConstant())
00474 return cache_mgr.generate(navi);
00475
00476 typename SetType::idx_type index = *navi;
00477 while(*rhs < index )
00478 rhs.incrementElse();
00479
00480 if (rhs.isConstant())
00481 return cache_mgr.generate(navi);
00482
00483 if (rhs == navi)
00484 return cache_mgr.zero();
00485
00486
00487 NaviType cached = cache_mgr.find(navi, rhs);
00488 if (cached.isValid())
00489 return cache_mgr.generate(cached);
00490
00491
00492 SetType result;
00493 if (index == *rhs){
00494
00495 NaviType rhselse = rhs.elseBranch();
00496 SetType thenres =
00497 dd_modulo_monomials(cache_mgr, navi.thenBranch(), rhs.thenBranch(), init);
00498
00499 result =
00500 SetType(index,
00501 dd_modulo_monomials(cache_mgr,
00502 thenres.navigation(), rhselse, init),
00503 dd_modulo_monomials(cache_mgr,
00504 navi.elseBranch(), rhselse, init)
00505 );
00506
00507 }
00508 else {
00509 assert(*rhs > index);
00510 result =
00511 SetType(index,
00512 dd_modulo_monomials(cache_mgr, navi.thenBranch(), rhs, init),
00513 dd_modulo_monomials(cache_mgr, navi.elseBranch(), rhs, init)
00514 );
00515 }
00516 cache_mgr.insert(navi, rhs, result.navigation());
00517 return result;
00518 }
00519
00521 template <class CacheMgr, class ModMonCacheMgr, class NaviType, class SetType>
00522 SetType
00523 dd_minimal_elements(const CacheMgr& cache_mgr, const ModMonCacheMgr& modmon_mgr,
00524 NaviType navi, const SetType& init){
00525
00526
00527 if (navi.isEmpty())
00528 return cache_mgr.generate(navi);
00529
00530 if (owns_one(navi)) return cache_mgr.one();
00531
00532 NaviType ms0 = navi.elseBranch();
00533 NaviType ms1 = navi.thenBranch();
00534
00535
00536 NaviType cached = cache_mgr.find(navi);
00537 if (cached.isValid())
00538 return cache_mgr.generate(cached);
00539
00540 SetType minimal_else = dd_minimal_elements(cache_mgr, modmon_mgr, ms0, init);
00541 SetType minimal_then =
00542 dd_minimal_elements(cache_mgr, modmon_mgr,
00543 dd_modulo_monomials(modmon_mgr, ms1,
00544 minimal_else.navigation(),
00545 init).navigation(),
00546 init);
00547 SetType result;
00548 if ( (minimal_else.navigation() == ms0)
00549 && (minimal_then.navigation() == ms1) )
00550 result = cache_mgr.generate(navi);
00551 else
00552 result = SetType(*navi, minimal_then, minimal_else);
00553
00554 cache_mgr.insert(navi, result.navigation());
00555 return result;
00556 }
00557
00558
00562 template <class NaviType, class DDType>
00563 DDType
00564 dd_minimal_elements(NaviType navi, DDType dd, DDType& multiples) {
00565
00566
00567 if (!navi.isConstant()) {
00568
00569 DDType elsedd = dd.subset0(*navi);
00570
00571
00572 DDType elseMultiples;
00573 elsedd = dd_minimal_elements(navi.elseBranch(), elsedd, elseMultiples);
00574
00575
00576 if((navi.elseBranch() == navi.thenBranch()) || elsedd.blankness()){
00577 multiples = elseMultiples;
00578 return elsedd;
00579 }
00580
00581 NaviType elseNavi = elseMultiples.navigation();
00582
00583 int nmax;
00584 if (elseNavi.isConstant()){
00585 if (elseNavi.terminalValue())
00586 nmax = dd.nVariables();
00587 else
00588 nmax = *navi;
00589 }
00590 else
00591 nmax = *elseNavi;
00592
00593
00594 for(int i = nmax-1; i > *navi; --i){
00595 elseMultiples.uniteAssign(elseMultiples.change(i));
00596 }
00597
00598
00599 DDType thendd = dd.subset1(*navi);
00600 thendd = thendd.diff(elseMultiples);
00601
00602 DDType thenMultiples;
00603 thendd = dd_minimal_elements(navi.thenBranch(), thendd, thenMultiples);
00604
00605 NaviType thenNavi = thenMultiples.navigation();
00606
00607
00608 if (thenNavi.isConstant()){
00609 if (thenNavi.terminalValue())
00610 nmax = dd.nVariables();
00611 else
00612 nmax = *navi;
00613 }
00614 else
00615 nmax = *thenNavi;
00616
00617
00618 for(int i = nmax-1; i > *navi; --i){
00619 thenMultiples.uniteAssign(thenMultiples.change(i));
00620 }
00621
00622
00623 thenMultiples = thenMultiples.unite(elseMultiples);
00624 thenMultiples = thenMultiples.change(*navi);
00625
00626
00627 multiples = thenMultiples.unite(elseMultiples);
00628 thendd = thendd.change(*navi);
00629
00630 DDType result = thendd.unite(elsedd);
00631
00632 return result;
00633
00634 }
00635
00636 multiples = dd;
00637 return dd;
00638 }
00639
00640 template <class MgrType>
00641 inline const MgrType&
00642 get_mgr_core(const MgrType& rhs) {
00643 return rhs;
00644 }
00645 inline Cudd*
00646 get_mgr_core(const Cudd& rhs) {
00647 return &const_cast<Cudd&>(rhs);
00648 }
00649
00651 inline CCuddInterface::mgrcore_ptr
00652 get_mgr_core(const CCuddInterface& mgr) {
00653 return mgr.managerCore();
00654 }
00655
00657 template<class ManagerType, class ReverseIterator, class MultReverseIterator>
00658 typename manager_traits<ManagerType>::dd_base
00659 cudd_generate_multiples(const ManagerType& mgr,
00660 ReverseIterator start, ReverseIterator finish,
00661 MultReverseIterator multStart,
00662 MultReverseIterator multFinish) {
00663
00664 DdNode* prev( (mgr.getManager())->one );
00665
00666 DdNode* zeroNode( (mgr.getManager())->zero );
00667
00668 Cudd_Ref(prev);
00669 while(start != finish) {
00670
00671 while((multStart != multFinish) && (*start < *multStart)) {
00672
00673 DdNode* result = cuddUniqueInterZdd( mgr.getManager(), *multStart,
00674 prev, prev );
00675
00676 Cudd_Ref(result);
00677 Cudd_RecursiveDerefZdd(mgr.getManager(), prev);
00678
00679 prev = result;
00680 ++multStart;
00681
00682 };
00683
00684 DdNode* result = cuddUniqueInterZdd( mgr.getManager(), *start,
00685 prev, zeroNode );
00686
00687 Cudd_Ref(result);
00688 Cudd_RecursiveDerefZdd(mgr.getManager(), prev);
00689
00690 prev = result;
00691
00692
00693 if((multStart != multFinish) && (*start == *multStart))
00694 ++multStart;
00695
00696
00697 ++start;
00698 }
00699
00700 while(multStart != multFinish) {
00701
00702 DdNode* result = cuddUniqueInterZdd( mgr.getManager(), *multStart,
00703 prev, prev );
00704
00705 Cudd_Ref(result);
00706 Cudd_RecursiveDerefZdd(mgr.getManager(), prev);
00707
00708 prev = result;
00709 ++multStart;
00710
00711 };
00712
00713 Cudd_Deref(prev);
00714
00715 typedef typename manager_traits<ManagerType>::dd_base dd_base;
00716 return dd_base(get_mgr_core(mgr), prev);
00717 }
00718
00719
00720
00722 template<class ManagerType, class ReverseIterator>
00723 typename manager_traits<ManagerType>::dd_base
00724 cudd_generate_divisors(const ManagerType& mgr,
00725 ReverseIterator start, ReverseIterator finish) {
00726
00727 typedef typename manager_traits<ManagerType>::dd_base dd_base;
00728 DdNode* prev= (mgr.getManager())->one;
00729
00730 Cudd_Ref(prev);
00731 while(start != finish) {
00732
00733 DdNode* result = cuddUniqueInterZdd( mgr.getManager(), *start,
00734 prev, prev);
00735
00736 Cudd_Ref(result);
00737 Cudd_RecursiveDerefZdd(mgr.getManager(), prev);
00738
00739 prev = result;
00740 ++start;
00741 }
00742
00743 Cudd_Deref(prev);
00745 return dd_base(get_mgr_core(mgr), prev);
00746
00747 }
00748
00749
00750 template<class Iterator, class SizeType>
00751 Iterator
00752 bounded_max_element(Iterator start, Iterator finish, SizeType bound){
00753
00754 if (*start >= bound)
00755 return start;
00756
00757 Iterator result(start);
00758 if (start != finish)
00759 ++start;
00760
00761 while (start != finish) {
00762 if(*start >= bound)
00763 return start;
00764 if(*start > *result)
00765 result = start;
00766 ++start;
00767 }
00768
00769 return result;
00770 }
00771
00773 template <class LhsType, class RhsType, class BinaryPredicate>
00774 CTypes::comp_type
00775 generic_compare_3way(const LhsType& lhs, const RhsType& rhs, BinaryPredicate comp) {
00776
00777 if (lhs == rhs)
00778 return CTypes::equality;
00779
00780 return (comp(lhs, rhs)? CTypes::greater_than: CTypes::less_than);
00781 }
00782
00783
00784
00785 template <class IteratorLike, class ForwardIteratorTag>
00786 IteratorLike
00787 increment_iteratorlike(IteratorLike iter, ForwardIteratorTag) {
00788
00789 return ++iter;
00790 }
00791
00792 template <class IteratorLike>
00793 IteratorLike
00794 increment_iteratorlike(IteratorLike iter, navigator_tag) {
00795
00796 return iter.thenBranch();
00797 }
00798
00799
00800 template <class IteratorLike>
00801 IteratorLike
00802 increment_iteratorlike(IteratorLike iter) {
00803
00804 typedef typename std::iterator_traits<IteratorLike>::iterator_category
00805 iterator_category;
00806
00807 return increment_iteratorlike(iter, iterator_category());
00808 }
00809
00810 #ifdef PBORI_LOWLEVEL_XOR
00811
00812
00813 DdNode*
00814 pboriCuddZddUnionXor__(DdManager *, DdNode *, DdNode *);
00815
00816
00820 template <class MgrType, class NodeType>
00821 NodeType
00822 pboriCuddZddUnionXor(MgrType zdd, NodeType P, NodeType Q) {
00823
00824 int p_top, q_top;
00825 NodeType empty = DD_ZERO(zdd), t, e, res;
00826 MgrType table = zdd;
00827
00828 statLine(zdd);
00829
00830 if (P == empty)
00831 return(Q);
00832 if (Q == empty)
00833 return(P);
00834 if (P == Q)
00835 return(empty);
00836
00837
00838 res = cuddCacheLookup2Zdd(table, pboriCuddZddUnionXor__, P, Q);
00839 if (res != NULL)
00840 return(res);
00841
00842 if (cuddIsConstant(P))
00843 p_top = P->index;
00844 else
00845 p_top = P->index;
00846 if (cuddIsConstant(Q))
00847 q_top = Q->index;
00848 else
00849 q_top = Q->index;
00850 if (p_top < q_top) {
00851 e = pboriCuddZddUnionXor(zdd, cuddE(P), Q);
00852 if (e == NULL) return (NULL);
00853 Cudd_Ref(e);
00854 res = cuddZddGetNode(zdd, P->index, cuddT(P), e);
00855 if (res == NULL) {
00856 Cudd_RecursiveDerefZdd(table, e);
00857 return(NULL);
00858 }
00859 Cudd_Deref(e);
00860 } else if (p_top > q_top) {
00861 e = pboriCuddZddUnionXor(zdd, P, cuddE(Q));
00862 if (e == NULL) return(NULL);
00863 Cudd_Ref(e);
00864 res = cuddZddGetNode(zdd, Q->index, cuddT(Q), e);
00865 if (res == NULL) {
00866 Cudd_RecursiveDerefZdd(table, e);
00867 return(NULL);
00868 }
00869 Cudd_Deref(e);
00870 } else {
00871 t = pboriCuddZddUnionXor(zdd, cuddT(P), cuddT(Q));
00872 if (t == NULL) return(NULL);
00873 Cudd_Ref(t);
00874 e = pboriCuddZddUnionXor(zdd, cuddE(P), cuddE(Q));
00875 if (e == NULL) {
00876 Cudd_RecursiveDerefZdd(table, t);
00877 return(NULL);
00878 }
00879 Cudd_Ref(e);
00880 res = cuddZddGetNode(zdd, P->index, t, e);
00881 if (res == NULL) {
00882 Cudd_RecursiveDerefZdd(table, t);
00883 Cudd_RecursiveDerefZdd(table, e);
00884 return(NULL);
00885 }
00886 Cudd_Deref(t);
00887 Cudd_Deref(e);
00888 }
00889
00890 cuddCacheInsert2(table, pboriCuddZddUnionXor__, P, Q, res);
00891
00892 return(res);
00893 }
00894
00895 template <class MgrType, class NodeType>
00896 NodeType
00897 pboriCudd_zddUnionXor(MgrType dd, NodeType P, NodeType Q) {
00898
00899 NodeType res;
00900 do {
00901 dd->reordered = 0;
00902 res = pboriCuddZddUnionXor(dd, P, Q);
00903 } while (dd->reordered == 1);
00904 return(res);
00905 }
00906
00907 #endif // PBORI_LOWLEVEL_XOR
00908
00909
00910 template <class NaviType>
00911 bool
00912 dd_is_singleton(NaviType navi) {
00913
00914 while(!navi.isConstant()) {
00915 if (!navi.elseBranch().isEmpty())
00916 return false;
00917 navi.incrementThen();
00918 }
00919 return true;
00920 }
00921
00922 template <class NaviType, class BooleConstant>
00923 BooleConstant
00924 dd_pair_check(NaviType navi, BooleConstant allowSingleton) {
00925
00926 while(!navi.isConstant()) {
00927
00928 if (!navi.elseBranch().isEmpty())
00929 return dd_is_singleton(navi.elseBranch()) &&
00930 dd_is_singleton(navi.thenBranch());
00931
00932 navi.incrementThen();
00933 }
00934 return allowSingleton;
00935 }
00936
00937
00938 template <class NaviType>
00939 bool
00940 dd_is_singleton_or_pair(NaviType navi) {
00941
00942 return dd_pair_check(navi, true);
00943 }
00944
00945 template <class NaviType>
00946 bool
00947 dd_is_pair(NaviType navi) {
00948
00949 return dd_pair_check(navi, false);
00950 }
00951
00952
00953
00954 template <class SetType>
00955 void combine_sizes(const SetType& bset, double& init) {
00956 init += bset.sizeDouble();
00957 }
00958
00959 template <class SetType>
00960 void combine_sizes(const SetType& bset,
00961 typename SetType::size_type& init) {
00962 init += bset.size();
00963 }
00964
00965
00966 template <class SizeType, class IdxType, class NaviType, class SetType>
00967 SizeType&
00968 count_index(SizeType& size, IdxType idx, NaviType navi, const SetType& init) {
00969
00970 if (*navi == idx)
00971 combine_sizes(SetType(navi.incrementThen(), init.ring()), size);
00972
00973 if (*navi < idx) {
00974 count_index(size, idx, navi.thenBranch(), init);
00975 count_index(size, idx, navi.elseBranch(), init);
00976 }
00977 return size;
00978 }
00979
00980
00981 template <class SizeType, class IdxType, class SetType>
00982 SizeType&
00983 count_index(SizeType& size, IdxType idx, const SetType& bset) {
00984
00985 return count_index(size, idx, bset.navigation(), SetType());
00986 }
00987
00988 END_NAMESPACE_PBORI
00989
00990 #endif