Boost logo

Boost :

From: Kresimir Fresl (fresl_at_[hidden])
Date: 2002-03-09 07:45:22


IMHO the current definition/implementation of
`numerics::vector<>::upper_bound()' is wrong [1,2].

I think that semantics of `numerics::vector<>::upper_bound()'
should be identical to that of `std::map<>::upper_bound()' [3],
which ``returns an iterator pointing to the first element with key
*greater* than k'' (where `k' is given argument).

As a concrete example:
--------------------------------------------------------------------------
     typedef std::map<std::size_t, double> sp_vec_t;
     typedef sp_vec_t::value_type v_t;
     typedef sp_vec_t::iterator it_t;

     sp_vec_t sv;
     for (int i = 0; i < 8; ++i) sv.insert (v_t (i, 0.1 * i));
     // sv = { (0: 0.0), (1: 0.1), ... , (7: 0.7) }

     it_t lb = sv.lower_bound (3);
     it_t ub = sv.upper_bound (3);
     std::cout << lb->first << ": " << lb->second << " | "
                    << ub->first << ": " << ub->second << std::endl;
--------------------------------------------------------------------------
The output is: `3: 0.3 | 4: 0.4'.

In other words, `[lb, ub)' is *non-empty* range and

     for (it_t i = lb; i != ub; ++i)
        std::cout << i -> first << ": " << i -> second << std::endl;

prints: `3: 0.3'.

But the output of:
--------------------------------------------------------------------------
     typedef numerics::vector<double> vct_t;
     typedef vct_t::iterator it_t;

     vct_t v (8);
     for (std::size_t i = 0; i < 8; ++i) v[i] = 0.1* i;

     it_t lb = v.lower_bound (3);
     it_t ub = v.upper_bound (3);
     std::cout << lb.index() << ": " << *lb << " | "
                    << ub.index() << ": " << *ub << std::endl;
--------------------------------------------------------------------------
is: `3: 0.3 | 3: 0.3', ie. `[lb, ub)' is now an *empty* range
and

     for (it_t i = lb; i != ub; ++i)
        std::cout << i.index() << ": " << *i << std::endl;

prints nothing.

There is currently no difference between
`vector<>::upper_bound()' and `vector<>::lower_bound()'.
Both behave as `std::map<>::lower_bound()' which ``returns
an iterator pointing to the first element with key not less than k''.

Definition of `numerics::vector<>::upper_bound()' should be
something like

      iterator upper_bound (size_type i) { return find (i+1); }

I am not quite sure how this will reflect to `vector<>::end()'.
It should be changed because of the current definition of
`vector<>::find()' [which is `return iterator (*this, i);'
or `return iterator (*this, data_.begin () + i);' ], but *not* into:

      iterator end () { return upper_bound (size_-1); }

because size_ (which is unsigned integer) can be 0.
Maybe to

      iterator end () { return lower_bound (size_); }

Similarly, `unit_vector<>::upper_bound()' should be:

      const_iterator upper_bound (size_type i) const {
            return const_iterator (*this, std::min (i+1, index_+1));
      }

Sincerely,

fres

[1] And also of `numerics::unit_vector<>::upper_bound()'
and `numerics::sparse_vector<>::upper_bound()' and,
I am afraid, of `upper_boundD()' in various matrix classes.

[2] `find()', `lower_bound()' and `upper_bound()' are listed
in interface of `numerics::vector<>' in docs, but I didn't find
their description (AFAIK functions `find()' etc. are described
only in docs for `compressed_array<>'; their descriptions are
similar to those for `std::map<>').

Some history: I first noticed that something was wrong
with `unit_vector<>::upper_bound()':

-----------------------------------------------------------------------------
     numerics::vector<double> v (8);
     for (std::size_t i = 0; i < 8; ++i) v[i] = i;
     // v = { 0, 1, 2, 3, 4, 5, 6, 7 }
     numerics::unit_vector<double> uv (n, 3);
     // uv = { 0, 0, 0, 1, 0, 0, 0, 0 }
     std::cout << numerics::inner_prod (v, uv) << std::endl;
------------------------------------------------------------------------------

And the result is ... `0' instead of `3'.

There was a long way to go ;o), but finally I arrived to
`Packed bidirectional specialization' of
`vector_scalar_binary<>::evaluate()' in `vector_et.h'.

Its arguments are `v.begin(), v.end(), uv.begin(), uv.end()',
but [uv.begin(), uv.end()) is an empty range.

And `unit_vector<>::end()' is defined/implemeted in terms of
`unit_vector<>::upper_bound()'. QED ;o)

[3] After all, `std::map<std::size_t, T>' can be used as
StorageType in `numerics::sparse_vector<T, StorageType>'.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk