Boost logo

Boost :

From: Joerg Walter (jhr.walter_at_[hidden])
Date: 2002-05-07 01:49:03


----- Original Message -----
From: "Kresimir Fresl" <fresl_at_[hidden]>
To: <boost_at_[hidden]>
Sent: Tuesday, May 07, 2002 12:33 AM
Subject: [boost] Re: ublas: matrix clear() and operator=

>
> Joerg Walter wrote:
>
> > But Toon is right, if he mentions, that
> > ublas clear() doesn't have the same semantics as STL clear(). Shouldn't
we
> > better use the name zeroize() instead of clear()?
>
> Ha! You have finally opened the Pandora's box ;o)

Oops.

> Let's see one small example:
>
> ==========================================
> typedef numerics::vector<double> uvector;
> typedef
> numerics::vector< double, numerics::bounded_array<double, 16> >
bvector;
> typedef numerics::vector< double, std::vector<double> > svector;
>
> int main() {
>
> uvector uv (8);
> bvector bv (8);
> svector sv (8);
> for (int i = 0; i < 8; ++i)
> uv[i] = bv[i] = sv[i] = i+1;
> cout << endl << "original:\n" << "uv: " << uv << endl;
> cout << "bv: " << bv << endl;
> cout << "sv: " << sv << endl;
>
> uv.insert (4, 100);
> bv.insert (4, 100);
> sv.insert (4, 100);
> cout << endl << "after insert():\n" << "uv: " << uv << endl;
> cout << "bv: " << bv << endl;
> cout << "sv: " << sv << endl;
>
> uv.erase (4);
> bv.erase (4);
> sv.erase (4);
> cout << endl << "after erase():\n" << "uv: " << uv << endl;
> cout << "bv: " << bv << endl;
> cout << "sv: " << sv << endl;
>
> uv.resize (12);
> bv.resize (12);
> sv.resize (12);
> cout << endl << "after resize():\n" << "uv: " << uv << endl;
> cout << "bv: " << bv << endl;
> cout << "sv: " << sv << endl << endl;
>
> }
> =========================================
>
> The output is:
>
> =========================================
> original:
> uv: [8](1,2,3,4,5,6,7,8)
> bv: [8](1,2,3,4,5,6,7,8)
> sv: [8](1,2,3,4,5,6,7,8)
>
> after insert():
> uv: [8](1,2,3,4,100,6,7,8)
> bv: [8](1,2,3,4,100,6,7,8)
> sv: [8](1,2,3,4,100,5,6,7)
>
> after erase():
> uv: [8](1,2,3,4,0,6,7,8)
> bv: [8](1,2,3,4,0,6,7,8)
> sv: [8](1,2,3,4,5,6,7,8)
>
> after resize():
> uv: [12](0,0,0,0,0,0,0,0,0,0,0,0)
> bv: [12](1,2,3,4,0,6,7,8,4.85584e-270,4.92833e-270,2.81476,2.09812)
> sv: [12](1,2,3,4,5,6,7,8,0,0,0,0)
> ==========================================
>
> The behaviour of ublas::vector<>, when insert(), erase() or
> resize() are called, depends on array_type, because
> these functions call array_type's functions with same
> names. And those have different semantics.

Ok, I understand: numerics::vector<>'s insert() and erase() suffer from the
same problem like clear() earlier did. This clearly is a(nother) bug report,
thanks.

resize() doesn't even care to preserve the old content of the array, let
alone to initialize new elements. This is intended behaviour.

> On the other hand, behaviour of clear() is always the
> same, because ublas::vector<>::clear() does not
> call array_type::clear() but std::fill().

Ok, insert() and erase() could be changed (similar to clear()) to

        // Element insertion and erasure
        void insert (size_type i, const_reference t) {
            check (data () [i] == value_type (), bad_index ());
            data () [i] = t;
        }
        void erase (size_type i) {
            data () [i] = value_type ();
        }

This would ensure, that the semantics for std::vector as array_type are
identical to numerics::*_array.

> This is rather confusing: behaviour of some functions
> depends on underlying array_type and is the same
> as corresponding array_type's function, while behaviour
> of some other functions doesn't depend and is *different*
> from the corresponding array_type's function.
>
> I don't think that renaming is the cure.
>
> ublas::vector<> should be regarded as adaptor/decorator
> which adds linear algebra functionality to underlying `array_type'
> (of course, this should be clearly and loudly stated in documentation)
> and it should not change the behaviour of array_type's functions
> with same names.

Here I'm not sure, if I should follow: the main problem, which something
like the clear()/insert()/erase() interface is intended to solve, is that
the sparse vector assignment

    void operator () (V &v, const vector_expression<E> &e, sparse_tag) {
            check (v.size () == e ().size (), bad_size ());
            v.clear ();
            typename E::const_iterator ite (e ().begin ());
            typename E::const_iterator ite_end (e ().end ());
            while (ite != ite_end)
                v.insert (ite.index (), *ite), ++ ite;
        }

has to work for dense, packed *and* sparse lhs (if only the rhs is sparse,
the whole assignment is demoted to the sparse case).

As you stated correctly, a STL conforming clear()/insert()/erase() interface
doesn't solve the problem, although it is related. So either we rename some
of the functions or redefine the semantics at least in the dense case.

> Concretely, ublas::vector<>::clear() should call
> array_type::clear(), whatever it does.
>
> Problem that results in current version of ublas::vector<>::clear()
> was (thread `ublas & custom containers (2)'):
>
> >> If a sparse matrix result is assigned to a dense matrix,
> >> the assignment operation should be dispatched to
> >> the sparse matrix logic: clear the dense matrix and insert
> >> the rhs elements at the corresponding positions.
> [...]
> > `numerics::vector_assign<>::operator()' with `sparse_tag'
> > uses `array_type::clear()' to clear `numerics::vector<>'
> > before assignement, that is, before the call to
> > `array_type::insert()'. But the behaviour and semantics of
> > `numerics::unbounded_array<>::clear()' and
> > `numerics::array_adaptor<>::clear()' is very different
> > from the behaviour of `std::vector<>::clear()'.
> > First two simply assign `0' to all elements. But
> > `std::vector<>::clear()' really clears the vector,
> > ie. it *removes* all elements
>
> I proposed to call std::fill (v.begin(), v.end(), value_type());
> in vector_assign<>::operator() (vct_t v, vct_expr, sparse_tag)
> instead of ublas::vector::clear(). Joerg put std::fill() in
> ublas::vector<>::clear() instead.
>
> At that time I didn't see any reason to object, but now I think
> that my proposal should be reconsidered.

IMO we have to extend your previous clear() fix to insert()/erase() and
optionally to rename some or all of these functions as they do not have the
STL semantics.

Regards

Joerg

> PS. It should be noted that semantics of std::valarray<>::resize()
> is different from std::vector<>::resize():
>
> ==========================================
> std::vector<double> vct (4);
> std::valarray<double> va (4);
> for (int i = 0; i < 4; ++i)
> vct[i] = va[i] = i;
>
> vct.resize (6, 100);
> va.resize (6, 100);
>
> for (int i = 0; i < 6; ++i)
> std::cout << vct[i] << " " << va[i] << "\n";
> ===========================================
>
> Output is:
>
> 0 100
> 1 100
> 2 100
> 3 100
> 100 100
> 100 100
>
> _______________________________________________
> Unsubscribe & other changes:
http://lists.boost.org/mailman/listinfo.cgi/boost


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