Using the SciPy DCT function to create a 2D DCT-II - scipy

I am creating a 2D DCT-II in labview but want to be able to check my outputs are correct. SciPy has a nice DCT function which defaults to DCT-II but is 1D.
I want to make it work for a 2D array. To do this the DCT must be applied to the columns and then the DCT must be again applied to the rows of this outcome.
I'm not sure what function I want to use to do this. I have tried np.rot90 which rotates the numpy array 90 degrees counter clockwise as follows:
import numpy as np
from scipy.fftpack import dct
a = np.array([[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0],
[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0],
[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0],
[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0],
[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0],
[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0],
[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0],
[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0]])
b = dct(np.rot90(dct(a),3))
However this outputs the following:
array([[ 1152. , 0. , 0. , 0. ,
0. , 0. , 0. , 0. ],
[ -412.30867345, 0. , 0. , 0. ,
0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ,
0. , 0. , 0. , 0. ],
[ -43.10110726, 0. , 0. , 0. ,
0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ,
0. , 0. , 0. , 0. ],
[ -12.85778584, 0. , 0. , 0. ,
0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ,
0. , 0. , 0. , 0. ],
[ -3.24494866, 0. , 0. , 0. ,
0. , 0. , 0. , 0. ]])
I think that rot90 is not the right function to do what I want to do, perhaps there is a better one?

#Jaime's answer is fine. I'll add that dct has an axis argument for just this purpose. First apply it along, say, axis 0, then along axis 1 of the result:
In [30]: from scipy.fftpack import dct
In [31]: a.shape
Out[31]: (8, 8)
In [32]: t1 = dct(dct(a, axis=0), axis=1)
In [33]: t2 = dct(dct(a.T).T)
In [34]: np.abs(t1 - t2).max()
Out[34]: 0.0

I don't think that a rotation is what you want, since it converts rows into columns, but it also messes with the order of the data. Use np.transpose instead.
To apply dct first by columns, then by rows, you would do something like:
dct(dct(a.T).T)
The trailing .T is equivalent to np.transpose. Note how you need to undo the transposition after you operate on the columns, to get the return aligned by rows again.
I don't think that the order in which you apply the dct, i.e. columns then rows vs. rows then columns, makes any difference, but you could get rows then columns as:
dct(dct(a).T).T

There is now a multidimensional DCT function (and inverse) as well:
>>> from scipy.fft import dctn, idctn
>>> b = dctn(a)
>>> np.allclose(a, idctn(b))
True
https://docs.scipy.org/doc/scipy/reference/generated/scipy.fft.dctn.html

Related

How can I efficiently convert a scipy sparse matrix into a sympy sparse matrix?

I have a matrix A with the following properties.
<1047x1047 sparse matrix of type '<class 'numpy.float64'>'
with 888344 stored elements in Compressed Sparse Column format>
A has this content.
array([[ 1.00000000e+00, -5.85786642e-17, -3.97082034e-17, ...,
0.00000000e+00, 0.00000000e+00, 0.00000000e+00],
[ 6.82195979e-17, 1.00000000e+00, -4.11166786e-17, ...,
0.00000000e+00, 0.00000000e+00, 0.00000000e+00],
[-4.98202332e-17, 1.13957868e-17, 1.00000000e+00, ...,
0.00000000e+00, 0.00000000e+00, 0.00000000e+00],
...,
[ 4.56847824e-15, 1.32261454e-14, -7.22890998e-15, ...,
1.00000000e+00, 0.00000000e+00, 0.00000000e+00],
[-9.11597396e-15, -2.28796167e-14, 1.26624823e-14, ...,
0.00000000e+00, 1.00000000e+00, 0.00000000e+00],
[ 1.80765584e-14, 1.93779820e-14, -1.36520100e-14, ...,
0.00000000e+00, 0.00000000e+00, 1.00000000e+00]])
Now I'm trying to create a sympy sparse matrix from this scipy sparse matrix.
from sympy.matrices import SparseMatrix
A = SparseMatrix(A)
But I get this error message.
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all().
I am confused because this matrix has no logical entries.
Thanks for any help!
The Error
When you get an error that you don't understand, take a bit of time to look at the traceback. Or at least show it to us!
In [288]: M = sparse.random(5,5,.2, 'csr')
In [289]: M
Out[289]:
<5x5 sparse matrix of type '<class 'numpy.float64'>'
with 5 stored elements in Compressed Sparse Row format>
In [290]: print(M)
(1, 1) 0.17737340878962138
(2, 2) 0.12362174819457106
(2, 3) 0.24324155883057885
(3, 0) 0.7666429046432961
(3, 4) 0.21848551209470246
In [291]: SparseMatrix(M)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-291-cca56ea35868> in <module>
----> 1 SparseMatrix(M)
/usr/local/lib/python3.6/dist-packages/sympy/matrices/sparse.py in __new__(cls, *args, **kwargs)
206 else:
207 # handle full matrix forms with _handle_creation_inputs
--> 208 r, c, _list = Matrix._handle_creation_inputs(*args)
209 self.rows = r
210 self.cols = c
/usr/local/lib/python3.6/dist-packages/sympy/matrices/matrices.py in _handle_creation_inputs(cls, *args, **kwargs)
1070 if 0 in row.shape:
1071 continue
-> 1072 elif not row:
1073 continue
1074
/usr/local/lib/python3.6/dist-packages/scipy/sparse/base.py in __bool__(self)
281 return self.nnz != 0
282 else:
--> 283 raise ValueError("The truth value of an array with more than one "
284 "element is ambiguous. Use a.any() or a.all().")
285 __nonzero__ = __bool__
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all().
A full understanding requires reading the sympy code, but a cursory look indicates that it's trying to handle your input as "full matrix", and looks at rows. The error isn't the result of you doing logical operations on the entries, but that sympy is doing a logical test on your sparse matrix. It's trying to check if the row is empty (so it can skip it).
SparseMatrix docs may not be the clearest, but most examples either show a dict of points, or a flat array of ALL values plus shape, or a ragged list of lists. I suspect it's trying to treat your matrix that way, looking at it row by row.
But the row of M is itself a sparse matrix:
In [295]: [row for row in M]
Out[295]:
[<1x5 sparse matrix of type '<class 'numpy.float64'>'
with 0 stored elements in Compressed Sparse Row format>,
<1x5 sparse matrix of type '<class 'numpy.float64'>'
with 1 stored elements in Compressed Sparse Row format>,
...]
And trying to check if that row is empty not row produces this error:
In [296]: not [row for row in M][0]
...
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all().
So clearly SparseMatrix cannot handle a scipy.sparse matrix as is (at least not in the csr or csc format, and probably not the others. Plus scipy.sparse is not mentioned anywhere in the SparseMatrix docs!
from dense array
Converting the sparse matrix to its dense equivalent does work:
In [297]: M.A
Out[297]:
array([[0. , 0. , 0. , 0. , 0. ],
[0. , 0.17737341, 0. , 0. , 0. ],
[0. , 0. , 0.12362175, 0.24324156, 0. ],
[0.7666429 , 0. , 0. , 0. , 0.21848551],
[0. , 0. , 0. , 0. , 0. ]])
In [298]: SparseMatrix(M.A)
Out[298]:
⎡ 0 0 0 0 0 ⎤
...⎦
Or a list of lists:
SparseMatrix(M.A.tolist())
from dict
The dok format stores a sparse matrix as a dict, which then can be
In [305]: dict(M.todok())
Out[305]:
{(3, 0): 0.7666429046432961,
(1, 1): 0.17737340878962138,
(2, 2): 0.12362174819457106,
(2, 3): 0.24324155883057885,
(3, 4): 0.21848551209470246}
Which works fine as an input:
SparseMatrix(5,5,dict(M.todok()))
I don't know what's most efficient. Generally when working with sympy we (or at least I) don't worry about efficiency. Just get it to work is enough. Efficiency is more relevant in numpy/scipy where arrays can be large, and using the fast compiled numpy methods makes a big difference in speed.
Finally - numpy and sympy are not integrated. That applies also to the sparse versions. sympy is built on Python, not numpy. So inputs in the form of lists and dicts makes most sense.
from sympy.matrices import SparseMatrix
import scipy.sparse as sps
A = sps.random(100, 10, format="dok")
B = SparseMatrix(100, 10, dict(A.items()))
From the perspective of someone who likes efficient memory structures this is like staring into the abyss. But it will work.
This is a simplified version of your error.
from scipy import sparse
row = np.array([0, 0, 1, 2, 2, 2])
col = np.array([0, 2, 2, 0, 1, 2])
data = np.array([1, 2, 3, 4, 5, 6])
A = sparse.csc_matrix((data, (row, col)), shape=(3, 3))
So A is a sparse matrix with 6 elements:
<3x3 sparse matrix of type '<class 'numpy.intc'>'
with 6 stored elements in Compressed Sparse Column format>
Calling SparseMatrix() on it returns the same kind of error that you have. You might like to convert A to numpy array first:
>>> SparseMatrix(A.todense())
Matrix([
[1, 0, 2],
[0, 0, 3],
[4, 5, 6]])

Mixed-integer linear programming: How to generate constraints?

I have an objective function such as
(for simplicity I omitted the coefficients).
I want to minimize this function using intlinprog with the following constraints:
and
with all x binary. These sums result in these 4 inequalities:
It is clear that the constaints matrix is
This works well if I create this matrix manually. Now suppose I have 6 or 8 or 10 variables instead of 4 in my objective function and in the constraints (same pattern). How can I use Matlab to generate this constraints matrix for these larger problems?
I recommend writing down some other cases a bit. So it seems you want to constraint all row-sums and all column-sums:
For N=3, there are 9 vars (i'm assuming a square case here; you did not provide complete info):
x00 x01 x02
x10 x11 x12
x20 x21 x22
Now the constraint matrix looks like:
x00 x01 x02 | x10 x11 x12 | x20 x21 x22
---------------------------------------
1 1 1
1 1 1
1 1 1
1 1 1
1 1 1
1 1 1
That's pretty regular. Not it's time to check out matlab's matrix-creation functions. Sadly i'm not much of a matlab-user, but:
the lower half of rows consist of:
horizontal stacking of N identity-matrices each of size N
the upper half of rows consist of:
block-diagonal matrix of N 1-row-vectors each of size N
the final matrix is a vertical stacking of both components
A full sparse-matrix python-example (sorry, no matlab here; but there should be nearly a 1:1 mapping), to be more clear would look like:
import numpy as np
import scipy.sparse as sp
N = 3
component_a = sp.hstack([sp.eye(N) for i in range(N)])
row_full_1 = sp.csr_matrix(np.ones(N))
component_b = sp.block_diag([row_full_1 for i in range(N)]) # matlab: blkdiag?
matrix = sp.vstack((component_b, component_a))
print(matrix.todense())
Output:
[[ 1. 1. 1. 0. 0. 0. 0. 0. 0.]
[ 0. 0. 0. 1. 1. 1. 0. 0. 0.]
[ 0. 0. 0. 0. 0. 0. 1. 1. 1.]
[ 1. 0. 0. 1. 0. 0. 1. 0. 0.]
[ 0. 1. 0. 0. 1. 0. 0. 1. 0.]
[ 0. 0. 1. 0. 0. 1. 0. 0. 1.]]
Remark: depending on N, you need to think about using dense or sparse-matrices. Given N, the ratio of non-zeros in the matrix will be 1/N.

Incorrect eigenvalues SciPy sparse linalg.eigs, eigsh for non-diagonal M matrix

Why do eigh and eigsh from scipy.sparse.linalg as used below give incorrect results when solving the generalized eigenvalue problem A * x = lambda * M * x , if M is non-diagonal?
import mkl
import numpy as np
from scipy import linalg as LA
from scipy.sparse import linalg as LAsp
from scipy.sparse import csr_matrix
A = np.diag(np.arange(1.0,7.0))
M = np.array([[ 25.1, 0. , 0. , 17.3, 0. , 0. ],
[ 0. , 33.6, 16.8, 8.4, 4.2, 2.1],
[ 0. , 16.8, 3.6, 0. , 11. , 0. ],
[ 17.3, 8.4, 0. , 4.2, 0. , 9.5],
[ 0. , 4.2, 11. , 0. , 2.7, 8.3],
[ 0. , 2.1, 0. , 9.5, 8.3, 4.4]])
Asp = csr_matrix(np.matrix(A,dtype=float))
Msp = csr_matrix(np.matrix(M,dtype=float))
D, V = LA.eig(A, b=M)
eigno = 4
Dsp0, Vsp0 = LAsp.eigs(csr_matrix(np.matrix(np.dot(np.linalg.inv(M),A))),
k=eigno,which='LM',return_eigenvectors=True)
Dsp1, Vsp1 = LAsp.eigs(Asp,k=eigno,M=Msp,which='LM',return_eigenvectors=True)
Dsp2, Vsp2 = LAsp.eigsh(Asp,k=eigno,M=Msp,which='LA',return_eigenvectors=True,
maxiter=1000)
From LA.eig and checking with MatLab the eigenvalues for this small generalized eigenvalue problem with test matrices A and M should be:
D = [ 0.7208+0.j, 0.3979+0.j, -0.3011+0.j, -0.3251+0.j, 0.0357+0.j, 0.0502+0.j]
I want to use sparse matrices because the actual A and M matrices involved are around 30,000 x 30,000. A is always square, real and diagonal, M is always square, real and symmetric. When M is diagonal I get the correct results. However, both eigs and eigsh give incorrect results when solving the generalized eigenvalue problem for a non-diagonal M matrix.
Dsp1 = [-1.6526+2.3357j, -1.6526-2.3357j, -0.6243+2.7334j, -0.6243-2.7334j]
Dsp2 = [ 2.01019097, 3.09248265, 4.06799498, 7.01216316]
When I convert the problem to the standard eigenvalue form M^-1 * A * x = lambda * x, eigs gives the correct result (Dsp0). For large matrices this is not an option because it takes too long to compute the inverse of M.
I noticed that using mkl or not yields different Dsp1 and Dsp2 eigenvalues as well. Could this eigenvalue problem be caused by an issue with my Python installation? I am running Python 2.7.8 anaconda with SciPy 0.15.1 - np19py27_p0 [mkl] on Mac OS 10.10.2.
Both eigs and eigsh require that M be positive definite (see the descriptions of M in the docstrings for more details).
Your matrix M is not positive definite. Note the negative eigenvalues:
In [212]: M
Out[212]:
array([[ 25.1, 0. , 0. , 17.3, 0. , 0. ],
[ 0. , 33.6, 16.8, 8.4, 4.2, 2.1],
[ 0. , 16.8, 3.6, 0. , 11. , 0. ],
[ 17.3, 8.4, 0. , 4.2, 0. , 9.5],
[ 0. , 4.2, 11. , 0. , 2.7, 8.3],
[ 0. , 2.1, 0. , 9.5, 8.3, 4.4]])
In [213]: np.linalg.eigvals(M)
Out[213]:
array([ 45.92443169, 33.92113421, -13.12639751, -10.6991868 ,
5.34183619, 12.23818222])

MATLAB : Compare each element of rx_bs with a threshold value of 0.50

Question : Create a vector of random numbers of size 1×20 and name it as rx_bs. Compare each element of rx_bs with a threshold value of 0.50. If the value of the element is greater than 0.5, it returns value 1, otherwise 0. Therefore, you will obtain another 1x20 vector, name it as bs.
My Answer:
rx_bs=rand(1,20);
threshold_c=0.5;
bs=[1:20];
for i=1:length(rx_bs)
if rx_bs(i)>threshold_c
bs(i)=1;
end
if rx_bs(i)<threshold_c
bs(i)=0;
end
end
rx_bs
bs
Why is this wrong?

Count pixels with certain indices that have a certain value in Matlab

I have two vectors xx and yy holding the x and y indices of certain pixels respectively in matrix A . What I want to do is to check the values of the pixels with those indices and count how many of those pixels have the value 0. For example, if xx=[1 2 3] and y=[2 5 8], I want to check how many of these pixels(x,y) (1,2), (2,5), (3,8) have the value 0. I can do this with for loops but I think it can be done easier in Matlab, so if anyone could please advise.
The following should work:
sum(A(sub2ind(size(A),xx,yy)) == 0)
First, you convert the row and column indices into single indices into the matrix A. Then, you check where A is zero for these indices (which will result in ones). Then you simply sum up the ones.
A dirtier way than sub2ind is
sum( A( [1 size(A,1)]*( [ yy; xx ] - 1 ) + 1 ) == 0 )
You can check here and see that the dirty method is ~x4 times faster than sub2ind. So, if you are in need for speed, use the dirty method ;)