How should I use Cramer’s rule in Matlab? - matlab

The relationship between the two matrices is shown is Ax=B.
How do I find x using Cramer’s rule?
A=[521 202 -176 612;-761 41 -655 712;314 102 -234 891;612 291 209 -318]
B=[718;408;215;356]

You can use Cramer's rule like this for your specific 4x4 case. The element at index i of the result x is given by the ratio of 2 determinants (See the wikipedia link for a full explanation) - you can create the result with the following loop
x = ones(4,1);
a_det = det(A);
for i = 1:4
C = A;
C(:,i) = B;
x(i,1) = det(C)/a_det;
end
the column vector x should now be your result. There could be a faster way to do this but this should work. You can verify this by comparing the result with
x = A\B;

Related

Multiple constant to a matrix and convert them into block diagonal matrix in matlab

I have a1 a2 a3. They are constants. I have a matrix A. What I want to do is to get a1*A, a2*A, a3*A three matrices. Then I want transfer them into a diagonal block matrix. For three constants case, this is easy. I can let b1 = a1*A, b2=a2*A, b3=a3*A, then use blkdiag(b1, b2, b3) in matlab.
What if I have n constants, a1 ... an. How could I do this without any looping?I know this can be done by kronecker product but this is very time-consuming and you need do a lot of unnecessary 0 * constant.
Thank you.
Discussion and code
This could be one approach with bsxfun(#plus that facilitates in linear indexing as coded in a function format -
function out = bsxfun_linidx(A,a)
%// Get sizes
[A_nrows,A_ncols] = size(A);
N_a = numel(a);
%// Linear indexing offsets between 2 columns in a block & between 2 blocks
off1 = A_nrows*N_a;
off2 = off1*A_ncols+A_nrows;
%// Get the matrix multiplication results
vals = bsxfun(#times,A,permute(a,[1 3 2])); %// OR vals = A(:)*a_arr;
%// Get linear indices for the first block
block1_idx = bsxfun(#plus,[1:A_nrows]',[0:A_ncols-1]*off1); %//'
%// Initialize output array base on fast pre-allocation inspired by -
%// http://undocumentedmatlab.com/blog/preallocation-performance
out(A_nrows*N_a,A_ncols*N_a) = 0;
%// Get linear indices for all blocks and place vals in out indexed by them
out(bsxfun(#plus,block1_idx(:),(0:N_a-1)*off2)) = vals;
return;
How to use: To use the above listed function code, let's suppose you have the a1, a2, a3, ...., an stored in a vector a, then do something like this out = bsxfun_linidx(A,a) to have the desired output in out.
Benchmarking
This section compares or benchmarks the approach listed in this answer against the other two approaches listed in the other answers for runtime performances.
Other answers were converted to function forms, like so -
function B = bsxfun_blkdiag(A,a)
B = bsxfun(#times, A, reshape(a,1,1,[])); %// step 1: compute products as a 3D array
B = mat2cell(B,size(A,1),size(A,2),ones(1,numel(a))); %// step 2: convert to cell array
B = blkdiag(B{:}); %// step 3: call blkdiag with comma-separated list from cell array
and,
function out = kron_diag(A,a_arr)
out = kron(diag(a_arr),A);
For the comparison, four combinations of sizes of A and a were tested, which are -
A as 500 x 500 and a as 1 x 10
A as 200 x 200 and a as 1 x 50
A as 100 x 100 and a as 1 x 100
A as 50 x 50 and a as 1 x 200
The benchmarking code used is listed next -
%// Datasizes
N_a = [10 50 100 200];
N_A = [500 200 100 50];
timeall = zeros(3,numel(N_a)); %// Array to store runtimes
for iter = 1:numel(N_a)
%// Create random inputs
a = randi(9,1,N_a(iter));
A = rand(N_A(iter),N_A(iter));
%// Time the approaches
func1 = #() kron_diag(A,a);
timeall(1,iter) = timeit(func1); clear func1
func2 = #() bsxfun_blkdiag(A,a);
timeall(2,iter) = timeit(func2); clear func2
func3 = #() bsxfun_linidx(A,a);
timeall(3,iter) = timeit(func3); clear func3
end
%// Plot runtimes against size of A
figure,hold on,grid on
plot(N_A,timeall(1,:),'-ro'),
plot(N_A,timeall(2,:),'-kx'),
plot(N_A,timeall(3,:),'-b+'),
legend('KRON + DIAG','BSXFUN + BLKDIAG','BSXFUN + LINEAR INDEXING'),
xlabel('Datasize (Size of A) ->'),ylabel('Runtimes (sec)'),title('Runtime Plot')
%// Plot runtimes against size of a
figure,hold on,grid on
plot(N_a,timeall(1,:),'-ro'),
plot(N_a,timeall(2,:),'-kx'),
plot(N_a,timeall(3,:),'-b+'),
legend('KRON + DIAG','BSXFUN + BLKDIAG','BSXFUN + LINEAR INDEXING'),
xlabel('Datasize (Size of a) ->'),ylabel('Runtimes (sec)'),title('Runtime Plot')
Runtime plots thus obtained at my end were -
Conclusions: As you can see, either one of the bsxfun based methods could be looked into, depending on what kind of datasizes you are dealing with!
Here's another approach:
Compute the products as a 3D array using bsxfun;
Convert into a cell array with one product (matrix) in each cell;
Call blkdiag with a comma-separated list generated from the cell array.
Let A denote your matrix, and a denote a vector with your constants. Then the desired result B is obtained as
B = bsxfun(#times, A, reshape(a,1,1,[])); %// step 1: compute products as a 3D array
B = mat2cell(B,size(A,1),size(A,2),ones(1,numel(a))); %// step 2: convert to cell array
B = blkdiag(B{:}); %// step 3: call blkdiag with comma-separated list from cell array
Here's a method using kron which seems to be faster and more memory efficient than Divakar's bsxfun based solution. I'm not sure if this is different to your method, but the timing seems pretty good. It might be worth doing some testing between the different methods to work out which is more efficient for you problem.
A=magic(4);
a1=1;
a2=2;
a3=3;
kron(diag([a1 a2 a3]),A)

Why does my function return two values when I only return one?

So I'm trying to implement the Simpson method in Matlab, this is my code:
function q = simpson(x,f)
n = size(x);
%subtracting the last value of the x vector with the first one
ba = x(n) - x(1);
%adding all the values of the f vector which are in even places starting from f(2)
a = 2*f(2:2:end-1);
%adding all the values of the f vector which are in odd places starting from 1
b = 4*f(1:2:end-1);
%the result is the Simpson approximation of the values given
q = ((ba)/3*n)*(f(1) + f(n) + a + b);
This is the error I'm getting:
Error using ==> mtimes
Inner matrix dimensions must agree.
For some reason even if I set q to be
q = f(n)
As a result I get:
q =
0 1
Instead of
q =
0
When I set q to be
q = f(1)
I get:
q =
0
q =
0
I can't explain this behavior, that's probably why I get the error mentioned above. So why does q have two values instead of one?
edit: x = linspace(0,pi/2,12);
f = sin(x);
size(x) returns the size of the array. This will be a vector with all the dimensions of the matrix. There must be at least two dimensions.
In your case n=size(x) will give n=[N, 1], not just the length of the array as you desire. This will mean than ba will have 2 elements.
You can fix this be using length(x) which returns the longest dimension rather than size (or numel(x) or size(x, 1) or 2 depending on how x is defined which returns only the numbered dimension).
Also you want to sum over in a and b whereas now you just create an vector with these elements in. try changing it to a=2*sum(f(...)) and similar for b.
The error occurs because you are doing matrix multiplication of two vectors with different dimensions which isn't allowed. If you change the code all the values should be scalars so it should work.
To get the correct answer (3*n) should also be in brackets as matlab doesn't prefer between / and * (http://uk.mathworks.com/help/matlab/matlab_prog/operator-precedence.html). Your version does (ba/3)*n which is wrong.

Assign values from vector to a specific part of another vector [Matlab]

I am fairly new to matlab. I am sure there is a nice way to do this.
I have the vector h which contains 1257 elements.
And I have the vector t which contains 101 elements.
What I want is to assign the vector t from the 529th to the 630th element from vector h.
I tried this:
h(529:630) = t;
Then I get this message: "In an assignment A(I) = B, the number of elements in B and I must be the same."
If I use a scalar it works. For example:
h(529:630) = 5;
No problem there.
Can someone come up with something clever :)?
Thx
h(529:630) will have 630 - 529 + 1 = 102 elements
>> length(h(529:630))
ans =
102
You must use :
h(530:630) = t ;
Or
h(529:629) = t ;
whatever the case may be.

How to compare array to a number for if statement?

H0 is an array ([1:10]), and H is a single number (5).
How to compare every element in H0 with the single number H?
For example in
if H0>H
do something
else
do another thing
end
MATLAB always does the other thing.
if requires the following statement to evaluate to a scalar true/false. If the statement is an array, the behaviour is equivalent to wrapping it in all(..).
If your comparison results in a logical array, such as
H0 = 1:10;
H = 5;
test = H0>H;
you have two options to pass test through the if-statement:
(1) You can aggregate the output of test, for example you want the if-clause to be executed when any or all of the elements in test are true, e.g.
if any(test)
do something
end
(2) You iterate through the elements of test, and react accordingly
for ii = 1:length(test)
if test(ii)
do something
end
end
Note that it may be possible to vectorize this operation by using the logical vector test as index.
edit
If, as indicated in a comment, you want P(i)=H0(i)^3 if H0(i)<H, and otherwise P(i)=H0(i)^2, you simply write
P = H0 .^ (H0<H + 2)
#Jonas's nice answer at his last line motivated me to come up with a version using logical indexing.
Instead of
for i=1:N
if H0(i)>H
H0(i)=H0(i)^2;
else
H0(i)=H0(i)^3;
end
end
you can do this
P = zeros(size(H0)); % preallocate output
test = H0>H;
P(test) = H0(test).^2; % element-wise operations
% on the elements for which the test is true
P(~test) = H0(~test).^3; % element-wise operations
% on the elements for which the test is false
Note that this is a general solution.
Anyway take a look at this: using ismemeber() function. Frankly not sure how do you expect to compare. Either greater than, smaller , equal or within as a member. So my answer might not be yet satisfying to you. But just giving you an idea anyway.
H0 = [0 2 4 6 8 10 12 14 16 18 20];
H = [10];
ismember(H,H0)
IF (ans = 1) then
// true
else
//false
end
Update Answer
This is super bruteforce method - just use it explain. You are better off with any other answers given here than what I present. Ideally what you need is to rip off greater/lower values into two different vectors with ^3 processing - I assume... :)
H0 = [0 2 4 6 8 10 12 14 16 18 20];
H = [10];
H0(:)
ans =
0
2
4
6
8
10
12
14
16
18
20
Function find returns indices of all values in H0 greater than 10 values in a linear index.
X = find(H0>H)
X =
7
8
9
10
11
Function find returns indices of all values in H0 lower than 10 in a linear index.
Y = find(H0<H)
Y =
1
2
3
4
5
6
If you want you can access each element of H0 to check greater/lower values or you can use the above matrices with indices to rip the values off H0 into two different arrays with the arithmetic operations.
G = zeros(size(X)); // matrix with the size = number of values greater than H
J = zeros(size(Y)); // matrix with the size = number of values lower than H
for i = 1:numel(X)
G(i) = H0(X(i)).^3
end
G(:)
ans =
1728
2744
4096
5832
8000
for i = 1:numel(Y)
J(i) = H0(Y(i)).^2
end
J(:)
ans =
0
4
16
36
64
100

matlab - error with cross product

I am having an issue with the cross product function. I need to take the cross product of two vectors for each pixel, and then sum the results of all pixels.
i=1;
[h,w,d] = size(current_vec);
for pxRow = 1:h % fixed pixel row
for pxCol = 1:w % fixed pixel column
for pxsize = 1:d
for r = 1:h % row of distant pixel
for c = 1:w % column of distant pixel
for dpth = 1:d
bfield(c,r,dpth) = cross(current_vec(c,r,dpth),dist_vec(c,r,dpth)); % pythagoras theorem to get distance to each pixel % unit vector from x to s
end
end
end
Bfield(i) = {bfield}; % filling a cell array with results. read below
i = i+1;
end
end
end
??? Error using ==> cross at 37
A and B must have at least one dimension of length 3.
??? Error using ==> cross at 37
A and B must have at least one dimension of length 3.
Error in ==> MAC2 at 71
bfield(c,r,dpth) = cross(current_vec(c,r,dpth),dist_vec(c,r,dpth));
however the offending vectors current_vec and dist_vec are the following:
>> size(current_vec)
ans =
35 35 3
>> size(dist_vec)
ans =
35 35 3
so as far as I'm concerned they fill the criteria to be used in a cross product. why isn't this the case?
You need to use the vectorized form of cross:
bfield = cross(current_vec,dist_vec);
cross will work on the first dimension with length of 3. The way you were doing it with nested loops, you're accessing a single element (a scalar) by indexing. You can't cross a scalar with a scalar.