Function to find entries with same maximum value in a vector - matlab

In my project I need a function which returns the index of the largest element of a given vector. Just like max. For more than one entry with the same maximum value (which occurs frequently) the function should choose one randomly. Unlike max.
The function is a subfunction in a MATLAB Function Block in Simulink. And the whole Simulink model is compiled.
My basic idea was:
function ind = findOpt(vector)
index_max = find(vector == max(vector));
random = randi([1,length(index_max)],1);
ind = index_max(random);
end
But I got problems with the comparison in find and with randi.
I found out about safe comparison here: Problem using the find function in MATLAB. Also I found a way to replace randi([1,imax],1): Implement 'randi' using 'rand' in MATLAB.
My Code now looks like this:
function ind = findOpt(vector)
tolerance = 0.00001;
index_max = find(abs(vector - max(vector)) < tolerance);
random = ceil(length(index_max)*rand(1));
ind = index_max(random);
end
Still doesn't work. I understand that the length of index_max is unclear and causes problems. But I can not think of any way to know it before. Any ideas how to solve this?
Also, I'm shocked that ceil doesn't work when the code gets executed?? In debug mode there is no change to the input visible.
I thought about creating an array like: index_max = abs(vector - max(vector)) < tolerance; But not sure how that could help. Also, it doesn't solve my problem with the random selection.
Hopefully somebody has more ideas or at least could give me some hints!
I am using MATLAB R2012b (32bit) on a Windows7-64bit PC, with the Lcc-win32 C 2.4.1 compiler.
Edit:
Vector usually is of size 5x1 and contains values between -2000 and zero which are of type double, e.g. vector = [-1000 -1200 -1000 -1100 -1550]'. But I think such a simple function should work with any kind of input vector.
The call of length(index_max) causes an system error in MATLAB and forces me to shut it down. I guess this is due to the strange return I get from find. For a vector with all the same values the return from find is something like [1.000 2.000 1.000 2.000 0.000]' which doesn't make any sense to me at all.

function v= findOpt(v)
if isempty(v)
return;
end
v = find((max(v) - v) < 0.00001);
v = v(ceil(rand(1)*end));
end

I was indeed overloading, just like user664303 suggested! Since I can not use objects in my project, I wanted an function that behaves similar, so I wrote:
function varargout = table(mode, varargin)
persistent table;
if isempty(table) && ~strcmp(mode,'writeTable')
error(...)
end
switch mode
case 'getValue'
...
case 'writeTable'
table = ...
...
end
end
Wanted to avoid passing the dimensions for the table in every call and thought it would be enough if the first call initializes the Table with mode='writeTable'. Looks like this caused my problem.
No problems after changing to:
if isempty(table)
table = zeros(dim1,dim2,...)
end

Related

Declaring a functional recursive sequence in Matlab

I'd like to declare first of all, that I'm a mathematician. This might be a stupid stupid question; but I've gone through all the matlab tutorials--they've gotten me nowhere. I imagine I could code this in C (it'd be exhausting); but I need matlab for this particular function. And I don't get exactly how to do it.
Here is the pasted Matlab code of where I'm running into trouble:
function y = TAU(z,n)
y=0;
for i =[1,n]
y(z) = log(beta(z+1,i) + y(z+1)) - beta(z,i);
end
end
(beta is an arbitrary "float" to "float" function with an index i.)
I'm having trouble declaring y as a function, in which we call the function at a different argument. I want to define y_n(z) with something something y_{n-1}(z+1). This is all done in a recursive process to create the function. I really feel like I'm missing something stupid.
As a default function it assigns y to be an array (or whatever you call the default index assignment). But I don't want an array. I want y to be assigned as a "function" class (i.e. takes "float" to "float"). And then I'm defining a sequence of y_n : "float" to "float". So that z to z+1 is a map on "float" to "float".
I don't know if I'm asking too much of matlab...
Help a poor mathematician who hasn't coded since the glory days of X-box mods.
...Please don't tell me I have to go back to Pari-GP/C drawing boards over something so stupid.
Please help!
EDIT: At rahnema1 & mimocha's request, I'll describe the math, and of what I am trying to do with my program. I can't see how to implement latex in here. So I'll write the latex code in a generator and upload a picture. I'm not so sure if there even is a work around to what I want to do.
As to the expected output. We'd want,
beta(z+1,i) + TAU(z+1,i) = exp(beta(z,i) + TAU(z,i+1))
And we want to grow i to a fixed value n. Again, I haven't programmed in forever, so I apologize if I'm speaking a little nonsensically.
EDIT2:
So, as #rahnema1 suggests; I should produce a reproducible example. In order to do this, I'll write the code for my beta function. It's surprisingly simple. This is for the case where the "multiplier" variable is set to log(2); but you don't need to worry about any of that.
function f = beta(z,n)
f=0;
for i = 0:n-1
f = exp(f)/(1+exp(log(2)*(n-i-z)));
end
end
This will work fine for z a float no greater than 4. Once you make z larger it'll start to overflow. So for example, if you put in,
beta(2,100)
1.4242
beta(3,100)
3.3235
beta(3,100) - exp(beta(2,100))/(1/4+1)
0
The significance of the 100, is simply how many iterations we perform; it converges fast so even setting this to 15 or so will still produce the same numerical accuracy. Now, the expected output I want for TAU is pretty straight forward,
TAU(z,1) = log(beta(z+1,1)) - beta(z,1)
TAU(z,2) = log(beta(z+1,2) + TAU(z+1,1)) - beta(z,2)
TAU(z,3) = log(beta(z+1,3) + TAU(z+1,2)) - beta(z,3)
...
TAU(z,n) = log(beta(z+1,n) + TAU(z+1,n-1)) -beta(z,n)
I hope this helps. I feel like there should be an easy way to program this sequence, and I must be missing something obvious; but maybe it's just not possible in Matlab.
At mimocha's suggestion, I'll look into tail-end recursion. I hope to god I don't have to go back to Pari-gp; but it looks like I may have to. Not looking forward to doing a deep dive on that language, lol.
Thanks, again!
Is this what you are looking for?
function out = tau(z,n)
% Ends recursion when n == 1
if n == 1
out = log(beta(z+1,1)) - beta(z,1);
return
end
out = log(beta(z+1,n) + tau(z+1,n-1)) - beta(z,n);
end
function f = beta(z,n)
f = 0;
for i = 0:n-1
f = exp(f) / (1 + exp(log(2)*(n-i-z)));
end
end
This is basically your code from the most recent edit, but I've added a simple catch in the tau function. I tried running your code and noticed that n gets decremented infinitely (no exit condition).
With the modification, the code runs successfully on my laptop for smaller integer values of n, where 1e5 > n >= 1; and for floating values of z, real and complex. So the code will unfortunately break for floating values of n, since I don't know what values to return for, say, tau(1,0) or tau(1,0.9). This should easily be fixable if you know the math though.
However, many of the values I get are NaNs or Infs. So I'm not sure if your original problem was Out of memory error (infinite recursion), or values blowing up to infinity / NaN (numerical stability issue).
Here is a quick 100x100 grid calculation I made with this code.
Then I tested on negative values of z, and found the imaginary part of the output to looks kinda cool.
Not to mention I'm slightly geeking out over the fact that pi is showing up in the imaginary part as well :)
tau(-0.3,2) == -1.45179335740446147085 +3.14159265358979311600i

Post and previous values for an analog input inside a matlab function block in Simulink

I need a Simulink block or a group of blocks to make peak detection: compare each value of an input stream to its previous and post values. If it's larger than the previous AND larger than the next value, output this value.
I've tried to do it with a Matlab Function Block, but I cannot make the required delay. I mean it's not possible, as far as I tried, to store previous values for example.
So, what should I do?
Update: Another example
In responding to the comments, suggested solutions are helpful if I'm dealing with discrete values. So here is another example to represent my need:
A Schmidt Trigger
I need to implement a Matlab function to implement the given scenario. I can do something like
if u >= 2
y = 3;
elseif (u < 2)
y = -3;
But still this is not correct as I need to look at the previous value (hysteresis) of the input, other wise I'll end up having something like the following
PS: I know there is nothing called previous value in analog, but we all know that Simulink is dealing with analog values as a discrete in the end (much larger sampling). So I think maybe there is a way to do it.
I think your code is fine except for one minor mistake:
if u > 2
y = 3;
elseif u < -2
y = -3;
else
y = u;
The variable 'u' in elseif part should get compared with the -2 (upper threshold but with a negative sign)
Hope it helps!

Getting into an infinite loop in MATLAB function

I'm trying to plot a function on matlab that's defined such that:
Y=-100t ; 0>=t>=0.15
Y=-15 ; t>.15
I'm using the following code:
function [ Y ] = Gain( t )
for t=[0:0.01:0.15]
Y=-100*t
end
for t=0.15:0.01:2
Y=-15
end
plot (Gain)
but I'm going into an infinite loop!
Would someone please solve this problem for me.
Thank you.
Functions don't work like that in MATLAB, unfortunately. (Or at least I don't think they do). Try something like this:
function Y = Gain(t)
Y = -100*t;
Y(t >= 0.15) = -15;
end
x = 0:0.01:2;
plot(x, Gain(x))
MATLAB still uses C-esque functions, so you have to define it that way, using C-style syntax, instead of more math-like syntax, unfortunately. I'm multiplying the input values by -100, then for the ones that match up to where t is greater than 15, I replace those with -15. MATLAB is weird.
Edit: Sorry, previous code sample also used the wrong syntax.. MATLAB is weird.
I'm not certain what you're TRYING to do, but when you call the Gain function "from outside", so to speak,...
You enter the Gain function
The first for loop executes, overwriting passed-in value of t with each iteration. (Therefore, the value of t that you passed in is completely ignored, the way that you have this code written.)
The second for-loop executes, and
You call plot(Gain), which forces Gain to be called again, this time with no arguments. Back to 1.
Repeat forever.

How to add elements to a vector in matlab

I've looked around on the internet a bit and cannot seem to find the answer to this question. I want to declare a vector in matlab and then have a for loop that will add an element to the vector each time I go through the for loop.
This is what I've tried and it doesn't seem to be working
vector[];
for k = 1 ; 10
%calculate some value
%calculated value stored in temp variable
vector(k) = temp;
end
This does not work. Does anybody know how to solve this issue?
As ypnos said, you don't need to declare the vector variable upfront. For example if you did:
vector(50) = 1;
MATLAB would make a vector of length 50 with the 50th value being 1. If you want to improve performance and want to create a vector of the proper size beforehand then do the following:
vector = zeros(10, 1);
The code as you have it (as long as you fix the loop as ypnos said) will work, except for how you declare vector, which is not correct. I bet you are getting the error message: "Error: Unbalanced or unexpected parenthesis or bracket." You do not specify whether a variable is a matrix/vector in MATLAB.
vector = [vector; temp];
or
vector(end+1) = temp;

Matlab plot won't return correct results

I have written a function that is the beginning of a Poisson Process
function n_t = PoisProc2(t,tao,SIZE)
n_t=0;
for n=1:SIZE
if t>tao(1,n)
n_t=n_t+1;
end
end
end
tao is simply an array of random doubles of length SIZE. For simplicity we'll say [1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,20]
So this functions purpose is to count how many elements of tao that t is greater than for any given t.
This code works fine when I simply write
PoisProc2(3,tao,20);
the answer I get is 19 as expected, but if I write
x=1:.01:20;
y=PoisProc2(x,tao,20);
plot(x,y,'-')
y shows up as 0 in the workspace (I would expect an array of length 1901) and my plot also reads 0. I'm pretty new to Matlab, but this seems like a pretty simply thing I'm trying to do and I must be missing something obvious. Please help!
Your code does not work as you are giving a vector. So your if condition is not working as you expect.
First initialize n_t with a vector :
n_t=zeros(1,length(t))
instead of
if t>tao(1,n)
n_t=n_t+1;
end
Vectorize your expression :
n_t = n_t + (t>tao(1,n))
Cheers
Because x is a vector in your last example, the "if t>tao(1,n)" statement in your function behave totally different from what you think.
This function below should give you the right result.
function ret = PoisProc2(thresholds, vec)
ret = zeros(size(thresholds));
for k = 1:numel(thresholds)
ret(k) = numel(nonzeros(vec > thresholds(k)));
end
Side comments:
Your original function is quite C/Java style. You can see in my function, it's replaced by a one-liner "numel(nonzeros(vec > thresholds(k)))", which is more MATLAB style.
I think this can be done with hist() function. But this probably is easier to understand.