[SciPy-Dev] linalg.toeplitz and ticker #667

Warren Weckesser warren.weckesser at enthought.com
Sun Mar 7 22:01:39 EST 2010


josef.pktd at gmail.com wrote:
> On Sun, Mar 7, 2010 at 8:32 PM, Warren Weckesser
> <warren.weckesser at enthought.com> wrote:
>   
>> Warren Weckesser wrote:
>>     
>>> I am going to update linalg.toeplitz to fix the problem reported in
>>> ticket #667, but I have some questions about the desired behavior of
>>> the function when either `c` (the first column) or `r` (the first row)
>>> is complex.  The docstring does not say anything about complex values,
>>> but the code does some undocumented and unexpected things in this
>>> case, one example of which is the bug reported in the ticket #667.
>>>
>>> I would like to fix this, but I would first like opinions on exactly
>>> how it *should* handle complex arguments.  I *think* the idea is that
>>> if `c` is complex and `r` is not given, then a Hermitian Toeplitz
>>> matrix is created.  Is that correct?  Note that this requires that
>>> c[0] be real, since c[0] is the value that will be in the diagonal of
>>> the matrix.
>>>
>>>       

It looks like the behavior was copied from Matlab:

http://www.mathworks.com/access/helpdesk/help/techdoc/ref/toeplitz.html

>>> While I am fixing this, I would like to remove the printed warning
>>> that occurs when r[0] != c[0].  I would like to change this to raise
>>> a ValueError--that is, adopt the philosophy that either the arguments
>>> are correct (and the code handles them as [not yet, but soon to be]
>>> documented in the docstring, with no warnings needed), or the
>>> arguments are wrong and an exception should be raised.
>>>
>>> This means that when `r` is not given, an exception would be raised
>>> if c[0] is not real.
>>>
>>> A very different way to handle the case of `r` not being given is to
>>> assume it means a square matrix should be created with r[1:] = 0
>>> (i.e. zeros in all the upper off-diagonals).  This avoids the whole
>>> issue of complex numbers and conjugates, but it is also a more
>>> drastic change.
>>>       
>
> a lot of code relies on toeplitz of a single argument to build the
> symmetric matrix.
>
>   

OK, thanks--that's good to know.

>>>       
>> By the way, that is how linalg.hankel handles the case where `r` is not
>> given.
>>     
>
> ??
>
>   

I'm not sure what your question marks mean.  What I meant by "that is 
how linalg.hankel handles [it]" was that when `r` is not given, hankel 
uses zeros to fill in the bottom row.  Your examples demonstrate this.  
My point is moot, since if there is "a lot of code" that relies on 
creating a symmetric/hermitian matrix, it would be a bad idea to make 
such a significant change to the API.

>>>> import scipy.linalg
>>>> scipy.linalg.toeplitz(np.arange(4))
>>>>         
> array([[0, 1, 2, 3],
>        [1, 0, 1, 2],
>        [2, 1, 0, 1],
>        [3, 2, 1, 0]])
>   
>>>> scipy.linalg.hankel(np.arange(4))
>>>>         
> array([[ 0.,  1.,  2.,  3.],
>        [ 1.,  2.,  3.,  0.],
>        [ 2.,  3.,  0.,  0.],
>        [ 3.,  0.,  0.,  0.]])
>   
>>>> scipy.linalg.hankel(np.arange(4)+1.j)
>>>>         
> array([[ 0.+1.j,  1.+1.j,  2.+1.j,  3.+1.j],
>        [ 1.+1.j,  2.+1.j,  3.+1.j,  0.+0.j],
>        [ 2.+1.j,  3.+1.j,  0.+0.j,  0.+0.j],
>        [ 3.+1.j,  0.+0.j,  0.+0.j,  0.+0.j]])
>   
>>>> scipy.linalg.toeplitz(np.arange(4)+1.j)
>>>>         
> Warning: column and row values don't agree; column value used.
> array([[ 0.+1.j,  1.+1.j,  2.+1.j,  3.+1.j],
>        [ 1.-1.j,  0.+1.j,  1.+1.j,  2.+1.j],
>        [ 2.-1.j,  1.-1.j,  0.+1.j,  1.+1.j],
>        [ 3.-1.j,  2.-1.j,  1.-1.j,  0.+1.j]])
>
>
> requiring the diagonal to be real might be too tough, I'm not using
> complex toeplitz, but for other cases, I often have "almost real"
> values, up to numerical imprecision.
>
>   

This could be dealt with like Matlab does: don't worry about it, and 
just use c[1:] to fill in r[1:].  If c[0] is has nonzero imaginary part, 
then the matrix is not Hermitian--but that's OK, since that is what the 
user gave to the function.

Your example illustrates one of the bugs: note that, except for the 
first element, the first column is the *conjugate* of the first 
argument.  The docstring says that `c` is the first column (and the 
optional second argument is the first row).  So it is the elements in 
the first row starting in the second column that should be conjugated.  
It also prints that annoying warning.

>>>> scipy.linalg.toeplitz(np.arange(4)*1.j,-np.arange(4)*1.j)
>>>>         
> array([[ 0.+0.j,  0.-1.j,  0.-2.j,  0.-3.j],
>        [ 0.+1.j,  0.+0.j,  0.-1.j,  0.-2.j],
>        [ 0.+2.j,  0.+1.j,  0.+0.j,  0.-1.j],
>        [ 0.+3.j,  0.+2.j,  0.+1.j,  0.+0.j]])
>
> also for real values  r[0] != c[0] might not be satisfied if there is
> numerical imprecision and they are only almost equal.
>
>   


True.  So if the requirement that r[0] == c[0] is strict, a user who 
knows the first values are "close enough", but maybe not exactly equal, 
would have to do something like:

r[0] = c[0]
t = toeplitz(c, r)

I could live with that, but not everyone will agree.

Instead, the function could require that the values be "close", using 
something like numpy.allclose(), but how close is close enough?  Should 
the function then have `atol` and `rtol` arguments to use for the 
comparison?  This feels like overkill, and is not my preference.

So that leaves the behavior used by Matlab: use c[0], and ignore r[0].  
But I don't like the printed warning (or any logged warning) when c[0] 
!= r[0].  If the program is behaving correctly, and as documented, no 
warning should be necessary.

(If I could start from scratch, I would simply define the `r` argument 
to give the values from the second column onward, and so completely 
avoid the issue.)

Warren




More information about the SciPy-Dev mailing list