1

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.

Community
  • 1
  • 1
FxH
  • 44
  • 4
  • 1
    what does not work? Tried your code in matlab and it seems fine? – stijn Jan 15 '14 at 15:09
  • 1
    In MATLAB it works fine for me, too. But running the Simulink model causes an runtime error, saying: "Expected an integer value, found non-integer variable random with value 4.07362." For the line with: ind=index_max(random); – FxH Jan 15 '14 at 15:26
  • hmm. That is interesting.. – stijn Jan 15 '14 at 15:30
  • implement ceil yourself. – Autonomous Jan 15 '14 at 17:24
  • could you post your vector? I guess there are lot of simple solutions using `find` and `randi`, but I guess you don't want to use them – Autonomous Jan 15 '14 at 17:24
  • Put `random = length(index_max)*rand(1)` and `random = ceil(random)` on consecutive lines, without a semicolon. What is the output from those two lines? Also put `which ceil` in the function, after the line calling ceil, and give us the output of that line too. – user664303 Jan 15 '14 at 17:30
  • Putting `which ceil` gives me an coder error, stating: "Function 'which' is not supported for coed generation. [...]". And `ceil(x)` still returns x. – FxH Jan 15 '14 at 17:57
  • If you open a fresh MATLAB and call `findOpt(rand(100, 1))`, does it work? If so, I guess that the code from which you normally call `findOpt()` is overloading `ceil()`; you need to find where. – user664303 Jan 16 '14 at 09:33
  • I stored `findOpt()` in a M-file and did like you said. Works perfectly fine, even for my original implementation. But still, in a MATLAB function block in Simulink it won't work. Don't think I'm overloading `ceil`. Could it be an issue with the compiler? Tomorrow I'll get the chance to try it on a different PC. Let's see what happens there ... – FxH Jan 16 '14 at 17:43

2 Answers2

0
function v= findOpt(v)
if isempty(v)
    return;
end
v = find((max(v) - v) < 0.00001);
v = v(ceil(rand(1)*end));
end
user664303
  • 2,053
  • 3
  • 13
  • 30
  • Tried it, but still get an runtime error for "ceil(rand(1)*end)" Somehow ceil doesn't do what it should do and just passes through "rand(1)*end". – FxH Jan 15 '14 at 15:41
  • What's the output of `which ceil`? Mine is `built-in (C:\Program Files\MATLAB\R2013b\toolbox\matlab\elfun\@double\ceil) % double method`. – user664303 Jan 15 '14 at 16:47
  • `built-in (C:\Program Files (x86)\MATLAB\R2012b\toolbox\matlab\elfun\@double\ceil) % double method` – FxH Jan 15 '14 at 17:00
0

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
FxH
  • 44
  • 4