Create 3D matrix in matlab - arrays

I want to plot the temporal evolution of the factor of safety (FS, a quantification for the risk of landslides in a certain area).
This is calculated as follows:
effcohesion=0;
rootcohesion=0;
gammat=12.9E3;
gammaw=9810;
c=0;
deltac=0;
m=0.5;
z=2.5;
phi=16;
slope=rand(20,20)*30 % slope of a gridpoint in area
Strength = c + deltac + (gammat - gammaw.*m).*z.*(cosd(slope).^2);
Stress = gammat.*z.*(sind(slope)).*(cosd(slope));
Part = tand(phi);
FS2 = (Strength./Stress).*(Part)
Now. The value of m (= the height of the water table, which determines the FS) varies throughout the year and is thus not constant. I have a file with precipitation, evaporation, etc. data but to make it not too complicated, I here assume that m is just a function of the day of the year:
mnew=zeros(365,1);
for t=1:365
mnew(t)=(m+t)/150;
end
I now have a dataset with FS for 20x20 points where m =0.5 (=FS2) and a file with the evolution of m during the year (= mnew).
How can I now create a 3D matrix where (1) the spatial variation of FS is stored (so the values of FS over the 20x20 matrix) and (2) the temporal evolution of FS in function of m throughout the year. Eventually, I want a matrix that has both the spatial and temporal evolution of FS in it.
Layer 1 = FS at all 20x20 points on day 1
Layer 2 = FS at all 20x20 points on day 2
etc.
Can someone help me?
Thanks in advance!

A "3D matrix" would more properly be called a rank 3 array. To do this, just paste your FS2 calculation inside the time loop. Instead of m, use the appropriate mnew to calculate FS2. Then set that layer of FS3 (the rank 3 array) to FS2.
Then, layer 1 (day 1) is given by FS3(:,:,1), layer 2 by FS3(:,:,2), etc.
m0=0.5;
% Sizes of array
n1 = 20;
n2 = 20;
n3 = 365;
FS3 = zeros(n1, n2, n3);
mnew=zeros(n3,1);
for t=1:n3
mnew(t)=(m0+t)/150;
effcohesion=0;
rootcohesion=0;
gammat=12.9E3;
gammaw=9810;
c=0;
deltac=0;
m = mnew(t);
z=2.5;
phi=16;
slope=rand(n1,n2)*30; % slope of a gridpoint in area
Strength = c + deltac + (gammat - gammaw.*m).*z.*(cosd(slope).^2);
Stress = gammat.*z.*(sind(slope)).*(cosd(slope));
Part = tand(phi);
FS2 = (Strength./Stress).*(Part);
FS3(:,:,t) = FS2;
end

Related

Random sampling of elements from an array based on a target condition

I have an array (let's call it ElmInfo) of size Nx2 representing a geometry. In that array the element number and element volume are on the column 1 and column 2 respectively. The volume of elements largely vary. The sum of the volume of all elements leads to a value V which can be obtained in MATLAB as:
V=sum(ElmInfo(:,2));
I want to randomly sample elements from the array ElmInfo in such a way that the volume of sampled elements (with no repetition) will lead to a target volume V1. Note: V1 is less than V. So I don't know the number of elements to be sampled. I am giving an example. For a sampling case number of sampled element can be '10' whereas in other sampling number of sampled element can be '15'.
There is no straightforward MATLAB in-built function to meet the target condition. How can I implement the code in MATLAB?
Finally I got the answer of my question. Here is the solution I got from a contributor at MATLAB central. For the convenience of the stack overflow community I am posting the answer here.
TotVol=sum(ElmInfo(:,2));
DefVf = 1.5; % This is the volume fraction I want to sample
% Target sample volume
DefVolm_target = TotVol*(DefVf/100);
% **************************************
n = 300;
v = ElmInfo(:,2);
tol = 1e-6;
sample = [];
maxits = 10000;
for count = 1:maxits
p = randperm(n);
s = cumsum(v(p));
k = find(abs(s - DefVolm_target) < tol);
if ~isempty(k)
sample_indices = p(1:k(1));
sample = v(sample_indices);
fprintf('Sample found after %d iterations\n', count);
break
end
end
DefVol_sim=sum(sample);
sampled_Elm=sort(sample_indices);

How to solve logistic regression using gradient Descent?

I was solving a exercise of a online course form coursera on machine learning. The problem statement is :
Suppose that a high school has a dataset representing 40 students who were admitted to college and 40 students who were not admitted. Each ( x(i), y(i) ) training example contains a student's score on two standardized exams and a label of whether the student was admitted.
Our task is to build a binary classification model that estimates college admission chances based on a student's scores on two exams. In the training data,
a. The first column of your x array represents all Test 1 scores, and the second column represents all Test 2 scores.
b. The y vector uses '1' to label a student who was admitted and '0' to label a student who was not admitted.
I have solved it by using predefined function named fminunc. Now , i am solving it by using gradient descent but my graph of cost vs number of iteration is not conversing i.e cost function value is not decreasing with number of iteration . My theta value is also not matching with the answer that should i get.
theta value that i got :
[-0.085260 0.047703 -0.022851]
theta value that i should get (answer) :
[-16.38 0.1483 0.1589]
My source code :
clear ; close all; clc
x = load('/home/utlesh/Downloads/ex4x.txt');
y = load('/home/utlesh/Downloads/ex4y.txt');
theta = [0,0,0];
alpha = 0.00002;
a = [0,0,0];
m = size(x,1);
x = [ones(m,1) x];
n = size(x,2);
y_hyp = y*ones(1,n);
for kk = 1:100000
hyposis = 1./(1 + exp(-(x*theta')));
x_hyp = hyposis*ones(1,n);
theta = theta - alpha*1/m*sum((x_hyp - y_hyp).*x);
a(kk,:) = theta ;
end
cost = [0];
for kk = 1:100000
h = 1./(1 + exp(-(x*a(kk,:)')));
cost(kk,:) = sum(-y .* log(h) - (1 - y) .* log(1 - h));
end
x_axis = [0];
for kk = 1:100000
x_axis(kk,:) = kk;
end
plot(x_axis,cost);
The graph that i got looks like that of 1/x;
Please tell me where i am doing mistake . If there is anything that i misunderstood please let me know .
What I can see missing is the usage of learning rate and weights. The weights can be adjusted in two modes online and batch.
The weights should be randomly assigned values between [-0.01,0.01]. I did an exercise as a part of my HW during my Master's. Below is the snippet:
assign values to weights between [-0.01,0.01] i.e. no. of weight values will be, no. of features + 1:
weights = -.01 + 0.02 * rand(3,1);
learnRate = 0.001;
Here running the code for set number of iterations: (It converged in 100 iterations also).
while iter < 100
old_output = new_output;
delta = zeros(cols-1,1);
for t = 1:rows
input = 0;
for j = 1:cols-1
input = input + weights(j) * numericdata(t,j);
end
new_output(t) = (1 ./ (1 + exp(-input)));
for j = 1:cols-1
delta(j) = delta(j) + (numericdata(t,4)-new_output(t)) * numericdata(t,j);
end
end
#Adjusting weights (Batch Mode):
for j=1:cols-1
weights(j) = weights(j) + learnRate * (delta(j));
end
error = abs(numericdata(:,4) - new_output);
errorStr(i) = (error(:));
error = 0;
iter = iter + 1;
i = i + 1;
end
Also, I had a talk with my professor, while studying it. He said, if the dataset given has the property to converge then you will see that when you randomly run it for different number of iterations.

Connecting random points in MATLAB without intersecting lines

I need help with solving this problem. I have randomly generated points (example on Picture #1) and I want to connect them with lines (example on Picture #2). Lines can't be intersected and after connection, the connected points should look like an irregular area.
%Generating random points
xn = randi([3 7],1,10);
yn = randi([3 6],1,10);
%Generated points
xn = [6,3,7,7,6,6,6,4,6,3];
yn = [5,3,4,3,3,6,5,4,6,3];
Picture #1:
Result should be like this:
Picture #2:
Any idea how to solve this?
I suppose for the general case it can be very difficult to come up with a solution. But, assuming your points are scattered "nicely" there is quite a simple solution.
If you sort your points according to the angle above the x axis of the vector connecting the point and the center of the point cloud then:
P = [xn;yn]; %// group the points as columns in a matrix
c = mean(P,2); %// center point relative to which you compute the angles
d = bsxfun(#minus, P, c ); %// vectors connecting the central point and the dots
th = atan2(d(2,:),d(1,:)); %// angle above x axis
[st si] = sort(th);
sP = P(:,si); %// sorting the points
And that's about it. To plot the result:
sP = [sP sP(:,1)]; %// add the first point again to close the polygon
figure;plot( sP(1,:), sP(2,:), 'x-');axis([0 10 0 10]);
This algorithm will fail if several points has the same angle w.r.t the center of the point cloud.
An example with 20 random points:
P = rand(2,50);
You could adapt the code from another answer I gave for generating random simple polygons of an arbitrary number of sides. The difference here is you already have your set of points chosen and thus implicitly the number of sides you want (i.e. the same as the number of unique points). Here's what the code would look like:
xn = [6,3,7,7,6,6,6,4,6,3]; % Sample x points
yn = [5,3,4,3,3,6,5,4,6,3]; % Sample y points
[~, index] = unique([xn.' yn.'], 'rows', 'stable'); % Get the unique pairs of points
x = xn(index).';
y = yn(index).';
numSides = numel(index);
dt = DelaunayTri(x, y);
boundaryEdges = freeBoundary(dt);
numEdges = size(boundaryEdges, 1);
while numEdges ~= numSides
if numEdges > numSides
triIndex = vertexAttachments(dt, boundaryEdges(:,1));
triIndex = triIndex(randperm(numel(triIndex)));
keep = (cellfun('size', triIndex, 2) ~= 1);
end
if (numEdges < numSides) || all(keep)
triIndex = edgeAttachments(dt, boundaryEdges);
triIndex = triIndex(randperm(numel(triIndex)));
triPoints = dt([triIndex{:}], :);
keep = all(ismember(triPoints, boundaryEdges(:,1)), 2);
end
if all(keep)
warning('Couldn''t achieve desired number of sides!');
break
end
triPoints = dt.Triangulation;
triPoints(triIndex{find(~keep, 1)}, :) = [];
dt = TriRep(triPoints, x, y);
boundaryEdges = freeBoundary(dt);
numEdges = size(boundaryEdges, 1);
end
boundaryEdges = [boundaryEdges(:,1); boundaryEdges(1,1)];
x = dt.X(boundaryEdges, 1);
y = dt.X(boundaryEdges, 2);
And here's the resulting polygon:
patch(x,y,'w');
hold on;
plot(x,y,'r*');
axis([0 10 0 10]);
Two things to note:
Some sets of points (like the ones you chose here) will not have a unique solution. Notice how my code connected the top 4 points in a slightly different way than you did.
I made use of the TriRep and DelaunayTri classes, both of which may be removed in future MATLAB releases in favor of the delaunayTriangulation class.

Optimize parameters of a pairwise distance function in Matlab

This question is related to matlab: find the index of common values at the same entry from two arrays.
Suppose that I have an 1000 by 10000 matrix that contains value 0,1,and 2. Each row are treated as a sample. I want to calculate the pairwise distance between those samples according to the formula d = 1-1/(2p)sum(a/c+b/d) where a,b,c,d can treated as as the row vector of length 10000 according to some definition and p=10000. c and d are probabilities such that c+d=1.
An example of how to find the values of a,b,c,d: suppose we want to find d between sample i and bj, then I look at row i and j.
If kth entry of row i and j has value 2 and 2, then a=2,b=0,c=1,d=0 (I guess I will assign 0/0=0 in this case).
If kth entry of row i and j has value 2 and 1 or vice versa, then a=1,b=0,c=3/4,d=1/4.
The similar assignment will give to the case for 2,0(a=0,b=0,c=1/2,d=1/2),1,1(a=1,b=1,c=1/2,d=1/2),1,0(a=0,b=1,c=1/4,d=3/4),0,0(a=0,b=2,c=0,d=1).
The matlab code I have so far is using for loops for i and j, then find the cases above by using find, then create two arrays for a/c and b/d. This is extremely slow, is there a way that I can improve the efficiency?
Edit: the distance d is the formula given in this paper on page 13.
Provided those coefficients are fixed, then I think I've successfully vectorised the distance function. Figuring out the formulae was fun. I flipped things around a bit to minimise division, and since I wasn't aware of pdist until #horchler's comment, you get it wrapped in loops with the constants factored out:
% m is the data
[n p] = size(m, 1);
distance = zeros(n);
for ii=1:n
for jj=ii+1:n
a = min(m(ii,:), m(jj,:));
b = 2 - max(m(ii,:), m(jj,:));
c = 4 ./ (m(ii,:) + m(jj,:));
c(c == Inf) = 0;
d = 1 - c;
distance(ii,jj) = sum(a.*c + b.*d);
% distance(jj,ii) = distance(ii,jj); % optional for the full matrix
end
end
distance = 1 - (1 / (2 * p)) * distance;

Surface area at certain distance from line collection in Matlab, similar to contour?

Dear stackoverflow users,
Some years ago i used mathematica for several months. After not programming for a few years I now do a research project, as a student, in which I use Matlab. I have found a lot of good help here on stackoverflow but now i am stuck at the following problem:
I have a data set of connections between nodes on a rectangular grid, each node has a possible connection to its 8 neighbors. My measurements are in the form of a 3 by n matrix where the first two values designate a node and the third value designates whether or not they are connected, the size of the grid is predetermined. Typically there are about ten lines coming from two or three nodes which are neighboring at least one of each other. The goal of my research project is to calculate the area at distance r around this collection of lines.
So far I have been able to plot the lines with the code below, for which I used bits of code from right here on stackoverflow, which was extremely useful. However I cant get a contour line around it at a certain distance (with which I would hope to calculate the area inside this contour line). The gplot function returns two vectors with two coordinates per line which I find difficult to convert to something more useable. I tried defining a value Z at a distance from the lines, to decline with distance from the lines, so I get a slope coming from these lines. From this slope i could calculate contourlines. However, because the lines are just coordinates I dont know how to calculate the distance to that line, opposed to when they would have been functions.
I am really at a loss. I hope I have somewhat clearly posted my problem here. This is the second time I post this problem, I have now added comments to the code and pictures to explain myself better. Thanks for any advice given!
This I have so far, the xls file is the 3 by n matrix i mention above, I have also written its contents in matrix form in the code below so my problem is easier to understand:
%# here i set my data/constants
filename='random.xls'; file=xlsread(filename); y=width; x=length;
%# random.xls looks approximately like this, after xlsread(filename) you get
file=[21 22 1;
21 20 1;
15 16 1;
15 14 1;
15 23 1;
14 22 1;
14 21 1;
22 15 1;
23 14 1;
24 15 1;
6 15 1;
5 14 1;
7 14 1;
8 15 1];
%# predefined width and length, i usually get this from the file
width=8; length=4;
%# here i create my adjaceny matrix in a elegant way user amro posted on stackoverflow
%# however i immediately multiply it by 0, creating a y*x by y*x matrix with all zeroes
[X Y] = meshgrid(1:x,1:y); X = X(:); Y = Y(:);
adjacency = squareform( pdist([X Y], 'chebychev') == 1 ); adjacency=adjacency*0;
%# here i take the matrix "file" for which the first two values are node numbers and
%# the third value designates whether there is a connection between the two nodes to
%# fill in the connections in the adjacencymatrix
[nrows,ncols]=size(file);
for r = 1:nrows
if file(r,3)==1
adjacency(file(r,1),file(r,2))=1;
end
end
adjacency=(adjacency+adjacency.');
%# plots the adjacencymatrix
subplot(121), spy(adjacency)
%# plots the connections and designates the nodes, note that the numbers designating
%# the nodes do not match original data, this is a separate problem i have not solved
[xx yy] = gplot(adjacency, [X Y]);
subplot(122), plot(xx, yy, 'ks-', 'MarkerFaceColor','b')
%# these last lines of code for plotting the numbers of the grid i do not fully
%# understand, in here is the cause for the numbers not matching the original data
axis([0 x+1 0 y+1])
[X Y] = meshgrid(1:x,1:y);
X = reshape(X',[],1) + 0.1; Y = reshape(Y',[],1) + 0.1;
text(X, Y(end:-1:1), cellstr(num2str((1:x*y)')) )
xlabel('length')
ylabel('width')
title(filename)
to clarify my problem i added these two pictures:
current plot http://imgur.com/5uPd4
area i want to know http://imgur.com/WsIbg
Solution to finding surface area inside isoline or contourline at distance r from collection of lines in Matlab, approximation by graphical processing (dilating), not an exact or efficient awnser!
I have made an approximation, so this is not an exact awnser nor is it efficient coding. A friend of mine who studies machine vision suggested converting the lines to pixels and then dilating the image with a disk, after which the pixel count is a measure of surface area:
%# constants and variables
minx = min(xx);
miny = min(yy);
maxx = max(xx);
maxy = max(yy);
rangex = maxx - minx;
rangey = maxy - miny;
borderRelNum = sqrt(2);
electrodeToImageScaleFactor = 100;
imsizex = 2*(maxx+borderRelNum)*electrodeToImageScaleFactor+2;
imsizey = 2*(maxy+borderRelNum)*electrodeToImageScaleFactor+2;
im = zeros(imsizex, imsizey);
grayscalevalue = 255;
disksize = round(borderRelNum*electrodeToImageScaleFactor);
%# transformation matrices
centerElectrodeSpace = [1, 0, -(minx + maxx) / 2;
0, 1, -(miny + maxy) / 2;
0, 0, 1 ];
scaleElectrodeToImage = [electrodeToImageScaleFactor , 0, 0;
0, electrodeToImageScaleFactor , 0;
0, 0, 1 ];
centerImageSpace = [ 1, 0, imsizex / 2;
0, 1, imsizey / 2;
0, 0, 1 ];
electrodeToImage = centerImageSpace * scaleElectrodeToImage * centerElectrodeSpace;
%# transformation
for i = 0:(size(xx,1) / 3 - 1)
p1 = [xx(i*3 + 1); yy(i*3 + 1); 1];
p2 = [xx(i*3 + 2); yy(i*3 + 2); 1];
p1im = electrodeToImage * p1
p2im = electrodeToImage * p2
lx = linspace( min( p1im(1), p2im(1) ), max( p1im(1), p2im(1) ), borderRelNum*electrodeToImageScaleFactor )
ly = linspace( min( p1im(2), p2im(2) ), max( p1im(2), p2im(2) ), borderRelNum*electrodeToImageScaleFactor )
index = sub2ind(size(im),round(lx),round(ly));
im(index) = grayscalevalue;
end
%# Now dilate and count pixels
se = strel('disk', disksize, 0);
im = imdilate(im, se);
image(im)
colormap(gray)
sum(sum(im/grayscalevalue))*(1/electrodeToImageScaleFactor^2)
If someone is able to solve my problem more elegantly, efficiently or more precisely i would still very much appreciate it. But this will do for now.
-edit- ok this is VERY inefficient indeed, my pc has been crunching numbers for 30 minutes on my data set (10 xls files, not that much) now and is still at file 1 it seems if i look at workspace values

Resources