I'm trying to vectorize the following code:
% code before
% code before
% a lot of code before we got to the current comment
%
% houghMatrix holds some values
for i=1:n
for j=1:m
for k = 1:maximalRadius
% get the maximal threshold
if houghMatrix(i,j,k) > getMaximalThreshold(k)
lhs = [j i k];
% verify that the new circle is not listed
isCircleExist = verifyCircleExists(circles,lhs,circleCounter);
% not listed - then we put it in the circles vector
if isCircleExist == 0
circles(circleCounter,:) = [j i k];
fprintf('Circle % d: % d, % d, % d \n', circleCounter, j, i, k);
circleCounter = circleCounter + 1;
end
end
end
end
end
Using tic tac I got the below outputs :
>> x = findCircles(ii);
Circle 1: 38, 38, 35
Circle 2: 89, 51, 34
Circle 3: 72, 66, 11
Circle 4: 33, 75, 30
Circle 5: 90, 81, 31
Circle 6: 54, 96, 26
Elapsed time is 3.111176 seconds.
>> x = findCircles(ii);
Circle 1: 38, 38, 35
Circle 2: 89, 51, 34
Circle 3: 72, 66, 11
Circle 4: 33, 75, 30
Circle 5: 90, 81, 31
Circle 6: 54, 96, 26
Elapsed time is 3.105642 seconds.
>> x = findCircles(ii);
Circle 1: 38, 38, 35
Circle 2: 89, 51, 34
Circle 3: 72, 66, 11
Circle 4: 33, 75, 30
Circle 5: 90, 81, 31
Circle 6: 54, 96, 26
Elapsed time is 3.135818 seconds.
Meaning - average of 3.1 seconds .
I tried to vectorize the code , but the problem is that I need to use
the index i,j,k in the body of the inner for (the 3rd for) .
Any suggestions how to vectorize the code would be greatly appreciated
Thanks
EDIT :
% -- function [circleExists] = verifyCircleExists(circles,lhs,total) --
%
%
function [circleExists] = verifyCircleExists(circles,lhs,total)
MINIMUM_ALLOWED_THRESHOLD = 2;
circleExists = 0;
for index = 1:total-1
rhs = circles(index,:);
absExpr = abs(lhs - rhs);
maxValue = max( absExpr );
if maxValue <= MINIMUM_ALLOWED_THRESHOLD + 1
circleExists = 1;
break
end
end
end
Heres what I think you want to do: For each valid coordinate triplet, you want to check whether there has been a nearby triplet already, otherwise, you add it to the list. This operation can be fully vectorized if there's no possibility of "chaining", i.e. if each cluster of possible candidate voxels can only accomodate one center. In this case, you simply use:
%# create a vector of thresholds
maximalThreshold = getMaximalThreshold(1:maximalRadius);
%# make it 1-by-1-by-3
maximalThreshold = reshape(maximalThreshold,1,1,[]);
%# create a binary array the size of houghMatrix with 1's
%# wherever we have a candidate circle center
validClusters = bsxfun(#gt, houghMatrix, maximalThreshold);
%# get the centroids of all valid clusters
stats = regionprops(validClusters,'Centroid');
%# collect centroids, round to get integer pixel values
circles = round(cat(1,stats.Centroid));
Alteratively, if you want to follow your scheme of selecting valid circles, you can get the ijk indices from validClusters as follows:
[potentialCircles(:,1),potentialCircles(:,2), potentialCircles(:,3)]= ...
sub2ind(size(houghMatrix),find(validClusters));
nPotentialCircles = size(potentialCircles,1);
for iTest = 2:nPotentialCircles
absDiff = abs(bsxfun(#minus,potentialCircles(1:iTest-1,:),potentialCircles(iTest,:)));
if any(absDiff(:) <= MINIMUM_ALLOWED_THRESHOLD + 1)
%# mask the potential circle
potentialCircles(iTest,:) = NaN;
end
end
circles = potentialCircles(isfinite(potentialCircles(:,1)),:);
Related
Given a recursive loop similar to the following:
A = [5,2;0,2]
B = [5;6]
x = [0;7]
for i = 1:10
x(:,i+1) = A * x(:,i) + B
end
How can this represented without a loop?
Sample output:
[ 0, 19, 140, 797, 4186, 21339, 107520, 539257, 2699606, 13504679, 67536700;
7, 20, 46, 98, 202, 410, 826, 1658, 3322, 6650, 13360]
Here is a more mathy approach by solving the general formula for your recursion
u = pinv(A-eye(2))*B;
C = arrayfun(#(n) A^n*(x+u)-u,0:10,'UniformOutput',false);
M = cat(2,C{:});
which gives
M =
Columns 1 through 9:
0 19 140 797 4186 21339 107520 539257 2699606
7 20 46 98 202 410 826 1658 3322
Columns 10 and 11:
13504679 67536700
6650 13306
I think you are looking to create a recursive function. If so, the below might work for you.
A = [5,2;0,2]
B = [5;6]
x = [0;7]
x = myRecursive(A,B,x, 10)
function [x] = myRecursive(A,B,x,n)
x(:,end+1) = A * x(:,end) + B;
if size(x,2) <= n
x = myRecursive(A,B,x,n);
end
end
I have an unordered set of 2D points which represents the corners of a building. I need to connect them to get the outline of the building.
The points were obtained by combining different polygons collected by different individuals. My idea is to use these polygons to get the points in order (e.g. taking the region between the biggest and smallest polygons and connect the points such that it comes in this region).
I tried using the minimum distance criteria and also to connect the points based on angles. But unfortunately it doesn't work. One useful thing which I have is the raw data of many polygons in which the point order is correct. So is there any possibility to compare with those polygons to connect these points? As I mentioned above, my professor gave the idea to take the biggest and the smallest polygons and use the area in between as a buffer. All the points will fall in this buffer area. But I am not sure how to implement this.
X = [364.533 372.267 397.067 408.133 382.471 379.533 329.250 257.200 199.412 195.267 184.385 168.643 157.533 174.500 108.533 99.333 150.733 184.800 138.105 179.474 218.278 232.133 267.714 306.929 312.143 357.733 421.333 431.000 371.867 364.533];
Y = [192.027 233.360 228.627 286.693 314.541 292.960 327.450 340.500 348.671 326.693 269.308 330.857 274.493 226.786 239.200 193.467 182.760 101.893 111.000 80.442 74.356 140.360 64.643 56.857 77.786 69.493 133.293 180.427 142.160 192.027];
The expected result is a closed polygon which represents the plan of the building. I have 15 building samples and the code needs to work for all. Some buildings don't preserve the right angle criteria between the corners. I am attaching the data which i had. The points i have is obtained by integrating the polygons. So is there any way to use this polygons(in which the points are in order)actual data before integration
EDIT
So, I could find a solution using my below-mentioned idea.
Remarks: I added one missing point manually. And, I removed the two tiny corners at the bottom. Either, these must be four corners in total, or they can be treated as no corners at all.
I explicitly state that, because my idea incorporates the assumption, that corners typically have a 90 degree angle.
General approach
Find order of points by below-mentioned method.
For all points, determine potential "neighbours" within a limit with respect to the found order.
For each two neighbours, determine the angle between neighbour #1 - current point - neighbour #2. Ideally, this angle should be 90 degree.
For all candidate combinations, find the one with the minimal total distance, i.e. distance(neighbour #1 - current point) + distance(current point - neighbour #2).
I realized that by using a for loop over all points, resulting in drawing all lines two times. Also, a lot of the calculations might by vectorized and moved from the loop. Optimization wasn't my intention right now. ;-)
% Point data of building corners; modified!
X = [285.400 372.267 397.067 408.133 382.471 379.533 199.412 195.267 184.385 168.643 157.533 174.500 108.533 99.333 150.733 184.800 138.105 179.474 218.278 232.133 267.714 306.929 312.143 357.733 421.333 431.000 371.867 364.533];
Y = [130.150 233.360 228.627 286.693 314.541 292.960 348.671 326.693 269.308 330.857 274.493 226.786 239.200 193.467 182.760 101.893 111.000 80.442 74.356 140.360 64.643 56.857 77.786 69.493 133.293 180.427 142.160 192.027];
% Place approximative center of building at (0, 0)
X = X - mean(X);
Y = Y - mean(Y);
C = [mean(X), mean(Y)];
% Sort points by angle with respect to center
[~, idx] = sort(atan2(X, Y));
% Rearrange points with respect to sorted angles
X = X(idx);
Y = Y(idx);
% Number of data points
n = numel(X);
% Calculate direction vectors for X and Y coordinates
dvX = repmat(X.', 1, n);
dvX = dvX - dvX.';
dvY = repmat(Y.', 1, n);
dvY = dvY - dvY.';
% Calculate distances
dst = sqrt(dvX.^2 + dvY.^2);
% Number of "neighbouring" points to be considered with respect to the order
nn = 8;
figure(1);
hold on;
% Center
plot(C(1), C(2), 'kx', 'MarkerSize', 15);
% Plain points
plot(X, Y, '.', 'MarkerSize', 15);
for k = 1:n
% Index
text(X(k) + 0.05, Y(k) + 0.05, num2str(k), 'FontSize', 12);
% Set up neighbourhood
nbh = mod([k-nn/2:k-1 k+1:k+nn/2], n);
nbh(nbh == 0) = n;
% Calculate angles and total distance arrays
ang = Inf(nn);
len = Inf(nn);
for ii = 1:nn
l = nbh(ii);
d1 = [dvX(k, l) dvY(k, l)];
for jj = ii+1:nn
m = nbh(jj);
d2 = [dvX(k, m) dvY(k, m)];
len(ii, jj) = dst(k, l) + dst(k, m);
ang(ii, jj) = abs(pi/2 - acos(dot(d1, d2) / (norm(d1) * norm(d2))));
end
end
% Find candidates with angle difference < 10 degree
cand = find(ang < pi/18);
% For these candidates, find the one with the shortest total distance
[~, I] = min(len(cand));
% Get corresponding indices
[I, J] = ind2sub([nn nn], cand(I));
cand = nbh([I J]);
% Lines
plot([X(k) X(cand(1))], [Y(k) Y(cand(1))], 'b', 'LineWidth', 1);
plot([X(k) X(cand(2))], [Y(k) Y(cand(2))], 'b', 'LineWidth', 1);
end
hold off;
Output image:
An approximative(!) solution is to determine the center of the contour described by the found points, and use atan2 with respect to the center to order the points by angle. See the following code snippet for visualization:
% Points
X = 2 * rand(1, 15) - 1;
Y = 2 * rand(1, 15) - 1;
% Center
C = [0, 0];
% Determine indices
[~, idx] = sort(atan2(X, Y));
figure(1);
hold on;
% Center
plot(C(1), C(2), 'kx', 'MarkerSize', 15);
% Plain points
plot(X, Y, '.', 'MarkerSize', 15);
% Indices and lines
for k = 1:numel(X)
text(X(idx(k)) + 0.05, Y(idx(k)) + 0.05, num2str(k), 'FontSize', 12);
if (k == numel(X))
plot([X(idx(k)) X(idx(1))], [Y(idx(k)) Y(idx(1))], 'b');
else
plot([X(idx(k)) X(idx(k+1))], [Y(idx(k)) Y(idx(k+1))], 'b');
end
end
hold off;
Gives the following output:
Although I'm sure, that a certain amount of the concavities will be correctly handled, I'm afraid, that it'll fail for the given example (especially the upper part). This is, because the image is not a perfect top view, thus angles are kinda "distorted".
Nevertheless, maybe the ordering can boost your minimum distance approach.
Here's a solution which that good for shapes that have outlines made from perpendicular* lines (as the one in your example). The idea is as follows:
We rotate the points to align* them to the XY grid.
We group points into families that have either the same* X or Y coordinates.
For each point we compute two points: the closest horizontally, and the closest vertically, from within the allowed families.
Build a connectivity matrix and transform back.
Just like in HansHirse's answer, I must change the dataset: add a missing corner (pt. 30), remove two non-corners (pts. 7-8), remove the duplicate last point.
* - approximately.
function A = q55511236
%% Initialization:
% Define points:
X = [364.533 372.267 397.067 408.133 382.471 379.533 329.250 257.200 199.412 195.267 184.385 ...
168.643 157.533 174.500 108.533 99.333 150.733 184.800 138.105 179.474 218.278 232.133 ...
267.714 306.929 312.143 357.733 421.333 431.000 371.867];
Y = [192.027 233.360 228.627 286.693 314.541 292.960 327.450 340.500 348.671 326.693 269.308 ...
330.857 274.493 226.786 239.200 193.467 182.760 101.893 111.000 80.442 74.356 140.360 ...
64.643 56.857 77.786 69.493 133.293 180.427 142.160];
%% Preprocessing:
% Centering:
XY = [X;Y] - [mean(X); mean(Y)];
% Rotation:
[U,~,~] = svd(XY,'econ');
rXY = (U.' * XY).';
% Fixing problems w/ some points:
rXY = vertcat(rXY, [-21.8, 66]); % add missing point
rXY(7:8, :) = NaN; % remove non-corners
% figure(); scatter(rXY(:,1),rXY(:,2));
%% Processing:
% Group points according to same-X and same-Y
CLOSE_ENOUGH_DISTANCE = 10; % found using trial and error
[~,~,sameXpts] = uniquetol(rXY(:,1), CLOSE_ENOUGH_DISTANCE, 'DataScale', 1);
[~,~,sameYpts] = uniquetol(rXY(:,2), CLOSE_ENOUGH_DISTANCE, 'DataScale', 1);
% Create masks for distance evaluations:
nP = size(rXY,1);
[maskX,maskY] = deal(zeros(nP));
maskX(sameXpts == sameXpts.') = Inf;
maskY(sameYpts == sameYpts.') = Inf;
% Compute X and Y distances separately (we can do this in the rotated space)
dX = abs(rXY(:,1) - rXY(:,1).') + maskX + 1./maskY;
dY = abs(rXY(:,2) - rXY(:,2).') + maskY + 1./maskX;
[~,nX] = min(dX);
[~,nY] = min(dY);
% Construct connectivity matrix:
A = false(nP);
idxTrue = sub2ind(size(A), repmat(1:nP, [1,2]), [nX(:).', nY(:).']);
A(idxTrue) = true;
%% Plot result:
% Rotated coordinates:
figure(); gplot(A, rXY, '-o'); text(rXY(:,1), rXY(:,2), string(1:nP));
uXY = (U*rXY.').';
% Original coordinates:
figure(); gplot(A, uXY, '-o'); text(uXY(:,1), uXY(:,2), string(1:nP)); axis ij;
Resulting in:
The concept used for the answer is the 'Travelling salesman problem'. A buffer is created around the points and this buffer is included as an extra criterion.
a=[141 188 178 217 229 282 267 307 313 357 372 422 434 365 372 398 411 382 382 233 229 191 185 166 156 183 173 114 97 149 139 139];
b=[109 103 79 76 140 132 64 56 78 72 141 133 180 192 234 228 287 293 315 348 343 348 329 332 270 268 225 240 194 184 108 108];
X=[364.5333 232.1333 397.0667 157.5333 431 421.3333 306.9286 184.3846 357.7333 199.4118 168.6429 179.4737 408.1333 382.4706 150.7333 372.2667 184.8 138.1053 312.1429 108.5333 174.5 195.2667 257.2 99.33333 379.5333 371.8667 329.25 280.7059 267.7143 218.2778];
Y=[192.0267 140.36 228.6267 274.4933 180.4267 133.2933 56.85714 269.3077 69.49333 348.6706 330.8571 80.44211 286.6933 314.5412 182.76 233.36 101.8933 111 77.78571 239.2 226.7857 326.6933 340.5 193.4667 292.96 142.16 327.45 130.5529 64.64286 74.35556];
R = [a' b'];
d = 12;
polyout = polybuffer(R,'lines',d)
figure
%imshow(I2);
hold on
%plot(R(:,1),R(:,2),'r.','MarkerSize',10)
plot(X,Y,'r.', 'MarkerSize', 15)
plot(polyout)
axis equal
hold off
[s,t] = boundary(polyout); %%this is the boundary polygon of the buffer
numPoints = length(clustersCentroids);
x = X; %these are the points to be connected
y = Y;
x([1 2],:)=x([2 1],:);
y([1 2],:)=y([2 1],:);
figure
plot(x, y, 'bo', 'LineWidth', 2, 'MarkerSize', 17);
grid on;
imshow(I2);
xlabel('X', 'FontSize', 10);
ylabel('Y', 'FontSize', 10);
% Make a list of which points have been visited
beenVisited = false(1, numPoints);
% Make an array to store the order in which we visit the points.
visitationOrder = ones(1, numPoints);
% Define a filasafe
maxIterations = numPoints + 1;
iterationCount = 1;
% Define a current index. currentIndex will be 1 to start and then will vary.
currentIndex = 1;
while sum(beenVisited) < numPoints
visitationOrder(iterationCount) = currentIndex;
beenVisited(currentIndex) = true;
% Get the x and y of the current point.
thisX = x(currentIndex);
thisY = y(currentIndex);
%text(thisX + 0.01, thisY, num2str(currentIndex), 'FontSize', 35, 'Color', 'r');
% Compute distances to all other points
distances = sqrt((thisX - x) .^ 2 + (thisY - y) .^ 2);
distances(beenVisited)=inf;
distances(currentIndex) = inf;
% Don't consider visited points by setting their distance to infinity.
[out,idx] = sort(distances);
xx=[x(currentIndex) x(idx(1))]
yy=[y(currentIndex) y(idx(1))]
if isempty(polyxpoly(xx,yy,s,t))
iterationCount = iterationCount + 1;
currentIndex =idx(1);
else
xx=[x(currentIndex) x(idx(2))]
yy=[y(currentIndex) y(idx(2))]
if isempty(polyxpoly(xx,yy,s,t))
iterationCount = iterationCount + 1;
currentIndex =idx(2);
else
xx=[x(currentIndex) x(idx(3))]
yy=[y(currentIndex) y(idx(3))]
if isempty(polyxpoly(xx,yy,s,t))
iterationCount = iterationCount + 1;
currentIndex =idx(3);
else
xx=[x(currentIndex) x(idx(4))]
yy=[y(currentIndex) y(idx(4))]
if isempty(polyxpoly(xx,yy,s,t))
iterationCount = iterationCount + 1;
currentIndex =idx(4);
end
end
end
end
end
% Plot lines in that order.
hold on;
orderedX = [x(visitationOrder); x(1)];
orderedY = [y(visitationOrder) ;y(1)];
plot(orderedX,orderedY, 'm-', 'LineWidth', 2);
title('Result', 'FontSize', 10);
I want to loop through different elements of 3 arrays and create a matrix as a function of their values.
My a vector ranges from 1 to 5, my b vector ranges from 1 to 5 and my x vector ranges from 2 to 10 as shown below. Then for particular values from a and b, using the equation y=a*x+b, I want the resulting y vector corresponding to the x values stored in the 1st column vector of the y matrix.
After that, changing a and b one by one, I want the results of different y to be stored in corresponding columns of the y matrix . How can I proceed to achieve that?
Here is the code I tried:
function mathstrial
a = [1:1:5];
b = [1:1:5];
x = [2:2:10];
for e1 = a
for e2 = b
for e3 = x
y = e1*x+e2;
end
end
end
disp(y)
end
I want the result to be
y =
3 4 5 6 7 ..
5 6 7 8 9 ..
7 8 9 10 11 ..
9 10 11 12 13 ..
11 12 13 14 15 ..
...
You can do this without any loops - the more "MATLAB-esque" way of doing things.
% Your a and b, to get combinations as a 5x5 grid we use meshgrid
[a,b] = meshgrid(1:5, 1:5);
% We want to make a 5x5x5 3D matrix, where the 2D layers each use a different value
% for x, and the gridded a and b we just generated. Get the layered x:
x = repmat(reshape(2:2:10, 1, 1, []), 5, 5, 1);
% Now we want the corresponding layered a and b
a = repmat(a, 1, 1, 5); b = repmat(b, 1, 1, 5);
% Now calculate the result, ensuring we use element-wise multiplication .*
y = a.*x + b;
% Reshape to be a 2D array, collapsing the 3rd dimension
y = reshape(y(:,:).', [], 5, 1);
Result as you wanted:
y =
[3, 4, 5, 6, 7
5, 6, 7, 8, 9
7, 8, 9, 10, 11
9, 10, 11, 12, 13
...
41, 42, 43, 44, 45
51, 52, 53, 54, 55]
You could easily make this more generic by using size in place of the 5s to get the appropriate sizes.
you can build up y in a single for loop
a = [1:1:5];
b = [1:1:5];
x = [2:2:10];
y = zeros(5,5,5);
for ct = 1:length(a)
y(:,:,ct) = (a(ct).*x)'+b;
end
with b over the second and a over the third dimension.
Or even in a single unreadable line
y=repmat((a'.*x),[1,1,length(b)])+repmat(permute(b,[1,3,2]),[length(x),length(a),1])
with a over the second, and b over the third dimension
a = [1:1:5];
b = [1:1:5];
x = [2:2:10];
y = zeros(5,5,5);
for i = 1:5
for j = 1:5
for k =1:5
y(i,j,k) = i*x(k)+j
end
end
end
final_y = reshape(y, [5, 25])
I created the following three dimensional mockup matrix:
mockup(:,:,1) = ...
[100, 100, 100; ...
103, 95, 100; ...
101, 85, 100; ...
96, 90, 102; ...
91, 89, 99; ...
97, 91, 97; ...
105, 83, 100];
mockup(:,:,2) = ...
[50, NaN, NaN; ...
47, NaN, 40; ...
45, 60, 45; ...
47, 65, 45; ...
51, 70, 45; ...
54, 65, 50; ...
62, 80, 55];
I also defined percentTickerAvailable = 0.5.
As a result, The columns represent equity prices from three different assets. For futher processing I need to manipulate the NaN values in the following way.
If the percentage of NaNs in any given ROW is greater than 1 - percentTickerAvailable, replace all values in these particular rows with NaNs. That is, if not enough assets have prices in that particular row, ignore the row completely.
If the percentage of NaNs in any given ROW is less or equal to 1 - percentTickerAvailable, replace the respective NaNs with -inf.
To be clear, "percentage of NaNs in any given ROW" is calculated as follows:
Number of NaNs in any given ROW divided by number of columns.
The adjusted mockup matrix should look like this:
mockupAdj(:,:,1) = ...
[100, 100, 100; ...
103, 95, 100; ...
101, 85, 100; ...
96, 90, 102; ...
91, 89, 99; ...
97, 91, 97; ...
105, 83, 100];
mockupAdj(:,:,2) = ...
[NaN, NaN, NaN; ...
47, -inf, 40; ...
45, 60, 45; ...
47, 65, 45; ...
51, 70, 45; ...
54, 65, 50; ...
62, 80, 55];
So far, I did the following:
function vout = ranking(vin, percentTickerAvailable)
percentNonNaN = 1 - sum(isnan(vin), 2) / size(vin, 2);
NaNIdx = percentNonNaN < percentTickerAvailable;
infIdx = percentNonNaN > percentTickerAvailable & ...
percentNonNaN < 1;
[~, ~, numDimVin] = size(vin);
for i = 1 : numDimVin
vin(NaNIdx(:,:,i) == 1, :, i) = NaN;
end
about = vin;
end % EoF
By calling mockupAdj = ranking(mockup, 0.5) this already transforms the first row in mockup(1,:,2)correctly to {'NaN', 'NaN', 'NaN'}. However, I am struggling with the second point. With infIdx I already successfully identified the rows that corresponds to the second condition. But I don't know how to correctly use that information in order to replace the single NaN in mockup(2,2,2) with -inf.
Any hint is highly appreciated.
This is a good example of something that can be solved using vectorization. I am providing two versions of the code, one that uses the modern syntax (including implicit expansion) and one for older version of MATLAB.
Several things to note:
In the NaN substitution stage, I'm using a "trick" where 0/0 is evaluated to NaN.
In the Inf substitution stage, I'm using logical masking/indexing to access the correct elements in vin.
R2016b and newer:
function vin = ranking (vin, percentTickerAvailable)
% Find percentage of NaNs on each line:
pNaN = mean(isnan(vin), 2, 'double');
% Fills rows with NaNs:
vin = vin + 0 ./ (1 - ( pNaN >= percentTickerAvailable));
% Replace the rest with -Inf
vin(isnan(vin) & pNaN < percentTickerAvailable) = -Inf;
end
Prior to R2016b:
function vin = rankingOld (vin, percentTickerAvailable)
% Find percentage of NaNs on each line:
pNaN = mean(isnan(vin), 2, 'double');
% Fills rows with NaNs:
vin = bsxfun(#plus, vin, 0 ./ (1 - ( pNaN >= percentTickerAvailable)));
% Replace the rest with -Inf
vin(bsxfun(#and, isnan(vin), pNaN < percentTickerAvailable)) = -Inf;
end
1)
The percentage of NaN in any given row should be smaller than 1
... Are you talking about ratio? In which case this is a useless check, as it will always be the case. Or talking about percentages? In which case your code doesn't do what you describe. My guess is ratio.
2) Based on my guess, I have a follow up question: following your description, shouldn't mockup(2,2,2) stay NaN? There is 33% (<50%) of NaN in that row, so it does not fulfill your condition 2.
3) Based on the answers I deemed logical, I would have changed percentNaN = sum(isnan(vin), 2) / size(vin, 2); for readability, and NaNIdx = percentNaN > percentTickerAvailable; accordingly. Now just add one line in front of your loop:
vin(isnan(vin)) = -inf;
Why? Because like this you replace all the NaNs by -inf. Later on, the ones that respect condition 1 will be overwritten to NaN again, by the loop. You don't need the InfIdx.
4) Be aware that your function cannot return vout as of now. Just let it return vin, and you'll be fine.
You can also use logical indexing to achieve this task:
x(:,:,1) = ...
[100, 100, 100; ...
103, 95, 100; ...
101, 85, 100; ...
96, 90, 102; ...
91, 89, 99; ...
97, 91, 97; ...
105, 83, 100];
x(:,:,2) = ...
[50, NaN, NaN; ...
47, NaN, 40; ...
45, 60, 45; ...
47, 65, 45; ...
51, 70, 45; ...
54, 65, 50; ...
62, 80, 55];
% We fix the threshold
tres = 0.5; %fix the threshold.
% We check if a value = NaN or not.
in = isnan(x);
% Which line have more than 50% of NaN ?.
ind = (sum(in,2)./(size(x,2)))>0.5
% We generate an index
[x1,~,x3] = ind2sub(size(ind),ind);
% We set the NaN index to 0 if the line contains less than 50 % of NaN.
in(x1,:,x3) = 0;
% We calculate the new values.
x(in) = -inf;
x(x1,:,x3) = NaN;
So my problem is, I'd like to do this without the for loop. Geting the prod() of multiple vectors but of different lengths.
I am dealing with rays intersecting voxels. I typically have 1e6 rays and 1e5 voxels, but this can vary.
intxRays is a list of rays that have intersected voxels.
gainList is a one dimensional vector, each element has a value that corresponds to a specific ray voxel intersection calculated previously (actually with the help of you lovely lot here).
rayIntxStart and rayIntxEnd are vectors of indices for, where in the gainlist array, each ray's corresponding values start and end (they're all in order).
Here is the code and some examples and expected outputs.
gainSum = zeros(1, 5);
% only interested in the intx uniques
intxSegCtr = 1;
% loop through all of the unique segments
for rayCtr = 1:max(intxRays)
if rayCtr == intxRays(intxSegCtr)
startInd = rayIntxStart(intxSegCtr);
endInd = rayIntxEnd(intxSegCtr);
% find which rows correspoond to those segements
gainVals = gainList(startInd:endInd);
gainProd = prod(gainVals);
% get the product of the gains for those voxels
gainSumIdx = intxRays(intxSegCtr);
gainSum(gainSumIdx) = gainProd;
% increment counter
intxSegCtr = intxSegCtr + 1;
end
end
Example data for five rays and nine voxels. Assume the voxel gain array looked like this (for simplicity) for nine voxels (used in previous step).
voxelGains = 10:10:90;
Now say rays 1 and 3 don't hit anything, ray 2 hits voxels 1 and 2, ray 4 hits voxels 2:7
and ray 5 hits voxels 6:9
intxRays = [2, 4, 5];
gainList = [10, 20, 20, 30, 40, 50, 60, 70, 60 70, 80, 90];
rayIntxStart = [1, 3, 9];
rayIntxEnd = [2, 8, 12];
For these numbers the above code would give as a result:
gainSum = [0, 200, 0, 5.0400e+09, 3.024e+07];
I hope this all makes sense.
When I developed it I was using far smaller ray and voxel numbers and it worked fine. As I'm moving up though, the major bottleneck in my code is this loop. Actually just the gainVals and gainProd assignment is like 80% and 15% of my runtime on their own.
This is the only method I can find that works, padding and the like won't work due to the sizes involved.
Is there a way to get the value I want, without this loop?
Many thanks!
ok this is a very small performance boost, but it might help. for testing the matrix way without the loop a bigger data sample is needed.
These are 3 soultions, your original, an optimized and the optimized way as a oneliner. could you please try if this is already doing something for you?
clear all
% orignial loop through all Rays
intxRays = [2, 4, 5];
gainList = [10, 20, 20, 30, 40, 50, 60, 70, 60 70, 80, 90];
rayIntxStart = [1, 3, 9];
rayIntxEnd = [2, 8, 12];
gainSum = zeros(1, 5);
tic
% only interested in the intx uniques
intxSegCtr = 1;
% loop through all of the unique segments
for rayCtr = 1:max(intxRays)
if rayCtr == intxRays(intxSegCtr)
startInd = rayIntxStart(intxSegCtr);
endInd = rayIntxEnd(intxSegCtr);
% find which rows correspoond to those segements
gainVals = gainList(startInd:endInd);
gainProd = prod(gainVals);
% get the product of the gains for those voxels
gainSumIdx = intxRays(intxSegCtr);
gainSum(gainSumIdx) = gainProd;
% increment counter
intxSegCtr = intxSegCtr + 1;
end
end
toc
clear all
%loop insted of every single one to max just through the intxRays
intxRays = [2, 4, 5];
gainList = [10, 20, 20, 30, 40, 50, 60, 70, 60 70, 80, 90];
rayIntxStart = [1, 3, 9];
rayIntxEnd = [2, 8, 12];
gainSum = zeros(1, 5);
tic
for rayCtr=1:length(intxRays)
%no if as you just go through them
%intxRays(rayCtr) is the corresponding element
startInd = rayIntxStart(rayCtr);
endInd = rayIntxEnd(rayCtr);
% find which rows correspoond to those segements
gainVals = gainList(startInd:endInd);
gainProd = prod(gainVals);
% get the product of the gains for those voxels and set them to the ray
gainSum(intxRays(rayCtr)) = gainProd;
end
%disp(gainSum);
toc
clear all
%same as above, but down to 1 line so no additional values are generated
intxRays = [2, 4, 5];
gainList = [10, 20, 20, 30, 40, 50, 60, 70, 60 70, 80, 90];
rayIntxStart = [1, 3, 9];
rayIntxEnd = [2, 8, 12];
gainSum = zeros(1, 5);
tic
for rayCtr=1:length(intxRays)
gainSum(intxRays(rayCtr))=prod(gainList(rayIntxStart(rayCtr):rayIntxEnd(rayCtr)));
end
toc