how to define an array with fractional index number - matlab

Like suppose that I need to create a function named pressure denoted by p (a 2-D matrix) which depends on 2 variables r and z.
u, v, w are linear matrices which also depend on 2 variables r and z.
r and z are linear matrix defined below take i={1,2,3,4,5,6,7,8,9,10}
r(i)=i/10
z(i)=i/10
u(i) = 2*r(i) + 3*z(i)
v(i) = 8*r(i) + 4*z(i)
w(i) = 3*r(i) + 2*z(i)
p = p(r,z) %, which is given as,
p(r(i),z(j)) = 2*v(i) - 4*u(i) + w(j)
Now suppose the value of p at a given location (r,z) say (0.4,0.8) is needed, I want that if I give the input p(0.4,0.8), I get the result.

In your case the easiest way is to convert the fractional numbers to integers by multiplying by 10.
This way the location (r,z) = (0.4, 0.8) will become (4,8).
If you don't want to remember every time to provide the locations multiplied by 10, just create a function that will do it for you, so you can call the function with the fractional location.
If your matrices are linear, you will always find a multiplying factor to get rid of the fractional coordinates.

Not entirely sure what you mean here, but if your matrix is only defined in the indices you give (i.e. you only want to draw values from the fixed set of indices you defined), then this should do it:
% the query indices
r_i = 0.4;
z_i = 0.8;
value = p(r_i*10,z_i*10);
if you want to look at values between the ones you defined, you need to look at interpolation:
% the query indices
r_i = 0.46;
z_i = 0.84;
value = interp2(r,z, p, r_i, z_i);
(I may have gotten r and z in that last function in the wrong order, try it out).

Related

MatLab :: Assume and find different possible unknown variables of inequalities ,

I have inequalities with two unknown variables. So how could I assume one variable with different values and get the others?
For instance: -15<10*x+2*y<20.
How could I assume x=2, 3, and so on, and then find answer of (y) depending on the value of (x)?
I have been trying to apply the assume and find commands, but unfortunately, I could not. So I hope anyone could help me, please.
Looking forward to hearing from you.
I am new to Matlab, so I have been trying to apply solve, assume, and find commands
clear all;
clc;
syms x y real;
z=solve(-15<10*x+2*y,[x y])
b=solve(10*x+2*y<20,[x y])
yinterval = [ z,b]
I expect the output: to assume x=different numbers and then y= be a list of possible results depending on the value of x
Thanks,
For each value of x, technically there are infinite values of y that satisfy those equations, so for my solution, I assumed x and y were integer values. As well, it appears that you want to give the program a set of x values and have it calculate y values for each x value. Instead of using the solve command, we can simply use a couple of loops to find all satisfactory integer values of y for each value of x.
To start, we need to make a results matrix to store each x,y pair that satisfies the equations you've given. This is called pre-allocation, as we're pre-allocating the space needed to store our answers. Using the equations, we can deduce that there will be 17 satisfactory y values per x. So, our first two lines of code will be initializing the desired x-values and the results matrix:
xVec = 1:5; %x-vector, change this to whatever x-values you want to test
results = zeros(length(xVec)*14, 2); %results matrix
Note: If you decide to iterate x or y by a value different than +1 (more on that later), you'll need to come up with a different method of creating this results matrix. You could also just not pre-allocate the results matrix, but your code will run slower as the size of the results matrix will be changing on each loop.
Next are the loops. Admittedly, this is not the most elegant solution, but it'll get the job done. First, we need an index to keep up with where we are in our results matrix. This is pretty easy, we'll just call it index and start at 1 (since MATLAB indexes from 1 in matrices. Remember that!):
index = 1; %index for results matrix
Next, we need to loop through each value in our x-vector. Simply use a for loop:
for x = xVec
...
For each value of x, there is a minimum value of y. This value can be solved for in
-15 < 10*x + 2*y --> -14 = 10*x + 2*y_min
So, simply solving for y gives us our next line of code:
y = -7 - 5*x; %solving for y
Note: each time we iterate x in our for loop, a new starting value of y will be calculated.
Finally, we need to loop through values of y that still satisfy the inequalities given. This is performed through use of a while loop:
while 10*x + 2*y > -15 && 10*x + 2*y < 20
...
Note: && is the 'and' statement while using loops. You can't use a single equation for this (i.e. you can't say something like -15 < x < 20, you have to split them up using &&).
Since we solved for the first value of y, we can go ahead and record the current x and y values in our results matrix:
results(index, :) = [x, y]; %storing current x- and y-values
Then, we need to iterate y, as otherwise we'd be stuck in this while-loop forever.
y = y + 1;
Note: You can iterate this y-value with whatever amount you want. I chose to iterate by 1 each time, as I assumed you wanted to find integer values. Just change the +1 to whatever value you want.
Finally, we iterate our index, so that the next pair of x,y values that satisfy our equations don't overwrite our previous solutions.
index = index + 1;
All that's left is to close our loops and run! As I said, this isn't the most efficient solution, so I wouldn't use this for large amounts of x- and y-values. As well, like with iterating the y-values, the x-values can have any 'step-size' you want. As it's coded currently, it jumps +1 between each x, but changing the xVec input to any vector will still work (ex. xVec = 1:0.1:5; iterates the x-value by +0.1 each step instead of +1).
Here's the code all together, sans comments (since I wrote the comments while making the above code snippets):
xVec = 1:5;
results = zeros(length(xVec)*14, 2);
index = 1;
for x = xVec
y = -7 - 5*x;
while 10*x + 2*y > -15 && 10*x + 2*y < 20
results(index, :) = [x, y];
y = y + 1;
index = index + 1;
end
end
Let me know if you have any questions!

Generating all ordered samples with replacement

I would like to generate an array which contains all ordered samples of length k taken from a set of n elements {a_1,...,a_n}, that is all the k-tuples (x_1,...,x_k) where each x_j can be any of the a_i (repetition of elements is allowed), and whose total number is n^k.
Is there a built-in function in Matlab to obtain it?
I have tried to write a code that iteratively uses the datasample function, but I couldn't get what desired so far.
An alternative way to get all the tuples is based on k-base integer representation.
If you take the k-base representation of all integers from 0 to n^k - 1, it gives you all possible set of k indexes, knowing that these indexes start at 0.
Now, implementing this idea is quite straightforward. You can use dec2base if k is lower than 10:
X = A(dec2base(0:(n^k-1), k)-'0'+1));
For k between 10 and 36, you can still use dec2base but you must take care of letters as there is a gap in ordinal codes between '9' and 'A':
X = A(dec2base(0:(n^k-1), k)-'0'+1));
X(X>=17) = X(X>=17)-7;
Above 36, you must use a custom made code for retrieving the representation of the integer, like this one. But IMO you may not need this as 2^36 is quite huge.
What you are looking for is ndgrid: it generates the grid elements in any dimension.
In the case k is fixed at the moment of coding, get all indexes of all elements a this way:
[X_1, ..., X_k] = ndgrid(1:n);
Then build the matrix X from vector A:
X = [A(X_1(:)), ..., A(X_k(:))];
If k is a parameter, my advice would be to look at the code of ndgrid and adapt it in a new function so that the output is a matrix of values instead of storing them in varargout.
What about this solution, I don't know if it's as fast as yours, but do you think is correct?
function Y = ordsampwithrep(X,K)
%ordsampwithrep Ordered samples with replacement
% Generates an array Y containing in its rows all ordered samples with
% replacement of length K with elements of vector X
X = X(:);
nX = length(X);
Y = zeros(nX^K,K);
Y(1,:) = datasample(X,K)';
k = 2;
while k < nX^K +1
temprow = datasample(X,K)';
%checknew = find (temprow == Y(1:k-1,:));
if not(ismember(temprow,Y(1:k-1,:),'rows'))
Y(k,:) = temprow;
k = k+1;
end
end
end

Optimize nested for loop for calculating xcorr of matrix rows

I have 2 nested loops which do the following:
Get two rows of a matrix
Check if indices meet a condition or not
If they do: calculate xcorr between the two rows and put it into new vector
Find the index of the maximum value of sub vector and replace element of LAG matrix with this value
I dont know how I can speed this code up by vectorizing or otherwise.
b=size(data,1);
F=size(data,2);
LAG= zeros(b,b);
for i=1:b
for j=1:b
if j>i
x=data(i,:);
y=data(j,:);
d=xcorr(x,y);
d=d(:,F:(2*F)-1);
[M,I] = max(d);
LAG(i,j)=I-1;
d=xcorr(y,x);
d=d(:,F:(2*F)-1);
[M,I] = max(d);
LAG(j,i)=I-1;
end
end
end
First, a note on floating point precision...
You mention in a comment that your data contains the integers 0, 1, and 2. You would therefore expect a cross-correlation to give integer results. However, since the calculation is being done in double-precision, there appears to be some floating-point error introduced. This error can cause the results to be ever so slightly larger or smaller than integer values.
Since your calculations involve looking for the location of the maxima, then you could get slightly different results if there are repeated maximal integer values with added precision errors. For example, let's say you expect the value 10 to be the maximum and appear in indices 2 and 4 of a vector d. You might calculate d one way and get d(2) = 10 and d(4) = 10.00000000000001, with some added precision error. The maximum would therefore be located in index 4. If you use a different method to calculate d, you might get d(2) = 10 and d(4) = 9.99999999999999, with the error going in the opposite direction, causing the maximum to be located in index 2.
The solution? Round your cross-correlation data first:
d = round(xcorr(x, y));
This will eliminate the floating-point errors and give you the integer results you expect.
Now, on to the actual solutions...
Solution 1: Non-loop option
You can pass a matrix to xcorr and it will perform the cross-correlation for every pairwise combination of columns. Using this, you can forego your loops altogether like so:
d = round(xcorr(data.'));
[~, I] = max(d(F:(2*F)-1,:), [], 1);
LAG = reshape(I-1, b, b).';
Solution 2: Improved loop option
There are limits to how large data can be for the above solution, since it will produce large intermediate and output variables that can exceed the maximum array size available. In such a case for loops may be unavoidable, but you can improve upon the for-loop solution above. Specifically, you can compute the cross-correlation once for a pair (x, y), then just flip the result for the pair (y, x):
% Loop over rows:
for row = 1:b
% Loop over upper matrix triangle:
for col = (row+1):b
% Cross-correlation for upper triangle:
d = round(xcorr(data(row, :), data(col, :)));
[~, I] = max(d(:, F:(2*F)-1));
LAG(row, col) = I-1;
% Cross-correlation for lower triangle:
d = fliplr(d);
[~, I] = max(d(:, F:(2*F)-1));
LAG(col, row) = I-1;
end
end

MATLAB use custom function with pdist

I have a custom function to calculate the weight between two pixels (that represent nodes on a graph) of an image
function [weight] = getWeight(a,b,img, r, L)
ac = num2cell(a);
bc = num2cell(b);
imgint1 = img(sub2ind(size(img),ac{:}));
imgint2 = img(sub2ind(size(img),bc{:}));
weight = (sum((a - b) .^ 2) + (r^2/L) * abs(imgint2 - imgint1)) / (2*r^2);
where a = [x1 y1] and b = [x2 y2] are coordinates that represents pixels of the image, img is a gray-scale image and r and L are constants. Within the function imgint1 and imgint2 are gray intensities of the pixels on a and b.
I need to calculate the weight among set of points of the image.
Instead of two nested loops, I want to use the pdist function because it is WAY FASTER!
For instance, let nodes a set of pixel coordinates
nodes =
1 1
1 2
2 1
2 2
And img = [ 128 254; 0 255], r = 3, L = 255
In order to get these weights, I am using an intermediate function.
function [weight] = fxIntermediate(a,b, img, r, L)
weight = bsxfun(#(a,b) getWeight(a,b,img,r,L), a, b);
In order to finally get the whole set of weights
distNodes = pdist(nodes,#(XI,XJ) fxIntermediate(XI,XJ,img,r,L));
But it always get me an error
Error using pdist (line 373)
Error evaluating distance function '#(XI,XJ)fxIntermediate(XI,XJ,img,r,L)'.
Error in obtenerMatriz (line 27)
distNodes = pdist(nodes,#(XI,XJ) fxIntermediate(XI,XJ,img,r,L));
Caused by:
Error using bsxfun
Invalid output dimensions.
EDIT 1
This is a short example of my code that it should work, but I got the error mentioned above. If you copy/paste the code on MATLAB and run the code you will see the error
function [adjacencyMatrix] = problem
img = [123, 229; 0, 45]; % 2x2 Image as example
nodes = [1 1; 1 2; 2 2]; % I want to calculate distance function getWeight()
% between pixels img(1,1), img(1,2), img(2,2)
r = 3; % r is a constant, doesn't matter its meaning
L = 255; % L is a constant, doesn't matter its meaning
distNodes = pdist(nodes,#(XI,XJ) fxIntermediate(XI,XJ,img,r,L));
adjacencyMatrix = squareform(distNodes );
end
function [weight] = fxIntermediate(a,b, img, r, L)
weight = bsxfun(#(a,b) getWeight(a,b,img,r,L), a, b);
end
function [weight] = getWeight(a,b,img, r, L)
ac = num2cell(a);
bc = num2cell(b);
imgint1 = img(sub2ind(size(img),ac{:}));
imgint2 = img(sub2ind(size(img),bc{:}));
weight = (sum((a - b) .^ 2) + (r^2/L) * abs(imgint2 - imgint1)) / (2*r^2);
end
My goal is to obtain an adjacency matrix that represents the distance between pixels. For the above example, the desired adjacency matrix is:
adjacencyMatrix =
0 0.2634 0.2641
0.2634 0 0.4163
0.2641 0.4163 0
The problem is that you are neither fulfilling the expectations for a function to be used with pdist, nor those for a function to be used with bsxfun.
– From the documentation of pdist:
A distance function must be of form
d2 = distfun(XI,XJ)
taking as arguments a 1-by-n vector XI, corresponding to a single row
of X, and an m2-by-n matrix XJ, corresponding to multiple rows of X.
distfun must accept a matrix XJ with an arbitrary number of rows.
distfun must return an m2-by-1 vector of distances d2, whose kth
element is the distance between XI and XJ(k,:).
However, by using bsxfun in fxIntermediate, this function always returns a matrix of values whose size is the larger of the sizes of the two inputs.
– From the documentation of bsxfun:
A binary element-wise function of the form C
= fun(A,B) accepts arrays A and B of arbitrary but equal size and returns output of the same size. Each element in the output array C is
the result of an operation on the corresponding elements of A and B
only. fun must also support scalar expansion, such that if A or B is a
scalar, C is the result of applying the scalar to every element in the
other input array.
However, your getWeight appears to always return a scalar.
I do not understand your problem well enough in order to repair this. Moreover, I think if speed is what you are after, feeding pdist with a function handle is not the way to go. pdist does not perform magic; it is only fast because its built-in distance functions are implemented efficiently. Also, you are using anonymous function handles and conversions to and from cell arrays, all of which slow the process down. I think you should post a new question where you start with a description of what you are trying to compute, include some code that does the job even if inefficiently, and ask how to improve that.

Generate matrix with for-loop in matlab

Say I have two functions f(x), g(x), and a vector:
xval=1:0.01:2
For each of these individual x values, I want to define a vector of y-values, covering the y-interval bounded by the two functions (or possibly a matrix where columns are x-values, and rows are y-values).
How would I go about creating a loop that would handle this for me? I have absolutely no idea myself, but I'm sure some of you have something right up your sleeve. I've been sweating over this problem for a few hours by now.
Thanks in advance.
Since you wish to generate a matrix, I assume the number of values between f(x) and g(x) should be the same for every xval. Let's call that number of values n_pt. Then, we also know what the dimensions of your result matrix rng will be.
n_pt = 10;
xval = 1 : 0.01 : 2;
rng = zeros(n_pt, length(xval));
Now, into the loop. Once we know what the y-values returned by f(x) and g(x) are, we can use linspace to give us n_pt equally spaced points between them.
for n = 1 : length(xval)
y_f = f(xval(n))
y_g = g(xval(n))
rng(:, n) = linspace(y_f, y_g, n_pt)';
end
This is nice because with linspace you don't need to worry about whether y_f > y_g, y_f == y_g or y_f < y_g. That's all taken care of already.
For demsonstration, I run this example for xval = 1 : 0.1 : 2 and the two sinusoids f = #(x) sin(2 * x) and g = #(x) sin(x) * 2. The points are plotted using plot(xval, rng, '*k');.