Re: [eigen] Array cwise multiplication |
[ Thread Index |
Date Index
| More lists.tuxfamily.org/eigen Archives
]
- To: eigen@xxxxxxxxxxxxxxxxxxx
- Subject: Re: [eigen] Array cwise multiplication
- From: Benoit Jacob <jacob.benoit.1@xxxxxxxxx>
- Date: Fri, 1 Oct 2010 14:29:06 -0700
- Dkim-signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:mime-version:received:received:in-reply-to :references:date:message-id:subject:from:to:content-type :content-transfer-encoding; bh=d3P4TDPkdrpALRhTVPUJpKTl0+iOdGO4D8RQUZLdWjk=; b=iZ/QhFDe05OGrAXe5MEhc8oLFWpw0tBc+lDTyQZqEoURttxenaOjuVsFvnB6Rsj6II qeNg4B1/hOJVVZtnOYi3nXqOn7J7ZRA01mhj1/Og1pUAFp0/m76ICYjy71d61BUM6aU+ b4VWtYfeoGp2sPzGGDOBv1cNogag4Ic9osmds=
- Domainkey-signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :content-type:content-transfer-encoding; b=a95s0tmEz7TU2hOnwbhn18So+KUpyRhyY396E3hsM9uMK8d3Ot7Mh6SChTw/Eq1b8n jcqPfMVf7YpiMWQd8R/zOJp4NzYO5GliFW1g4wE8kPh0SNigyoUyQt+2hNVk5QkNNn9W v6ChYiTuOoEVs2NddgCCDuGzymvtVxMtu3BIo=
2010/10/1 Benoit Jacob <jacob.benoit.1@xxxxxxxxx>:
> you do have a point about the diagonal product; but I could see this
> being useful on arrays too. Then, given that there is no ambiguity
> thanks to the colwise prefix, we might as well allow it on matrices,
> especially as we see that people naturally expect it to work.
OK I changed my mind:
- indeed on matrices, diagonal product is all we want to allow
- we can still consider it on arrays though
Benoit
>
> Benoit
>
> 2010/10/1 Gael Guennebaud <gael.guennebaud@xxxxxxxxx>:
>> well, there is no operator * defined in VectorwiseOp so that clearly
>> cannot compile. This as never been added because this is precisely a
>> diagonal product especially if you are in the linear algebra world (in
>> contrast to arrays).
>>
>> If we add it, I'm really not sure we should enable it for matrices.
>>
>> gael
>>
>> On Wed, Sep 29, 2010 at 9:02 PM, Benoit Jacob <jacob.benoit.1@xxxxxxxxx> wrote:
>>> the asDiagonal() way is completely optimized.
>>>
>>> It doesn't hurt to file a bug, I agree that colwise multiplication should work.
>>>
>>> Benoit
>>>
>>> 2010/9/29 Carlos Becker <carlosbecker@xxxxxxxxx>:
>>>> That's a good idea, should I report this as a bug?
>>>> on the other hand, .asDiagonal() will return a diagonal object and it is
>>>> evaluated as a diagonal matrix, with its respective optimization?
>>>> Thanks
>>>>
>>>>
>>>> On Wed, Sep 29, 2010 at 8:37 PM, Benoit Jacob <jacob.benoit.1@xxxxxxxxx>
>>>> wrote:
>>>>>
>>>>> meanwhile you can do the same with a diagonal product:
>>>>>
>>>>> a * b.asDiagonal()
>>>>>
>>>>> or
>>>>>
>>>>> b.asDiagonal() * a
>>>>>
>>>>> 2010/9/29 Carlos Becker <carlosbecker@xxxxxxxxx>:
>>>>> > The strange things is that operator + and - work, but I guess that might
>>>>> > come from Matrix. So there is something strange going on with array
>>>>> > colwise() and rowwise() (just tested that too, very quick, and seems to
>>>>> > have
>>>>> > the same problems).
>>>>> >
>>>>> >
>>>>> > On Wed, Sep 29, 2010 at 8:09 PM, Benoit Jacob <jacob.benoit.1@xxxxxxxxxx>
>>>>> > wrote:
>>>>> >>
>>>>> >> erm, ignore me, that didn't make sense.
>>>>> >>
>>>>> >> 2010/9/29 Benoit Jacob <jacob.benoit.1@xxxxxxxxx>:
>>>>> >> > ah, i know.
>>>>> >> >
>>>>> >> > b is a column-vector. you can't multiply colwise by it.
>>>>> >> >
>>>>> >> > Either make it a row-vector or multiply rowwise by it.
>>>>> >> >
>>>>> >> > 2010/9/29 Carlos Becker <carlosbecker@xxxxxxxxx>:
>>>>> >> >> I already tried that, and still doesn't work. I get the following
>>>>> >> >> error
>>>>> >> >> (sorry for the flooding)
>>>>> >> >> test.cpp:20: error: no match for ‘operator*’ in
>>>>> >> >> ‘((Eigen::DenseBase<Eigen::ArrayWrapper<Eigen::Matrix<float,
>>>>> >> >> -0x00000000000000001, -0x00000000000000001, 0, -0x00000000000000001,
>>>>> >> >> -0x00000000000000001> >
>>>>> >> >> >*)(&((Eigen::MatrixBase<Eigen::Matrix<float,
>>>>> >> >> -0x00000000000000001, -0x00000000000000001, 0, -0x00000000000000001,
>>>>> >> >> -0x00000000000000001> >*)(& a))->Eigen::MatrixBase<Derived>::array
>>>>> >> >> [with
>>>>> >> >> Derived = Eigen::Matrix<float, -0x00000000000000001,
>>>>> >> >> -0x00000000000000001,
>>>>> >> >> 0, -0x00000000000000001,
>>>>> >> >> -0x00000000000000001>]()))->Eigen::DenseBase<Derived>::colwise [with
>>>>> >> >> Derived
>>>>> >> >> = Eigen::ArrayWrapper<Eigen::Matrix<float, -0x00000000000000001,
>>>>> >> >> -0x00000000000000001, 0, -0x00000000000000001, -0x00000000000000001>
>>>>> >> >> >]() *
>>>>> >> >> ((Eigen::MatrixBase<Eigen::Matrix<float, -0x00000000000000001, 1, 0,
>>>>> >> >> -0x00000000000000001, 1> >*)(&
>>>>> >> >> b))->Eigen::MatrixBase<Derived>::array
>>>>> >> >> [with
>>>>> >> >> Derived = Eigen::Matrix<float, -0x00000000000000001, 1, 0,
>>>>> >> >> -0x00000000000000001, 1>]()’
>>>>> >> >> ./Eigen/src/Core/../plugins/CommonCwiseUnaryOps.h:95: note:
>>>>> >> >> candidates
>>>>> >> >> are:
>>>>> >> >> const Eigen::CwiseUnaryOp<Eigen::ei_scalar_multiple2_op<float,
>>>>> >> >> std::complex<float> >, Eigen::ArrayWrapper<Eigen::Matrix<float,
>>>>> >> >> -0x00000000000000001, 1, 0, -0x00000000000000001, 1> > >
>>>>> >> >> Eigen::operator*(const std::complex<float>&, const
>>>>> >> >> Eigen::ArrayBase<Eigen::ArrayWrapper<Eigen::Matrix<float,
>>>>> >> >> -0x00000000000000001, 1, 0, -0x00000000000000001, 1> > >&)
>>>>> >> >> ./Eigen/src/Core/../plugins/CommonCwiseUnaryOps.h:91: note:
>>>>> >> >> const Eigen::CwiseUnaryOp<Eigen::ei_scalar_multiple_op<float>,
>>>>> >> >> Eigen::ArrayWrapper<Eigen::Matrix<float, -0x00000000000000001, 1, 0,
>>>>> >> >> -0x00000000000000001, 1> > > Eigen::operator*(const float&, const
>>>>> >> >> Eigen::ArrayBase<Eigen::ArrayWrapper<Eigen::Matrix<float,
>>>>> >> >> -0x00000000000000001, 1, 0, -0x00000000000000001, 1> > >&)
>>>>> >> >> ./Eigen/src/Core/../plugins/CommonCwiseUnaryOps.h:95: note:
>>>>> >> >> const Eigen::CwiseUnaryOp<Eigen::ei_scalar_multiple2_op<float,
>>>>> >> >> std::complex<float> >, Eigen::ArrayWrapper<Eigen::Matrix<float,
>>>>> >> >> -0x00000000000000001, -0x00000000000000001, 0, -0x00000000000000001,
>>>>> >> >> -0x00000000000000001> > > Eigen::operator*(const
>>>>> >> >> std::complex<float>&,
>>>>> >> >> const
>>>>> >> >> Eigen::ArrayBase<Eigen::ArrayWrapper<Eigen::Matrix<float,
>>>>> >> >> -0x00000000000000001, -0x00000000000000001, 0, -0x00000000000000001,
>>>>> >> >> -0x00000000000000001> > >&)
>>>>> >> >> ./Eigen/src/Core/../plugins/CommonCwiseUnaryOps.h:91: note:
>>>>> >> >> const Eigen::CwiseUnaryOp<Eigen::ei_scalar_multiple_op<float>,
>>>>> >> >> Eigen::ArrayWrapper<Eigen::Matrix<float, -0x00000000000000001,
>>>>> >> >> -0x00000000000000001, 0, -0x00000000000000001, -0x00000000000000001>
>>>>> >> >> >
>>>>> >> >> >
>>>>> >> >> Eigen::operator*(const float&, const
>>>>> >> >> Eigen::ArrayBase<Eigen::ArrayWrapper<Eigen::Matrix<float,
>>>>> >> >> -0x00000000000000001, -0x00000000000000001, 0, -0x00000000000000001,
>>>>> >> >> -0x00000000000000001> > >&)
>>>>> >> >> ./Eigen/src/Core/../plugins/CommonCwiseUnaryOps.h:95: note:
>>>>> >> >> const Eigen::CwiseUnaryOp<Eigen::ei_scalar_multiple2_op<float,
>>>>> >> >> std::complex<float> >, Eigen::Matrix<float, -0x00000000000000001,
>>>>> >> >> -0x00000000000000001, 0, -0x00000000000000001, -0x00000000000000001>
>>>>> >> >> >
>>>>> >> >> Eigen::operator*(const std::complex<float>&, const
>>>>> >> >> Eigen::MatrixBase<Eigen::Matrix<float, -0x00000000000000001,
>>>>> >> >> -0x00000000000000001, 0, -0x00000000000000001, -0x00000000000000001>
>>>>> >> >> >&)
>>>>> >> >> ./Eigen/src/Core/../plugins/CommonCwiseUnaryOps.h:91: note:
>>>>> >> >> const Eigen::CwiseUnaryOp<Eigen::ei_scalar_multiple_op<float>,
>>>>> >> >> Eigen::Matrix<float, -0x00000000000000001, -0x00000000000000001, 0,
>>>>> >> >> -0x00000000000000001, -0x00000000000000001> > Eigen::operator*(const
>>>>> >> >> float&,
>>>>> >> >> const Eigen::MatrixBase<Eigen::Matrix<float, -0x00000000000000001,
>>>>> >> >> -0x00000000000000001, 0, -0x00000000000000001, -0x00000000000000001>
>>>>> >> >> >&)
>>>>> >> >> ./Eigen/src/Core/../plugins/CommonCwiseUnaryOps.h:95: note:
>>>>> >> >> const Eigen::CwiseUnaryOp<Eigen::ei_scalar_multiple2_op<float,
>>>>> >> >> std::complex<float> >, Eigen::Matrix<float, -0x00000000000000001, 1,
>>>>> >> >> 0,
>>>>> >> >> -0x00000000000000001, 1> > Eigen::operator*(const
>>>>> >> >> std::complex<float>&,
>>>>> >> >> const Eigen::MatrixBase<Eigen::Matrix<float, -0x00000000000000001,
>>>>> >> >> 1,
>>>>> >> >> 0,
>>>>> >> >> -0x00000000000000001, 1> >&)
>>>>> >> >> ./Eigen/src/Core/../plugins/CommonCwiseUnaryOps.h:91: note:
>>>>> >> >> const Eigen::CwiseUnaryOp<Eigen::ei_scalar_multiple_op<float>,
>>>>> >> >> Eigen::Matrix<float, -0x00000000000000001, 1, 0,
>>>>> >> >> -0x00000000000000001,
>>>>> >> >> 1> >
>>>>> >> >> Eigen::operator*(const float&, const
>>>>> >> >> Eigen::MatrixBase<Eigen::Matrix<float,
>>>>> >> >> -0x00000000000000001, 1, 0, -0x00000000000000001, 1> >&)
>>>>> >> >> [2]+ Done gedit test.cpp
>>>>> >> >> cjb@cjb-laptop:/tmp/eigen$ g++ test.cpp -I.
>>>>> >> >> test.cpp: In function ‘int main()’:
>>>>> >> >> test.cpp:20: error: no match for ‘operator*’ in
>>>>> >> >> ‘((Eigen::DenseBase<Eigen::ArrayWrapper<Eigen::Matrix<float,
>>>>> >> >> -0x00000000000000001, -0x00000000000000001, 0, -0x00000000000000001,
>>>>> >> >> -0x00000000000000001> >
>>>>> >> >> >*)(&((Eigen::MatrixBase<Eigen::Matrix<float,
>>>>> >> >> -0x00000000000000001, -0x00000000000000001, 0, -0x00000000000000001,
>>>>> >> >> -0x00000000000000001> >*)(& a))->Eigen::MatrixBase<Derived>::array
>>>>> >> >> [with
>>>>> >> >> Derived = Eigen::Matrix<float, -0x00000000000000001,
>>>>> >> >> -0x00000000000000001,
>>>>> >> >> 0, -0x00000000000000001,
>>>>> >> >> -0x00000000000000001>]()))->Eigen::DenseBase<Derived>::colwise [with
>>>>> >> >> Derived
>>>>> >> >> = Eigen::ArrayWrapper<Eigen::Matrix<float, -0x00000000000000001,
>>>>> >> >> -0x00000000000000001, 0, -0x00000000000000001, -0x00000000000000001>
>>>>> >> >> >]() *
>>>>> >> >> ((Eigen::MatrixBase<Eigen::Matrix<float, -0x00000000000000001, 1, 0,
>>>>> >> >> -0x00000000000000001, 1> >*)(&
>>>>> >> >> b))->Eigen::MatrixBase<Derived>::array
>>>>> >> >> [with
>>>>> >> >> Derived = Eigen::Matrix<float, -0x00000000000000001, 1, 0,
>>>>> >> >> -0x00000000000000001, 1>]()’
>>>>> >> >> ./Eigen/src/Core/../plugins/CommonCwiseUnaryOps.h:95: note:
>>>>> >> >> candidates
>>>>> >> >> are:
>>>>> >> >> const Eigen::CwiseUnaryOp<Eigen::ei_scalar_multiple2_op<float,
>>>>> >> >> std::complex<float> >, Eigen::ArrayWrapper<Eigen::Matrix<float,
>>>>> >> >> -0x00000000000000001, 1, 0, -0x00000000000000001, 1> > >
>>>>> >> >> Eigen::operator*(const std::complex<float>&, const
>>>>> >> >> Eigen::ArrayBase<Eigen::ArrayWrapper<Eigen::Matrix<float,
>>>>> >> >> -0x00000000000000001, 1, 0, -0x00000000000000001, 1> > >&)
>>>>> >> >> ./Eigen/src/Core/../plugins/CommonCwiseUnaryOps.h:91: note:
>>>>> >> >> const Eigen::CwiseUnaryOp<Eigen::ei_scalar_multiple_op<float>,
>>>>> >> >> Eigen::ArrayWrapper<Eigen::Matrix<float, -0x00000000000000001, 1, 0,
>>>>> >> >> -0x00000000000000001, 1> > > Eigen::operator*(const float&, const
>>>>> >> >> Eigen::ArrayBase<Eigen::ArrayWrapper<Eigen::Matrix<float,
>>>>> >> >> -0x00000000000000001, 1, 0, -0x00000000000000001, 1> > >&)
>>>>> >> >> ./Eigen/src/Core/../plugins/CommonCwiseUnaryOps.h:95: note:
>>>>> >> >> const Eigen::CwiseUnaryOp<Eigen::ei_scalar_multiple2_op<float,
>>>>> >> >> std::complex<float> >, Eigen::ArrayWrapper<Eigen::Matrix<float,
>>>>> >> >> -0x00000000000000001, -0x00000000000000001, 0, -0x00000000000000001,
>>>>> >> >> -0x00000000000000001> > > Eigen::operator*(const
>>>>> >> >> std::complex<float>&,
>>>>> >> >> const
>>>>> >> >> Eigen::ArrayBase<Eigen::ArrayWrapper<Eigen::Matrix<float,
>>>>> >> >> -0x00000000000000001, -0x00000000000000001, 0, -0x00000000000000001,
>>>>> >> >> -0x00000000000000001> > >&)
>>>>> >> >> ./Eigen/src/Core/../plugins/CommonCwiseUnaryOps.h:91: note:
>>>>> >> >> const Eigen::CwiseUnaryOp<Eigen::ei_scalar_multiple_op<float>,
>>>>> >> >> Eigen::ArrayWrapper<Eigen::Matrix<float, -0x00000000000000001,
>>>>> >> >> -0x00000000000000001, 0, -0x00000000000000001, -0x00000000000000001>
>>>>> >> >> >
>>>>> >> >> >
>>>>> >> >> Eigen::operator*(const float&, const
>>>>> >> >> Eigen::ArrayBase<Eigen::ArrayWrapper<Eigen::Matrix<float,
>>>>> >> >> -0x00000000000000001, -0x00000000000000001, 0, -0x00000000000000001,
>>>>> >> >> -0x00000000000000001> > >&)
>>>>> >> >> ./Eigen/src/Core/../plugins/CommonCwiseUnaryOps.h:95: note:
>>>>> >> >> const Eigen::CwiseUnaryOp<Eigen::ei_scalar_multiple2_op<float,
>>>>> >> >> std::complex<float> >, Eigen::Matrix<float, -0x00000000000000001,
>>>>> >> >> -0x00000000000000001, 0, -0x00000000000000001, -0x00000000000000001>
>>>>> >> >> >
>>>>> >> >> Eigen::operator*(const std::complex<float>&, const
>>>>> >> >> Eigen::MatrixBase<Eigen::Matrix<float, -0x00000000000000001,
>>>>> >> >> -0x00000000000000001, 0, -0x00000000000000001, -0x00000000000000001>
>>>>> >> >> >&)
>>>>> >> >> ./Eigen/src/Core/../plugins/CommonCwiseUnaryOps.h:91: note:
>>>>> >> >> const Eigen::CwiseUnaryOp<Eigen::ei_scalar_multiple_op<float>,
>>>>> >> >> Eigen::Matrix<float, -0x00000000000000001, -0x00000000000000001, 0,
>>>>> >> >> -0x00000000000000001, -0x00000000000000001> > Eigen::operator*(const
>>>>> >> >> float&,
>>>>> >> >> const Eigen::MatrixBase<Eigen::Matrix<float, -0x00000000000000001,
>>>>> >> >> -0x00000000000000001, 0, -0x00000000000000001, -0x00000000000000001>
>>>>> >> >> >&)
>>>>> >> >> ./Eigen/src/Core/../plugins/CommonCwiseUnaryOps.h:95: note:
>>>>> >> >> const Eigen::CwiseUnaryOp<Eigen::ei_scalar_multiple2_op<float,
>>>>> >> >> std::complex<float> >, Eigen::Matrix<float, -0x00000000000000001, 1,
>>>>> >> >> 0,
>>>>> >> >> -0x00000000000000001, 1> > Eigen::operator*(const
>>>>> >> >> std::complex<float>&,
>>>>> >> >> const Eigen::MatrixBase<Eigen::Matrix<float, -0x00000000000000001,
>>>>> >> >> 1,
>>>>> >> >> 0,
>>>>> >> >> -0x00000000000000001, 1> >&)
>>>>> >> >> ./Eigen/src/Core/../plugins/CommonCwiseUnaryOps.h:91: note:
>>>>> >> >> const Eigen::CwiseUnaryOp<Eigen::ei_scalar_multiple_op<float>,
>>>>> >> >> Eigen::Matrix<float, -0x00000000000000001, 1, 0,
>>>>> >> >> -0x00000000000000001,
>>>>> >> >> 1> >
>>>>> >> >> Eigen::operator*(const float&, const
>>>>> >> >> Eigen::MatrixBase<Eigen::Matrix<float,
>>>>> >> >> -0x00000000000000001, 1, 0, -0x00000000000000001, 1> >&)
>>>>> >> >>
>>>>> >> >>
>>>>> >> >> On Wed, Sep 29, 2010 at 7:49 PM, Benoit Jacob
>>>>> >> >> <jacob.benoit.1@xxxxxxxxx>
>>>>> >> >> wrote:
>>>>> >> >>>
>>>>> >> >>> Does a.array().colwise() * b.array() work ?
>>>>> >> >>>
>>>>> >> >>> We're a bit pedantic if we require putting array() here since the
>>>>> >> >>> colwise() makes it clear what you want to do...
>>>>> >> >>>
>>>>> >> >>> Benoit
>>>>> >> >>>
>>>>> >> >>> 2010/9/29 Carlos Becker <carlosbecker@xxxxxxxxx>:
>>>>> >> >>> > Hi Benoit. No, it doesn't work and it makes sense, since it would
>>>>> >> >>> > be
>>>>> >> >>> > like
>>>>> >> >>> > multiplying a vector by a vector algebraically, which has no
>>>>> >> >>> > sense
>>>>> >> >>> > for a
>>>>> >> >>> > Matrix type (has it?)
>>>>> >> >>> > I wanted to do element-wise multiplication, and I thought that
>>>>> >> >>> > .array().colwise() would cope with that. Just to clarify, I want
>>>>> >> >>> > to
>>>>> >> >>> > do:
>>>>> >> >>> > if A = [1 2;
>>>>> >> >>> > 3 4]
>>>>> >> >>> > and B = [a;b] (matlab notation)
>>>>> >> >>> > then I want to get something like:
>>>>> >> >>> > result = [ 1*a, 2*a;
>>>>> >> >>> > 3*b 4*b ]
>>>>> >> >>> > Should I do this another way? I thought that .array().colwise()
>>>>> >> >>> > was
>>>>> >> >>> > defined
>>>>> >> >>> > to apply the element-wise operation for every column vector in A.
>>>>> >> >>> > Thanks
>>>>> >> >>> >
>>>>> >> >>> > On Wed, Sep 29, 2010 at 7:41 PM, Benoit Jacob
>>>>> >> >>> > <jacob.benoit.1@xxxxxxxxx>
>>>>> >> >>> > wrote:
>>>>> >> >>> >>
>>>>> >> >>> >> 2010/9/29 Carlos Becker <carlosbecker@xxxxxxxxx>:
>>>>> >> >>> >> > Hi all, I was trying to code something like this:
>>>>> >> >>> >> > #include <Eigen/Dense>
>>>>> >> >>> >> > using namespace Eigen;
>>>>> >> >>> >> > using namespace std;
>>>>> >> >>> >> > int main()
>>>>> >> >>> >> > {
>>>>> >> >>> >> > MatrixXf a;
>>>>> >> >>> >> > VectorXf b;
>>>>> >> >>> >> > a.resize(2,4);
>>>>> >> >>> >> > b.resize(2);
>>>>> >> >>> >> > a << 1,2,
>>>>> >> >>> >> > 3,4,
>>>>> >> >>> >> > 5,6,
>>>>> >> >>> >> > 7,8;
>>>>> >> >>> >> > b << 1,2;
>>>>> >> >>> >> > a = a.array().colwise() * b;
>>>>> >> >>> >>
>>>>> >> >>> >> Here you're multiplying an array by a matrix.
>>>>> >> >>> >>
>>>>> >> >>> >> Doesn't a.colwise() * b work?
>>>>> >> >>> >>
>>>>> >> >>> >> Benoit
>>>>> >> >>> >>
>>>>> >> >>> >> > return 0;
>>>>> >> >>> >> > }
>>>>> >> >>> >> > Should this compile correctly? I want to multiply every column
>>>>> >> >>> >> > in
>>>>> >> >>> >> > matrix
>>>>> >> >>> >> > a,
>>>>> >> >>> >> > element-wise, with vector b, but I cannot make it work
>>>>> >> >>> >> > I hope I am not forgetting about something important here..
>>>>> >> >>> >> > Cheers,
>>>>> >> >>> >> > Carlos
>>>>> >> >>> >>
>>>>> >> >>> >>
>>>>> >> >>> >
>>>>> >> >>> >
>>>>> >> >>>
>>>>> >> >>>
>>>>> >> >>
>>>>> >> >>
>>>>> >> >
>>>>> >>
>>>>> >>
>>>>> >
>>>>> >
>>>>>
>>>>>
>>>>
>>>>
>>>
>>>
>>>
>>
>>
>>
>