Least square distances - matlab

I have two ordered arrays of x(xcor) and y(ycor) values. Joining the first and last points gives a line. I want to compute the perpendicular distances of all points from this line. This is similar to least square distance. Is there a direct way to do this in matlab?
Please also note that sign of the distance should represent the side on the points lie of the line.
xy =
-121.9067 -53.5483
-122.0750 -53.5475
-122.4750 -53.5243
-123.0975 -53.4835
-123.9050 -53.4168
-124.8050 -53.3235
-125.7025 -53.2467
-126.5675 -53.1800
-127.3825 -53.1215
-128.1500 -53.0798
-128.8825 -53.0468
-129.6000 -53.0452
-130.3150 -53.1133
-131.0400 -53.2532
-131.7850 -53.4513
-132.5525 -53.6877
-133.3425 -53.9345
-134.1600 -54.1758
-135.0075 -54.4115
-135.8675 -54.6480
-136.7375 -54.9040
-137.5075 -55.2635
-138.1875 -55.7435
-138.7775 -56.3333
-139.2850 -57.0665
-139.8450 -57.9285
-140.4550 -58.9492
-141.1575 -60.0988
-141.9825 -61.3415
-142.9275 -62.6172
-144.0050 -63.8517
-145.2125 -65.0523
-146.5450 -66.1715
-147.9950 -67.1727
-149.5575 -68.0570
-151.2225 -68.8152
-152.9925 -69.4493
-154.8625 -69.9500
-156.8300 -70.3063
-158.8700 -70.5280
-160.9050 -70.6017
-162.8550 -70.6287
-164.6525 -70.7372
-165.5367 -70.7550
-166.3450 -70.8620

If you have a vector AB, the distance from a point C to that vector can be calculated as follows:
Normalize the vector AB
Calculate the vector AC
Project the vector AC onto AB
Subtract the projection from AC
Calculate the length of the result
In other words, you split AC into a component that is parallel to AB and a component that is perpendicular, and you calculate the length of the latter.
If you have arrays x and y, you can do the following
xy = [x(:),y(:)];
abVector = xy(end,:) - xy(1,:); %# a is the first, b the last point
abVectorNormed = abVector./norm(abVector);
acVector = bsxfun(#minus, xy, xy(1,:));
acParallelLength = sum(bsxfun(#times, acVector , abVectorNormed ),2);
acParallelVector = bsxfun(#times, acParallelLength, abVectorNormed );
perpendicularVector = acVector - acParallelVector;
perpendicularDistance = sqrt(sum(perpendicularVector.^2,2));
EDIT You asked for figures because the code "does not work" in your hands. See below the figures (top: raw data; bottom: perpendicular distance) and the command to plot them; the data looks fairly reasonable in my eyes.
subplot(2,1,1),plot(xy(:,1),xy(:,2),'or')
hold on, plot([xy(1,1),xy(1,1)+abVector(1)],[xy(1,2),xy(1,2)+abVector(2)],'b')
hold on, plot([xy(1,1)+acParallelVector(:,1),xy(:,1)]',[xy(1,2)+acParallelVector(:,2),xy(:,2)]','r')
axis equal %# important to see right angles as such
subplot(2,1,2),stem(xy(:,1),perpendicularDistance,'r')
ylabel('perpendicular distance')

function tot_distance=compute_distance2(x,y)
xA=x(1);xB=x(end);yA=y(1);yB=y(end);
a=(yA-yB);
b=(xB-xA);
c=xA*yB-xB*yA;
d=0;
for p=2:numel(x)-1,
d=d+(a*x(p)+b*y(p)+c)/sqrt(a^2+b^2);
end
tot_distance=abs(d);
end
Easier way.

Related

Plot distances between points matlab

I've made a plot of 10 points
10 10
248,628959661970 66,9462583977501
451,638770451973 939,398361884535
227,712826026548 18,1775336366957
804,449583613070 683,838613746355
986,104241895970 783,736480083219
29,9919502693899 534,137567882728
535,664190667238 885,359450931142
87,0772199008924 899,004898906140
990 990
With the first column as x-coordinates and the other column as y-coordinates
Leading to the following Plot:
Using the following code: scatter(Problem.Points(:,1),Problem.Points(:,2),'.b')
I then also calculated the euclidean distances using Problem.DistanceMatrix = pdist(Problem.Points);
Problem.DistanceMatrix = squareform(Problem.DistanceMatrix);
I replaced the distances by 1*10^6 when they are larger than a certain value.
This lead to the following table:
Then, I would like to plot the lines between the corresponding points, preferably with their distances, but only in case the distance < 1*10^6.
Specifically i want to plot the line [1,2] [1,4] [1,7] [2,4] etc.
My question is, can this be done and how?
Assuming one set of your data is in something called xdata and the other in ydata and then the distances in distances, the following code should accomplish what you want.
hold on
for k = 1:length(xdata)
for j = 1:length(ydata)
if(distances(k,j) < 1e6)
plot([xdata(k) xdata(j)], [ydata(k) ydata(j)]);
end
end
end
You just need to iterate through your matrix and then if the value is less than 1e6, then plot the line between the kth and jth index points. This will however double plot lines, so it will plot from k to j, and also from j to k, but it is quick to code and easy to understand. I got the following plot with this.
This should do the trick:
P = [
10.0000000000000 10.0000000000000;
248.6289596619700 66.9462583977501;
451.6387704519730 939.3983618845350;
227.7128260265480 18.1775336366957;
804.4495836130700 683.8386137463550;
986.1042418959700 783.7364800832190;
29.9919502693899 534.1375678827280;
535.6641906672380 885.3594509311420;
87.0772199008924 899.0048989061400;
990.0000000000000 990.0000000000000
];
P_len = size(P,1);
D = squareform(pdist(P));
D(D > 600) = 1e6;
scatter(P(:,1),P(:,2),'*b');
hold on;
for i = 1:P_len
pi = P(i,:);
for j = 1:P_len
pj = P(j,:);
d = D(i,j);
if ((d > 0) && (d < 1e6))
plot([pi(1) pj(1)],[pi(2) pj(2)],'-r');
end
end
end
hold off;
Final output:
On a side note, the part in which you replaces the distance values trespassing a certain treshold (it looks like it's 600 by looking at your distances matrix) with 1e6 can be avoided by just inserting that threshold into the loop for plotting the lines. I mean... it's not wrong, but I just think it's an unnecessary step.
D = squareform(pdist(P));
% ...
if ((d > 0) && (d < 600))
plot([pi(1) pj(1)],[pi(2) pj(2)],'-r');
end
A friend of mine suggested using gplot
gplot(Problem.AdjM, Problem.Points(:,:), '-o')
With problem.points as the coordinates and Problem.AdjM as the adjacency matrix. The Adjacency matrix was generated like this:
Problem.AdjM=Problem.DistanceMatrix;
Problem.AdjM(Problem.AdjM==1000000)=0;
Problem.AdjM(Problem.AdjM>0)=1;
Since the distances of 1*10^6 was the replacement of a distance that is too large, I put the adjacency there to 0 and all the other to 1.
This lead to the following plot, which was more or less what I wanted:
Since you people have been helping me in such a wonderful way, I just wanted to add this:
I added J. Mel's solution to my code, leading to two exactly the same figures:
Since the figures get the same outcome, both methods should be all right. Furthermore, since Tommasso's and J Mel's outcomes were equal earlier, Tommasso's code must also be correct.
Many thanks to both of you and all other people contributing!

Summing Values based on Area in Matlab

Im trying to write a code in Matlab to calculate an area of influence type question. This is an exert from my data (Weighting, x-coord, y-coord):
M =
15072.00 486.00 -292
13269.00 486.00 -292
12843.00 414.00 -267
10969.00 496.00 -287
9907.00 411.00 -274
9718.00 440.00 -265
9233.00 446.00 -253
9138.00 462.00 -275
8830.00 496.00 -257
8632.00 432.00 -253
R =
-13891.00 452.00 -398
-13471.00 461.00 -356
-12035.00 492.00 -329
-11309.00 413.00 -353
-11079.00 467.00 -375
-10659.00 493.00 -333
-10643.00 495.00 -338
-10121.00 455.00 -346
-9795.00 456.00 -367
-8927.00 485.00 -361
-8765.00 467.00 -351
I want to make a function to calculate the sum of the weightings at any given position based on a circle of influence of 30 for each coordinate.
I have thought of using a for loop to calculate each point independently and summing the result but seems unnecessarily complicated and inefficient.
I also thought of assigning an intensity of color to each circle and overlaying them but I dont know how to change color intensity based on value here is my attempt so far (I would like to have a visual of the result):
function [] = Influence()
M = xlsread('MR.xlsx','A4:C310');
R = xlsread('MR.xlsx','E4:G368');
%these are my values around 300 coordinates
%M are negative values and R positive, I want to see which are dominant in their regions
hold on
scatter(M(:,2),M(:,3),3000,'b','filled')
scatter(R(:,2),R(:,3),3000,'y','filled')
axis([350 650 -450 -200])
hold off
end
%had to use a scalar of 3000 for some reason as it isnt correlated to the graph size
I'd appreciate any ideas/solutions thank you
This is the same but with ca. 2000 data points
How about this:
r_influence = 30; % radius of influence
r = #(p,A) sqrt((p(1)-A(:,2)).^2 + (p(2)-A(:,3)).^2); % distance
wsum = #(p,A) sum(A(find(r(p,A)<=r_influence),1)); % sum where distance less than roi
% compute sum on a grid
xrange = linspace(350,550,201);
yrange = linspace(-200,-450,201);
[XY,YX] = meshgrid(xrange,yrange);
map_M = arrayfun(#(p1,p2) wsum([p1,p2],M),XY,YX);
map_R = arrayfun(#(p1,p2) wsum([p1,p2],R),XY,YX);
figure(1);
clf;
imagesc(xrange,yrange,map_M + map_R);
colorbar;
Gives a picture like this:
Is that what you are looking for?

Interpn - changing output

I have 4 grids:
kgrid which is [77x1]
x which is [15x1]
z which is [9x1]
s which is [2x1]
Then I have a function:
kprime which is [77x15x9x2]
I want to interpolate kprime at some points ksim (750 x 1) and zsim (750 x 1) (xsim is a scalar). I am doing:
[ks, xs, zs, ss] = ndgrid(kgrid, x, z, [1;2]);
Output = interpn(ks, xs, zs, ss, kprime, ksim, xsim, zsim, 1,'linear');
The problem with this interpolation is that the output given is for all combinations of ksim and zsim, meaning that the output is 750x750. I actually need an output of 750x1, meaning that instead of interpolation at all combinations of ksim and zsim I only need to interpolate at ksim(1,1) and zsim(1,1), then ksim(2,1) and zsim(2,1), then ksim(3,1) and zsim(3,1), etc.
In other words, after getting Output I am doing:
Output = diag(squeeze(Output));
I know I can use this output and then just pick the numbers I want, but this is extremely inefficient as it actually interpolates on all other points which I actually do not need. Any help appreciated.
tl;dr: Change xsim and (ssim) from scalars to vectors of the same size as ksim and zsim
Output = interpn (ks, xs, zs, ss, ...
kprime, ...
ksim, ...
repmat(xsim, size(ksim)), ... % <-- here
zsim, ...
repmat(1, size(ksim)), ... % <-- and here
'linear');
Explanation:
The ksim, xsim, zsim, and ssim inputs all need to have the same shape, so that at each common position in that shape, each input acts as an "interpolated subscript" component to the interpolated object. Note that while they all need to have the same shape, this shape can be arbitrary in terms of size and dimensions.
Conversely, if you pass vectors of different sizes (after all, a scalar is a vector of length 1), these get interpreted as the components of an ndgrid construction instead. So you were actually telling interpn to evaluate all interpolations on a grid defined by the vectors ksim, and zsim (and your singletons xsim and ssim). Which is why you got a 2D-grid-looking output.
Note that the same scheme applies with the constructing vectors as well (i.e. ks, xs, zs and ss) i.e. you could have used "vector syntax" instead of "common shape" syntax to define the grid instead, i.e.
Output = interpn(kgrid, x, z, s, kprime, % ...etc etc
and you would have gotten the same result.
From the documents:
Query points, specified as a real scalars, vectors, or arrays.
If Xq1,Xq2,...,Xqn are scalars, then they are the coordinates of a single query point in Rn.
If Xq1,Xq2,...,Xqn are vectors of different orientations, then Xq1,Xq2,...,Xqn are treated as grid vectors in Rn.
If Xq1,Xq2,...,Xqn are vectors of the same size and orientation, then Xq1,Xq2,...,Xqn are treated as scattered points in Rn.
If Xq1,Xq2,...,Xqn are arrays of the same size, then they represent either a full grid of query points (in ndgrid format) or scattered points in Rn.
Answer
You want the usage highlighted in bold. As such, you have to make sure that xsim and ssim ('1' in your code sample) are of size 750x1 also. Then all the query vectors are same length and orientation, such that it can be recognized as a vector of scattered points in Rn. The output will then be a 750x1 vector as needed.
This is to elaborate on #tvo/#Tasos answers, to test the fastest way to create a vector from a scalar:
function create_vector(n)
x = 5;
repm_time = timeit(#()repm(x,n))
repe_time = timeit(#()repe(x,n))
vrep_time = timeit(#()vrep(x,n))
onesv_time = timeit(#()onesv(x,n))
end
function A = repm(x,n)
for k = 1:10000
A = repmat(x,[n 1]);
end
end
function A = repe(x,n)
for k = 1:10000
A = repelem(x,n).';
end
end
function A = vrep(x,n)
v = ones(n,1);
for k = 1:10000
A = x*v;
end
end
function A = onesv(x,n)
for k = 1:10000
A = x*ones(n,1);
end
end
And the results are (for n = 750):
repm_time =
0.049847
repe_time =
0.044188
vrep_time =
0.0041342
onesv_time =
0.0024869
which means that the fastest way to create a vector from a scalar is simply writing x*ones(n,1).

How to interpolate random non monotonic increasing data

So I am working on my Thesis and I need to calculate geometric characteristics of an airfoil.
To do this, I need to interpolate the horizontal and vertical coordinates of an airfoil. This is used for a tool which will calculate the geometric characteristics automatically which come from random airfoil geometry files.
Sometime the Y values of the airfoil are non monotonic. Hence, the interp1 command gives an error since some values in the Y vector are repeated.
Therefore, my question is: How do I recognize and subsequently interpolate non monotonic increasing data automatically in Matlab.
Here is a sample data set:
0.999974 0.002176
0.994846 0.002555
0.984945 0.003283
0.973279 0.004131
0.960914 0.005022
0.948350 0.005919
0.935739 0.006810
0.923111 0.007691
0.910478 0.008564
0.897850 0.009428
0.885229 0.010282
0.872617 0.011125
0.860009 0.011960
0.847406 0.012783
0.834807 0.013598
0.822210 0.014402
0.809614 0.015199
0.797021 0.015985
0.784426 0.016764
0.771830 0.017536
0.759236 0.018297
0.746639 0.019053
0.734038 0.019797
0.721440 0.020531
0.708839 0.021256
0.696240 0.021971
0.683641 0.022674
0.671048 0.023367
0.658455 0.024048
0.645865 0.024721
0.633280 0.025378
0.620699 0.026029
0.608123 0.026670
0.595552 0.027299
0.582988 0.027919
0.570436 0.028523
0.557889 0.029115
0.545349 0.029697
0.532818 0.030265
0.520296 0.030820
0.507781 0.031365
0.495276 0.031894
0.482780 0.032414
0.470292 0.032920
0.457812 0.033415
0.445340 0.033898
0.432874 0.034369
0.420416 0.034829
0.407964 0.035275
0.395519 0.035708
0.383083 0.036126
0.370651 0.036530
0.358228 0.036916
0.345814 0.037284
0.333403 0.037629
0.320995 0.037950
0.308592 0.038244
0.296191 0.038506
0.283793 0.038733
0.271398 0.038920
0.259004 0.039061
0.246612 0.039153
0.234221 0.039188
0.221833 0.039162
0.209446 0.039064
0.197067 0.038889
0.184693 0.038628
0.172330 0.038271
0.159986 0.037809
0.147685 0.037231
0.135454 0.036526
0.123360 0.035684
0.111394 0.034690
0.099596 0.033528
0.088011 0.032181
0.076685 0.030635
0.065663 0.028864
0.055015 0.026849
0.044865 0.024579
0.035426 0.022076
0.027030 0.019427
0.019970 0.016771
0.014377 0.014268
0.010159 0.012029
0.007009 0.010051
0.004650 0.008292
0.002879 0.006696
0.001578 0.005207
0.000698 0.003785
0.000198 0.002434
0.000000 0.001190
0.000000 0.000000
0.000258 -0.001992
0.000832 -0.003348
0.001858 -0.004711
0.003426 -0.005982
0.005568 -0.007173
0.008409 -0.008303
0.012185 -0.009379
0.017243 -0.010404
0.023929 -0.011326
0.032338 -0.012056
0.042155 -0.012532
0.052898 -0.012742
0.064198 -0.012720
0.075846 -0.012533
0.087736 -0.012223
0.099803 -0.011837
0.111997 -0.011398
0.124285 -0.010925
0.136634 -0.010429
0.149040 -0.009918
0.161493 -0.009400
0.173985 -0.008878
0.186517 -0.008359
0.199087 -0.007845
0.211686 -0.007340
0.224315 -0.006846
0.236968 -0.006364
0.249641 -0.005898
0.262329 -0.005451
0.275030 -0.005022
0.287738 -0.004615
0.300450 -0.004231
0.313158 -0.003870
0.325864 -0.003534
0.338565 -0.003224
0.351261 -0.002939
0.363955 -0.002680
0.376646 -0.002447
0.389333 -0.002239
0.402018 -0.002057
0.414702 -0.001899
0.427381 -0.001766
0.440057 -0.001656
0.452730 -0.001566
0.465409 -0.001496
0.478092 -0.001443
0.490780 -0.001407
0.503470 -0.001381
0.516157 -0.001369
0.528844 -0.001364
0.541527 -0.001368
0.554213 -0.001376
0.566894 -0.001386
0.579575 -0.001398
0.592254 -0.001410
0.604934 -0.001424
0.617614 -0.001434
0.630291 -0.001437
0.642967 -0.001443
0.655644 -0.001442
0.668323 -0.001439
0.681003 -0.001437
0.693683 -0.001440
0.706365 -0.001442
0.719048 -0.001444
0.731731 -0.001446
0.744416 -0.001443
0.757102 -0.001445
0.769790 -0.001444
0.782480 -0.001445
0.795173 -0.001446
0.807870 -0.001446
0.820569 -0.001446
0.833273 -0.001446
0.845984 -0.001448
0.858698 -0.001448
0.871422 -0.001451
0.884148 -0.001448
0.896868 -0.001446
0.909585 -0.001443
0.922302 -0.001445
0.935019 -0.001446
0.947730 -0.001446
0.960405 -0.001439
0.972917 -0.001437
0.984788 -0.001441
0.994843 -0.001441
1.000019 -0.001441
First column is X and the second column is Y. Notice how the last values of Y are repeated.
Maybe someone can provide me with a piece of code to do this? Or any suggestions are welcome as well.
Remember I need to automate this process.
Thanks for your time and effort I really appreciate it!
There is quick and dirty method if you do not know the exact function defining the foil profile. Split your data into 2 sets, top and bottom planes, so the 'x' data are monotonic increasing.
First I imported your data table in the variable A, then:
%// just reorganise your input in individual vectors. (this is optional but
%// if you do not do it you'll have to adjust the code below)
x = A(:,1) ;
y = A(:,2) ;
ipos = y > 0 ; %// indices of the top plane
ineg = y <= 0 ; %// indices of the bottom plane
xi = linspace(0,1,500) ; %// new Xi for interpolation
ypos = interp1( x(ipos) , y(ipos) , xi ) ; %// re-interp the top plane
yneg = interp1( x(ineg) , y(ineg) , xi ) ; %// re-interp the bottom plane
y_new = [fliplr(yneg) ypos] ; %// stiches the two half data set together
x_new = [fliplr(xi) xi] ;
%% // display
figure
plot(x,y,'o')
hold on
plot(x_new,y_new,'.r')
axis equal
As said on top, it is quick and dirty. As you can see from the detail figure, you can greatly improve the x resolution this way in the area where the profile is close to the horizontal direction, but you loose a bit of resolution at the noose of the foil where the profile is close to the vertical direction.
If it's acceptable then you're all set. If you really need the resolution at the nose, you could look at interpolating on x as above but do a very fine x grid near the noose (instead of the regular x grid I provided as example).
if your replace the xi definition above by:
xi = [linspace(0,0.01,50) linspace(0.01,1,500)] ;
You get the following near the nose:
adjust that to your needs.
To interpolate any function, there must be a function defined. When you define y=f(x), you cannot have the same x for two different values of y because then we are not talking about a function. In your example data, neither x nor y are monotonic, so anyway you slice it, you'll have two (or more) "y"s for the same "x". If you wish to interpolate, you need to divide this into two separate problems, top/bottom and define proper functions for interp1/2/n to work with, for example, slice it horizontally where x==0. In any case, you would have to provide additional info than just x or y alone, e.g.: x=0.5 and y is on top.
On the other hand, if all you want to do is to insert a few values between each x and y in your array, you can do this using finite differences:
%// transform your original xy into 3d array where x is in first slice and y in second
xy = permute(xy(85:95,:), [3,1,2]); %// 85:95 is near x=0 in your data
%// lets say you want to insert three additional points along each line between every two points on given airfoil
h = [0, 0.25, 0.5, 0.75].'; %// steps along each line - column vector
%// every interpolated h along the way between f(x(n)) and f(x(n+1)) can
%// be defined as: f(x(n) + h) = f(x(n)) + h*( f(x(n+1)) - f(x(n)) )
%// this is first order finite differences approximation in 1D. 2D is very
%// similar only with gradient (this should be common knowledge, look it up)
%// from here it's just fancy matrix play
%// 2D gradient of xy curve
gradxy = diff(xy, 1, 2); %// diff xy, first order, along the 2nd dimension, where x and y now run
h_times_gradxy = bsxfun(#times, h, gradxy); %// gradient times step size
xy_in_3d_array = bsxfun(#plus, xy(:,1:end-1,:), h_times_gradxy); %// addition of "f(x)" and there we have it, the new x and y for every step h
[x,y] = deal(xy_in_3d_array(:,:,1), xy_in_3d_array(:,:,2)); %// extract x and y from 3d matrix
xy_interp = [x(:), y(:)]; %// use Matlab's linear indexing to flatten x and y into columns
%// plot to check results
figure; ax = newplot; hold on;
plot(ax, xy(:,:,1), xy(:,:,2),'o-');
plot(ax, xy_interp(:,1), xy_interp(:,2),'+')
legend('Original','Interpolated',0);
axis tight;
grid;
%// The End
And these are the results, near x=0 for clarity of presentation:
Hope that helps.
Cheers.

matlab - optimize getting the angle between each vector with all others in a large array

I am trying to get the angle between every vector in a large array (1896378x4 -EDIT: this means I need 1.7981e+12 angles... TOO LARGE, but if there's room to optimize the code, let me know anyways). It's too slow - I haven't seen it finish yet. Here's the steps towards optimizing I've taken:
First, logically what I (think I) want (just use Bt=rand(N,4) for testing):
[ro,col]=size(Bt);
angbtwn = zeros(ro-1); %too long to compute!! total non-zero = ro*(ro-1)/2
count=1;
for ii=1:ro-1
for jj=ii+1:ro
angbtwn(count) = atan2(norm(cross(Bt(ii,1:3),Bt(jj,1:3))), dot(Bt(ii,1:3),Bt(jj,1:3))).*180/pi;
count=count+1;
end
end
So, I though I'd try and vectorize it, and get rid of the non-built-in functions:
[ro,col]=size(Bt);
% angbtwn = zeros(ro-1); %TOO LONG!
for ii=1:ro-1
allAxes=Bt(ii:ro,1:3);
repeachAxis = allAxes(ones(ro-ii+1,1),1:3);
c = [repeachAxis(:,2).*allAxes(:,3)-repeachAxis(:,3).*allAxes(:,2)
repeachAxis(:,3).*allAxes(:,1)-repeachAxis(:,1).*allAxes(:,3)
repeachAxis(:,1).*allAxes(:,2)-repeachAxis(:,2).*allAxes(:,1)];
crossedAxis = reshape(c,size(repeachAxis));
normedAxis = sqrt(sum(crossedAxis.^2,2));
dottedAxis = sum(repeachAxis.*allAxes,2);
angbtwn(1:ro-ii+1,ii) = atan2(normedAxis,dottedAxis)*180/pi;
end
angbtwn(1,:)=[]; %angle btwn vec and itself
%only upper left triangle are values...
Still too long, even to pre-allocate... So I try to do sparse, but not implemented right:
[ro,col]=size(Bt);
%spalloc:
angbtwn = sparse([],[],[],ro,ro,ro*(ro-1)/2);%zeros(ro-1); %cell(ro,1)
for ii=1:ro-1
...same
angbtwn(1:ro-ii+1,ii) = atan2(normedAxis,dottedAxis)*180/pi; %WARNED: indexing = >overhead
% WHAT? Can't index sparse?? what's the point of spalloc then?
end
So if my logic can be improved, or if sparse is really the way to go, and I just can't implement it right, let me know where to improve. THANKS for your help.
Are you trying to get the angle between every pair of vectors in Bt? If Bt has 2 million vectors that's a trillion pairs each (apparently) requiring an inner product to get the angle between. I don't know that any kind of optimization is going to help have this operation finish in a reasonable amount of time in MATLAB on a single machine.
In any case, you can turn this problem into a matrix multiplication between matrices of unit vectors:
N=1000;
Bt=rand(N,4); % for testing. A matrix of N (row) vectors of length 4.
[ro,col]=size(Bt);
magnitude = zeros(N,1); % the magnitude of each row vector.
units = zeros(size(Bt)); % the unit vectors
% Compute the unit vectors for the row vectors
for ii=1:ro
magnitude(ii) = norm(Bt(ii,:));
units(ii,:) = Bt(ii,:) / magnitude(ii);
end
angbtwn = acos(units * units') * 360 / (2*pi);
But you'll run out of memory during the matrix multiplication for largish N.
You might want to use pdist with 'cosine' distance to compute the 1-cos(angbtwn).
Another perk for this approach that it does not compute n^2 values but exaxtly .5*(n-1)*n unique values :)