inarighas
inarighas

Reputation: 861

Generating a specific Symmetric Matrix

I want a fast method (one line, in python numpy or matlab) to generate a specific symmetric Matrix knowing it dimensions and a parameter a.

This matrix should have 1-a on the diagonal and a elsewhere:

1-a a a a ....... a a 1-a a ........... a a a 1-a a a a . . . . . . 1-a a a .......................... 1-a

Upvotes: 0

Views: 108

Answers (4)

Paul Panzer
Paul Panzer

Reputation: 53029

Here is a numpy one liner

a = 0.7
n = 4

np.where(np.eye(n), 1-a, a)
# array([[0.3, 0.7, 0.7, 0.7],
#        [0.7, 0.3, 0.7, 0.7],
#        [0.7, 0.7, 0.3, 0.7],
#        [0.7, 0.7, 0.7, 0.3]])

If speed is a concern then I recommend

res = np.full((n, n), a)
np.einsum('ii->i', res)[:] = 1-a
res
# array([[0.3, 0.7, 0.7, 0.7],
#        [0.7, 0.3, 0.7, 0.7],
#        [0.7, 0.7, 0.3, 0.7],
#        [0.7, 0.7, 0.7, 0.3]])

Upvotes: 2

Yvon
Yvon

Reputation: 2983

@Savithru has two excellent answers in Matlab. Here I just want to do it for fun....

EDIT: Surprisingly, repmat followed by reshape is actually faster than addition. In the following example, different methods, including Savithru's, are timed and compared.

n = 1e4;
a = 2;
timeit(@() reshape([repmat([1-a, a*ones(1,n)], 1,n-1),1-a], n,n))
timeit(@() a*ones(n,n) + (1-2*a)*eye(n))
timeit(@() a*ones(n,n) + (1-2*a)*diag(ones(n,1)))
timeit(@() testf(a,n))

function y = testf(a,n)
A = a*ones(n,n);
A(1:n+1:end) = 1-a;
y = A;
end


ans =

    0.7034


ans =

    1.0010


ans =

    1.0091


ans =

    0.4209

Upvotes: 2

Savithru
Savithru

Reputation: 745

In MATLAB you can do:

a*ones(n,n) + (1-2*a)*diag(ones(n,1))

where n is the size of your matrix.

If you can live with two lines, you could also do:

A = a*ones(n,n);
A(1:n+1:end) = 1-a; %this sets the diagonal entries

which I think is slightly more efficient.

Upvotes: 3

sacuL
sacuL

Reputation: 51335

The methods below might not be 1 line, but they should be fast!

method 1: create array with np.ones and fill with fill_diagonal

with numpy, you can use np.ones and np.fill_diagonal:

a = 5
size = 5

arr = np.ones((size,size)) * a
np.fill_diagonal(arr, a-1)

>>> arr
array([[4., 5., 5., 5., 5.],
       [5., 4., 5., 5., 5.],
       [5., 5., 4., 5., 5.],
       [5., 5., 5., 4., 5.],
       [5., 5., 5., 5., 4.]])

method 2: fill the diagonal with np.diag_indices instead:

Alternatively, using np.diag_indices:

arr = np.ones((size,size)) * a
di = np.diag_indices(size)
arr[di] = a-1

method 3: create array with np.full

You can also create the original array using np.full instead of np.ones:

arr = np.full((size,size), a)
np.fill_diagonal(arr, a-1)
# or:
# arr = np.full((size,size), a)
# np.fill_diagonal(arr, a-1)

Upvotes: 1

Related Questions