The code I wrote to do this looks something like this:
s = get(handles.editParam1, 'String');
try
eval(['param1=' s ';']);
catch
...
end;
% get 2nd & 3rd parameters in same way
for p1 = param1
for p2 = param2
for p3 = param3
DoSimulation(p1, p2, p3);
end;
end;
end;
Is there a neater and/or more flexible way of doing this?
My concern is that each parameter is tied to a particular edit box
and another nesting of the for loops. So if I wanted to add another
three possible parameters (say), I would have to make space for
three new edit boxes and further indent the looping code.
What would be nice would be to allow arbitrary parameter
specifications to be typed into one edit box, e.g. "p1=1:5 p2=0.4",
and have the code go through the combinations automatically.
Is this possible in Matlab? (I'm not so worried about performance.)
Francis
1) have users put a <delimiter> between sets of parameters in
your edit box, eg, </>
2) <s> now could look like this
s='p1=1:5 / p2=0.4 / p3=pi*[0:10]'
3) retrieve each parameter
b=s;
plist=[];
while ~isempty(b)
[a,b]=strtok(b,'/');
com=sprintf('plist.%s',a);
eval(com);
end
4) ... you'll end up with <plist>:
plist =
p1: [1 2 3 4 5]
p2: 0.4
p3: [1x11 double]
5) run your loop
for p1=plist.p1
for p2=plist.p2
% ...
end
end
us
Francis Burton wrote:
> s = get(handles.editParam1, 'String');
> try
> eval(['param1=' s ';']);
> catch
> ...
> end;
>
> % get 2nd & 3rd parameters in same way
I like this! Thanks for the new ideas.
>5) run your loop
> for p1=plist.p1
> for p2=plist.p2
>% ...
> end
> end
Is there any way to avoid "hardwiring" the loops in this way
and have the iterations 'eval'ed somehow? Maybe a function
that takes the above plist containing an arbitrary number of
elements and calls another function repeatedly with that
number of arguments, once for each combination.
Francis
One thing that might work for you is using NDGRID (assuming you know or can
find out the number of parameters ... maybe by capturing each variable name
while tokenizing the string) and either calling your function on those
multi-D arrays (assuming the function is vectorized) or looping once from 1
to the number of elements in one of the arrays NDGRID created (using NUMEL)
and operating on the appropriate elements of those multi-D arrays
individually.
--
Steve Lord
sl...@mathworks.com
there is.
some time ago i created an automatic loop-creator <aloop>,
which does exactly what you want. i uploaded it to TMWs central;
maybe it appears within the next years :-)
here's how it works:
c=aloop(a_command_template,...
option,...
indices1,...,indicesN);
eg,
c=aloop('sprintf(''%2d/%7.3f > %s'')',...
'-c',...
1:2,pi*[1:3],{'apple' 'banana'})
% output during runtime shows progression
ALOOP> sprintf(' 1/ 3.142 > apple')
ALOOP> sprintf(' 1/ 3.142 > banana')
ALOOP> sprintf(' 1/ 6.283 > apple')
ALOOP> sprintf(' 1/ 6.283 > banana')
ALOOP> sprintf(' 1/ 9.425 > apple')
ALOOP> sprintf(' 1/ 9.425 > banana')
ALOOP> sprintf(' 2/ 3.142 > apple')
ALOOP> sprintf(' 2/ 3.142 > banana')
ALOOP> sprintf(' 2/ 6.283 > apple')
ALOOP> sprintf(' 2/ 6.283 > banana')
ALOOP> sprintf(' 2/ 9.425 > apple')
ALOOP> sprintf(' 2/ 9.425 > banana')
c =
tmpl: sprintf('%2d/%7.3f > %s')'
opt: [1x1 struct]
argc: 3 % nr of index args
call: 24 % nr of internal recursions
n: 12 % nr of commands created
com: {12x1 cell}
c.com = % cell of command(s)
'sprintf(' 1/ 3.142 > apple')'
'sprintf(' 1/ 3.142 > banana')'
'sprintf(' 1/ 6.283 > apple')'
'sprintf(' 1/ 6.283 > banana')'
'sprintf(' 1/ 9.425 > apple')'
'sprintf(' 1/ 9.425 > banana')'
'sprintf(' 2/ 3.142 > apple')'
'sprintf(' 2/ 3.142 > banana')'
'sprintf(' 2/ 6.283 > apple')'
'sprintf(' 2/ 6.283 > banana')'
'sprintf(' 2/ 9.425 > apple')'
'sprintf(' 2/ 9.425 > banana')'
you can run commands:
for i=1:c.n
eval(c.com{i})
end
alternatively, <aloop> takes the option
-r
in which case the <template> is <eval>ed right away in
the base workspace
as you might guess, this snippet is rather versatile.
us
I will check weekly, if not daily, for it. :-)
It looks like it will solve my problem nicely, and be
worthwhile studying to learn a bit more about "advanced
programming" in Matlab.
Thanks!
Francis
The number of parameters will vary (which is why I didn't
like the hardcoded option), but will be known.
I think what you suggest could well work - and work well!
I briefly racked my brains for a solution based on matrices,
until it became apparent how many gaps there still are in my
working knowledge. Your clue will spur me on to fill some of
those gaps - thanks!
Francis
This particular usage of strtok in a loop to run through a string can be
very slow for long strings. You are much better off using
b= strread(s,'%s','delimiter','/');
to pull the string apart.
So you would then use something like this to achieve the same goal.
plist=[];
b = strread(s,'%s','delimiter','/')'
for count = 1:numel(b)
com=sprintf('plist.%s',b{count});
eval(com);
end
Rob
very bad news, rob:
in the past, i used to use <strread> because after all its main
engine (<dataread>) is mex-ed.
however, the max token size is 4095!
now, you assume that the user will enter a <very long> string
...
eg,
nr=1000;
nd=10;
z=char(double('a':'z'));
s=repmat(z,1,nr);
v=randperm(length(g));
s(v(1:nd))='/';
b = strread(s,'%s','delimiter','/')';
which typically yields:
??? Buffer overflow (bufsize = 4095) while reading string from
file (row 4, field 1) ==> uvwxyzabcdefghi
Error in ==> G:\usr\ml13\toolbox\matlab\iofun\dataread.dll
Error in ==> G:\usr\ml13\toolbox\matlab\iofun\strread.m
On line 51 ==> [varargout{1:nlhs}]=dataread('string',varargin{:});
hence, i didn't feel comfortable to suggest this - otherwise very
nice - function.
assuming of course that the OP gui users would find the time to enter
several thousand characters into the edit box ...
:-)
us
You are correct. The command to get around this is:
b = strread(s,'%s','delimiter','/','bufsize',2*numel(s)+1)';
This somewhat pathological example shows the performance difference.
s = repmat('a/',1,50000);
tic;b = strread(s,'%s','delimiter','/','bufsize',2*numel(s)+1)';toc
elapsed_time =
0.3710
tic; b=s; while ~isempty(b), [a,b] = strtok(b,'/');end; toc
elapsed_time =
128.2250
Rob
rob, only slighty pathological for most ML users ...
> shows the performance difference.
<SNIP BIGGISH performance delta>
... touche!
repmat(' :-) ',inf,inf)
us
... and this afterthought:
unfortunately, the average user (such as myself) will not see these
additional parameters using a pedestrian
help strread
he/she rather has to scrutinize
help textread
while it IS mentioned, it isn't THAT obvious
a lame excuse - i know
us
us wrote:
>
>
> Francis Burton wrote:
>> Is there any way to avoid "hardwiring" the loops in this way
>> and have the iterations 'eval'ed somehow? Maybe a function
>> that takes the above plist containing an arbitrary number of
>> elements and calls another function repeatedly with that
>> number of arguments, once for each combination.
>
> there is.
>
> some time ago i created an automatic loop-creator <aloop>,
> which does exactly what you want. i uploaded it to TMWs central;
> maybe it appears within the next years :-)
>
<http://www.mathworks.com/matlabcentral/fileexchange/loadFile.do?object>
Id=3338&objectType=FILE
note there was an earlier version that should NOT have been uploaded
us
us wrote:
> i uploaded the file <aloop> a few days ago; it still hasn't
> show up, however
Try run this example:
methods = {'vek' 'lc'}'
pnames = {'mjpn', 'fjpn'};
% iteration
dsu = [];
dsu.methods = methods;
dsu.pnames = pnames;
n = dsfactorsidx(dsu);
for i = 1:n
[k, di] = dsfactorsidx(dsu, i);
disp(i)
disp(di);
end
Hope it is help
Kirill Andreev
function [j, di] = dsfactorsidx(dsu, i);
% dsfactorsidx(): given row index of a normalized data set returns
indices of unique factor levels
% Description:
%
% Suppose we have the following structure with unique levels of
factor variables:
% dsu=[];
% dsu.population = {'jpn' 'dnk'};
% dsu.sex = [1 2];
% dsu.decade = [1950 1960 1970];
%
% [[it is important to use dsu =[] so the fieldnames() will return
% {'population' 'sex' 'decade'}. In this case we know the order of
fields.
% If 'dsu' have been initialized fieldnames() will return fields in
order of initialization]]
%
% In this case normalized data set will have 3 columns and 12 rows
and the following form
%
% jpn 1 1950 1
% jpn 1 1960 2
% jpn 1 1970 3
% jpn 2 1950 4
% jpn 2 1960 5
% jpn 2 1970 6
% dnk 1 1950 7
% dnk 1 1960 8
% dnk 1 1970 9
% dnk 2 1950 10
% dnk 2 1960 11
% dnk 2 1970 12
%
% The second parameter 'i' of this procedure is interpreted as a
row number of this data set (see the last column).
% For any 'i' between 1 and 12 this procedure returns indices of
factor variables stored in 'dsu'.
% If i = 9, for example, it returns [2 1 3] and corresponding
levels are
% di.population = {'dnk'};
% di.sex = 1;
% di.decade = 1970;
%
% Structure 'di' is returned as a second output argument.
%
% If no 'i' specified, the total number of unique combinations of
factor levels
% (number of rows in the normalized data set) is returned (12 in
this example).
%
% One of the important applications of this procedure is mapping of
multi-level nested loops into
% a single level loop. Suppose we need to loop over following
variables:
% dsu=[];
% dsu.population = {'jpn' 'dnk'};
% dsu.sex = [1 2];
% dsu.decade = [1950 1960 1970];
% This can be accomplished with the following code:
%
% n = dsfactorsidx(dsu)
% for i = 1:n
% [j, di] = dsfactorsidx(dsu)
% end
%
%
% Parameters:
% dsu - structure with unique factor levels
% i - row index of normalized data set
% Returns:
% j - indices of factor variables
% di - structure with combination of factor levels corresponding to j
% Example:
% Notes:
% This procedure doesn't create a normalized data set in memory so it
is very fast
% See also:
% Date of revision: 2002-11-27
% Copyright (c) Kirill Andreev
% get numbers of factor levels
f = fieldnames(dsu);
l = zeros(length(f), 1);
j = 1;
for k = 1:length(f)
l(k) = length(getfield(dsu, f{k}));
end
if nargin < 2
% return total number of unique combinations of factor levels
j = prod(l);
return
end
j = zeros(size(l));
m = rev(cumprod(rev(l))) ./ l;
for k = 1:length(l)
j(k) = ceil(i / m(k));
i = i - (j(k)-1) * m(k);
end
di = [];
k = 1;
for k = 1:length(f)
v = getfield(dsu, {1,1}, f{k}, {j(k)});
di = setfield(di, f{k}, v);
end
Error in ==> C:\MATLAB6p5\work\multiloop.m (dsfactorsidx)
On line 126 ==> m = rev(cumprod(rev(l))) ./ l;
Error in ==> C:\MATLAB6p5\work\multiloop.m
On line 19 ==> [k, di] = dsfactorsidx(dsu, i);
function y = rev(x);
% rev(): reverses the order of the rows in a matrix
% Parameters:
% x - matrix to be reversed
% Date of revision: 2001-08-29
% Copyright (c) Kirill Andreev
y = flipud(x);
Will <was...@sina.com> wrote in message news:<eebce...@WebX.raydaftYaTP>...
> Ok, going to profile..
>
> function y = rev(x);
> % rev(): reverses the order of the rows in a matrix
> % Parameters:
> % x - matrix to be reversed
> % Date of revision: 2001-08-29
> % Copyright (c) Kirill Andreev
>
> y = flipud(x);
First of all, why do you need an alias for "flipud"? Why not
simply call "flipud" directly?
Secondly, "rev" is a very generic term and a function with such a
generic name ought to be more general than this.
Peter
--
I wish dialog boxes had a button saying "Whatever". I hate being
forced to answer "Yes" or "No" to a question I have no opinion on
whatsoever. There ought to be a button matching my indifference.
not <generic> anymore, peter:
the creator put a <copyright> on it!
us
For a pretty generic reversing function, try my "flipdims", which
is an extension of "flipdim" in two ways:
1) You can flip along as many dimensions as you want, as many
times as you want.
2) If no dimension is given, it flips along the first
non-singleton dimension.
As a special case: Given a vector, the vector is REVersed. :-)
http://home.online.no/~pjacklam/matlab/software/util/matutil/flipdims.m