Reputation: 6424
I am looking for a more efficient way to make the following matrix L
:
|2 -2 0 0 0 |
|-1 2 -1 0 0 0 |
|0 -1 2 -1 0 |
(1/2).|0 0 -1 2 -1 |
| . . . |
| 0 0 -1 2 -1|
| 0 0 -2 2|
So far I have got this:
L = diag(ones(n,1)*2)- ...
diag(ones(n-1,1),1) - ...
diag(ones(n-1,1),-1);
L(1,2) = -2;
L(end,end-1) = -2;
L = L/2;
for instance for n=5
it produces:
L =
1.0000 -1.0000 0 0 0
-0.5000 1.0000 -0.5000 0 0
0 -0.5000 1.0000 -0.5000 0
0 0 -0.5000 1.0000 -0.5000
0 0 0 -1.0000 1.0000
n
can be a value in range [5 1000]
.
Upvotes: 3
Views: 73
Reputation: 104484
Instead, try using 2D convolution with conv2
where the input is the identity matrix and a horizontal [-0.5 1 -0.5]
filter tap is the kernel. This is nice because you can consider this identity matrix as an image and you are performing an edge detection where the only time you will get a coefficient of 1 in the output is when the centre of the kernel is directly on top of a 1. If the kernel centre is not on a 1 but any of the elements are touching a 1, the result would be -0.5. This is nice but it doesn't handle the border cases with the top and bottom row. That unfortunately you have to modify manually. We can escape using two statements to modify the elements in favour of using column-major indexing instead. This solution certainly beats using 3 diag
calls IMHO.
n = 5;
L = conv2(eye(n), [-0.5 1 -0.5], 'same');
L([n+1 end-n]) = -1;
Result:
>> L
L =
1.0000 -1.0000 0 0 0
-0.5000 1.0000 -0.5000 0 0
0 -0.5000 1.0000 -0.5000 0
0 0 -0.5000 1.0000 -0.5000
0 0 0 -1.0000 1.0000
Upvotes: 5
Reputation: 112659
Here's another way:
n = 5;
L = full(spdiags(repmat([-1 2 -1],n,1), [-1 0 1], zeros(n)));
L([n+1 end-n]) = -2;
Upvotes: 3