[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Performance of odeset
From: |
Rik |
Subject: |
Performance of odeset |
Date: |
Mon, 17 Oct 2016 10:08:57 -0700 |
10/17/16
Carlo,
I made a stab at improving the performance of odeset. The code in question is:
-- Code --
if (nargin == 0 && nargout == 0)
print_options ();
else
p.parse (varargin{:});
odestruct = p.Results;
odestruct_extra = p.Unmatched;
## FIXME: For speed, shouldn't this merge of structures only occur
## when there is something in odestruct_extra?
## FIXME: Should alphabetical order of fieldnames be maintained
## by using sort?
s1 = cellfun (@(x) ifelse (iscell (x), {x}, x),
struct2cell (odestruct),
"UniformOutput", false);
s2 = cellfun (@(x) ifelse (iscell (x), {x}, x),
struct2cell (odestruct_extra),
"UniformOutput", false);
C = [fieldnames(odestruct) s1;
fieldnames(odestruct_extra) s2];
odestruct = struct (C'{:});
endif
-- End Code --
I benchmarked the code in the else branch 50 times with the input
x = odeset ("RelTol", 1e-1);
Running times:
median = 2.44 ms
mean = 2.59 ms
Most of the time there will never be an option in odestruct_extra so it is
useless to merge an empty struct into it. I modified the code to test that.
-- Code 2 --
else
p.parse (varargin{:});
odestruct = p.Results;
odestruct_extra = p.Unmatched;
## FIXME: For speed, shouldn't this merge of structures only occur
## when there is something in odestruct_extra?
## FIXME: Should alphabetical order of fieldnames be maintained
## by using sort?
fields2 = fieldnames (odestruct_extra);
if (! isempty (fields2))
s1 = cellfun (@(x) ifelse (iscell (x), {x}, x),
struct2cell (odestruct),
"UniformOutput", false);
s2 = cellfun (@(x) ifelse (iscell (x), {x}, x),
struct2cell (odestruct_extra),
"UniformOutput", false);
C = [fieldnames(odestruct) s1;
fieldnames(odestruct_extra) s2];
odestruct = struct (C'{:});
endif
endif
-- End Code 2 --
Using the same benchmark running 50 times.
Running times:
median = .0379 ms
mean = .0385 ms
That's a 64X speedup so is worth doing.
Next I tried running with an input which will force the code to be used.
x = odeset ("FooBar", 1e-1);
I ran that 50 times and the results are similar to the first instance since
the merger of two structs is happening.
Running times:
median = 2.41 ms
mean = 2.46 ms
For small N, loops are often quite fast. Since the number of unknown ODE
solver options is unlikely to be very large, I tried re-coding the merging
of the structures to
-- Code 3 --
fields2 = fieldnames (odestruct_extra);
if (! isempty (fields2))
for [ val, key ] = odestruct_extra
odestruct.(key) = val;
endfor
endif
-- End Code 3 --
Running times:
median = .0501 ms
mean = .0542 ms
Only a 48X improvement, but still worth doing.
I attached the patch to https://savannah.gnu.org/bugs/index.php?49364 for
your review. Within the for loop seems a natural place to also issue a
warning for each unknown property that is used which is the subject of that
bug report.
--Rik
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- Performance of odeset,
Rik <=