How to write this more cleanly in Matlab? - matlab

I know there has got to be a cleaner more elegant way to do this. I have an array of number in the range [0,1] and want to check which ones are greater than a threshold. I remember there being some syntax to do this nicely. In python I would use something like a lambda function.
p = sigmoid(dot(theta,X));
for i =1:size(p)
if(p(i)>=0.5)
p(i)=1
else
p(i)=0
end
end

mtrw is on the right track, but it gets even shorter:
p = (p >= 0.5);

You can simply say p = (p>=0.5). Boolean operators work on arrays, and return logical arrays (which consist of boolean values).

You can operate on the whole array at once:
p(p >= 0.5) = 1;
p(p < 0.5) = 0;
For what it's worth, you can do the same thing in Numpy if p is a Numpy array:
>>> p[p >= 0.5] = 1
>>> p[p < 0.5] = 0

Just for variety. You can also do:
p = floor(p + 0.5);
which also generalises to other thresholds in the range [0,1].

Related

How to vectorize a piecewise periodic function in MATLAB?

I've noticed that matlab builtin functions can handle either scalar or vector parameters. Example:
sin(pi/2)
ans =
1
sin([0:pi/5:pi])
ans =
0 0.5878 0.9511 0.9511 0.5878 0.0000
If I write my own function, for example, a piecewise periodic function:
function v = foo(t)
t = mod( t, 2 ) ;
if ( t < 0.1 )
v = 0 ;
elseif ( t < 0.2 )
v = 10 * t - 1 ;
else
v = 1 ;
end
I can call this on individual values:
[foo(0.1) foo(0.15) foo(0.2)]
ans =
0 0.5000 1.0000
however, if the input for the function is a vector, it is not auto-vectorized like the builtin function:
foo([0.1:0.05:0.2])
ans =
1
Is there a syntax that can be used in the definition of the function that indicates that if a vector is provided, a vector should be produced? Or do builtin functions like sin, cos, ... check for the types of their input, and if the input is a vector produce the same result?
You need to change your syntax slightly to be able to handle data of any size. I typically use logical filters to vectorise if-statements, as you're trying to do:
function v = foo(t)
v = zeros(size(t));
t = mod( t, 2 ) ;
filt1 = t<0.1;
filt2 = ~filt1 & t<0.2;
filt3 = ~filt1 & ~filt2;
v(filt1) = 0;
v(filt2) = 10*t(filt2)-1;
v(filt3) = 1;
In this code, we've got three logical filters. The first picks out all elements such that t<0.1. The second picks out all of the elements such that t<0.2 that weren't in the first filter. The final filter gets everything else.
We then use this to set the vector v. We set every element of v that matches the first filter to 0. We set everything in v which matches the second filter to 10*t-1. We set every element of v which matches the third filter to 1.
For a more comprehensive coverage of vectorisation, check the MATLAB help page on it.
A simple approach that minimizes the number of operations is:
function v = foo(t)
t = mod(t, 2);
v = ones(size(t)) .* (t > 0.1);
v(t < 0.2) = 10*t(t < 0.2) - 1;
end
If the vectors are large, it might be faster to do ind = t < 0.2, and use that in the last line. That way you only search through the array once. Also, the multiplication might be substituted by an extra line with logical indices.
I repeatedly hit the same problem, thus I was looking for a more generic solution and came up with this:
%your function definition
c={#(t)(mod(t,2))<0.1,0,...
#(t)(mod(t,2))<0.2,#(t)(10 * t - 1),...
true,1};
%call pw which returns the function
foo=pw(c{:});
%example evaluation
foo([0.1:0.05:0.2])
Now the code for pw
function f=pw(varargin)
for ip=1:numel(varargin)
switch class(varargin{ip})
case {'double','logical'}
varargin{ip}=#(x)(repmat(varargin{ip},size(x)));
case 'function_handle'
%do nothing
otherwise
error('wrong input class')
end
end
c=struct('cnd',varargin(1:2:end),'fcn',varargin(2:2:end));
f=#(x)pweval(x,c);
end
function y=pweval(x,p)
todo=true(size(x));
y=x.*0;
for segment=1:numel(p)
mask=todo;
mask(mask)=logical(p(segment).cnd(x(mask)));
y(mask)=p(segment).fcn(x(mask));
todo(mask)=false;
end
assert(~any(todo));
end

How to overwrite part of a vector?

I am trying to rewrite part of a vector given that:
t = -10:.1:10
x = exp((-3.*t);
The length of x will be 201, and I want to rewrite the first 100 values.
The only way I've gotten to work is by doing this:
EDIT Fixed typo.
t = 0:.1:10;
x = exp((-3.*t); % EDIT: THERE WAS A TYPO HERE
z = zeros(1,100);
for k = 1 : 100
x(k) = z(k);
end
There are three questions. First: What is a faster and more efficient way of doing this? Second: What do I do if I don't want to overwrite the first part of the code but rather the middle or the second part? Third: Is there a way of utilizing the full range of t where t = -10:.1:10 and just ignoring the first half instead of writing a whole new variable for it?
First: Nothing else I've tried has been successful.
Second: The only way I can think to do that is to append the two vectors together, but then it doesn't overwrite the data, so that is a no go.
Third:I have tried an if statement and that didn't work at all.
Your code appears to assign something to y, then changes the value of x. I assume that is a typo - and not the problem you actually want to fix.
In general, if you have
t = -10:0.1:10; % my preference: t = linspace(-10,10,201);
and
y = exp(-3 * t );
but you want to set the first 100 elements of y to zero, you can then do
y(1:100) = 0;
If you wanted never to compute y(1:100) in the first place you might do
y = zeros(size(t));
y(101:end) = exp(-3 * t(101:end));
There are many variations on this. I think the above code samples address all three of your questions.
change your
for k = 1 : 100
x(k) = z(k); % i think it should be y(k) though
end
to
x(1:100) = 0;
You could use logical indexing; that is, you can use a logical statement to select elements of a vector/matrix:
t = -10:0.1:10;
x = exp((-3.*t);
x(t < 0) = 0;
This works for the middle of a matrix too:
x(t > -5 & t < 5) = whatever;

Compute the convolution of two arrays in MATLAB

I am trying to generate an array from some starting values using this formula in MATLAB:
yt = a0 + ∑i=1p (ai ⋅ yt-i), t ≥ p
p is some small number compared to T (max t). I have been able to make this using two for cycles but it is really slow. Is there some easy way to do it?
First p values of y are provided and vector a (its length is p+1) is provided too...
This is what I have so far, but now when I tried it, it doesn't work 100% (I think it's because of indexing from 1 in MATLAB):
y1 = zeros(T+1, 1);
y1(1:p) = y(1:p);
for t = p+1:T+1
value = a1(1);
for j = 2:p+1
value = value + a1(j)*y1(t-j+1);
end
y1(t) = value;
end
EDIT: I solved it, I am just not used to Matlab indexing from 1...
This statement
if(p>=t)
looks odd inside a loop whose index expression is
for t = p+1:T+1
which seems to guarantee that t>p for the entire duration of the loop. Is that what you meant to write ?
EDIT in response to comment
Inside a loop indexed with this statement
for j = 2:p
how does the reference you make to a(j) ever call for a(0) ?
y1 = zeros(T+1, 1);
y1(1:p) = y(1:p);
for t = p+1:T+1
value = a1(1);
for j = 2:p+1
value = value + a1(j)*y1(t-j+1);
end
y1(t) = value;
end

Removing duplicate entries in a vector, when entries are complex and rounding errors are causing problems

I want to remove duplicate entries from a vector on Matlab. The problem I'm having is that rounding errors are stopping the inbuilt Matlab function 'unique' from working properly. Ideally I'd like a way to set some sort of tolerance on the 'unique' function, or a small procedure that will remove the duplicates otherwise. If both the real and imaginary parts of two entries differ by less than 0.0001, then I'm happy to consider them equal. How can I do this?
Any help will be greatly appreciated. Thanks
A simple approximation would be to round the numbers and the use the indices returned by unique:
X = ... (input vector)
[b, i] = unique(round(X / (tolerance * (1 + i))));
output = X(i);
(you can probably replace b with ~ depending on your Matlab version).
it won't quite have the behaviour you want, since it is possible that two numbers are very close but will be rounded differently. I think you could mitigate this by doing:
X = ... (input vector)
[b, ind] = unique(round(X / (tolerance * (1 + i))));
X = X(ind);
[b, ind] = unique(round(X / (tolerance * (1 + i)) + 0.5 * (1 + i)));
X = X(ind);
This will round them twice, so any numbers that are exactly on a rounding boundary will be caught by the second unique.
There is still some messiness in this - some numbers will be affected as though the tolerance was doubled. But it might be sufficient for your needs.
The alternative is probably a for loop:
X = sort(X);
last = X(1);
indices = ones(numel(X), 1);
for j=2:numel(X)
if X(j) > last + tolerance * (1 + i)
last = X(j) + tolerance * (1 + i) / 2;
else
indices(j) = 0;
end
end
X = X(logical(indices));
I think this has the best behaviour you can expect (because you want to represent the vector by as few unique values as possible - when there are lots of numbers that differ by less than the tolerance level, there may be multiple ways of splitting them. This algorithm does so greedily, starting with the smallest).
I'm almost certain the below ill always assume any values closer than 1e-8 are equal. Simply replace 1e-8 with whatever value you want.
% unique function that assumes 1e-8 is equal
function [out, I] = unique(input, first_last)
threshold = 1e-8;
if nargin < 2
first_last = 'last';
end
[out, I] = sort(input);
db = diff(out);
k = find(abs(db) < threshold);
if strcmpi(first_last, 'last')
k2 = min(I(k), I(k+1));
elseif strcmpi(first_last, 'first')
k2 = max(I(k), I(k+1));
else
error('unknown flag option for unique, must be first or last');
end
k3 = true(1, length(input));
k3(k2) = false;
out = out(k3(I));
I = I(k3(I));
end
The following might serve your purposes. Given X, an array of complex doubles, it sorts them, then checks whether the absolute value differences between elements is within the complex tolerance, real_tol and imag_tol. It removes elements that satisfy this tolerance.
function X_unique = unique_complex_with_tolerance(X,real_tol,imag_tol)
X_sorted = sort(X); %Sorts by magnitude first, then imaginary part.
dX_sorted = diff(X_sorted);
dX_sorted_real = real(dX_sorted);
dX_sorted_imag = imag(dX_sorted);
remove_idx = (abs(dX_sorted_real)<real_tol) & (abs(dX_sorted_imag)<imag_tol);
X_unique = X_sorted;
X_unique(remove_idx) = [];
return
Note that this code will remove all elements which satisfy this difference tolerance. For example, if X = [1+i,2+2i,3+3i,4+4i], real_tol = 1.1, imag_tol = 1.1, then this function will return only one element, X_unique = [4+4i], even though you might consider, for example, X_unique = [1+i,4+4i] to also be a valid answer.

MATLAB and function

I want to calculate the function y(t) from the equation:
y(t) = -3t^2+5, t>=0
y(t) = 3t^2+5, t<0
for -9 <= t <= with the step-size 0.5
And I want to plot it by using MATLAB. I approach this question in two ways:
First
t=0:0.5:9
y=-3*t^2+5
t1=-0.00000000001:0.5:-9
y1=3*t^2+5
plot(t,y,t1,y1)
Second by using loop
t=-9:0.5:9
if(t>=0)
y=-3*(t.^2)+5
else
y=3.*(t.^2)+5
end
plot(t,y)
My problem is the two ways above seem not to give the same answer... Which one is the correct answer?
You can use the sign function to do this particular example a little easier:
t = -9:0.5:9;
y = -sign(t)*3.*t.^2 + 5;
plot(t,y);
In your first attempt, your t1 definition should be:
t1 = 0:-0.5:-9;
Note the minus sign on the increment.
Using a "loop" you seem to have left out the actual loop part. Try something like
t = -9:0.5:9;
for idx = 1:length(t)
if t(idx) <= 0
y(idx) = -3*(t(idx).^2)+5
etc.
Here's a more idiomatic solution that avoids SIGN for cases where that's not the only difference.
t = -9:0.5:9
y = -3*t.^2+5
y(t<0) = 3*t(t<0).^2+5
plot(t, y)