Say I have a function foo that can return three values given an input:
function [a,b,c] = foo(input)
The calculations of variables b and c take a long time, so sometimes I may wish to ignore their calculation within foo. If I want to ignore both calculations, I simply call the function like this:
output1 = foo(input);
and then include nargout within foo:
if nargout == 1
% Code to calculate "a" only
else
% Code to calculate other variables
The problem occurs if I want to calculate the last output, but not the second. In that case my function call would be:
[output1,~,output3] = foo(input);
Now if I use nargout within foo to check how many outputs are in the function-call, it will always return 3 because the tilde operator (~) is considered a valid output. Therefore, I cannot use nargout to determine whether or not to calculate the second output, b, within foo.
Is there any other way to do this? I.e., is it possible to check which outputs of a function-call are discarded from within the function itself?
The commenters are basically right; this is not something that can be totally solved by the user unless The MathWorks adds functionality. However, I wrote a small function, istilde (Wayback Machine Archive), a while back that attempts to do what you ask. It works in many cases, but it's really a bit of hack and not a totally robust solution. For example, I did not attempt to get it to work for functions called from the Command Window directly (this could potentially be added with some work). Also, it relies on parsing the actual M-file, which can have issues. See the included demo file for how one might use istilde.
Feel free to edit my code for your needs – just don't use this in any production code due to the robustness issues. Any improvements would be welcome.
Related
I have an ODE for calculating how acidicity changes. Everything is working just fine, only I would like to change a constant whenever acidicity reaches a critical point. It is supposed to be some kind of irreversible effect I wish to simulate.
My constants are coming from a structure file (c) I load once in the ODE function.
[Time,Results] = ode15s(#(x, c) f1(x, c),[0 c.length],x0,options);
The main problem I have here is not telling Matlab to change the constant but remember if it happened already during the simulation once. so Matlab should take the irreversibly changed constant rather than the one I supply at the beginning.
I would like to write a flag that is saved while the ODE is running and an if condition, "if flag exists, change constant". How to do that?
UPDATE I:
PROBLEM SOLVED
Here a first own solution, it is not polished and requires a structure file approach. Which means, the constants which should suddenly changed upon an event, must be struct files which are handed in the ODE function into the function that should be evaluated (look above for the ODE syntax). The function accepts the inputs like this:
function [OUTPUT] = f1(t, x, c)
% So here, the constants all start with c. followed by the variable name. (because they are structs instead of globals)
%% write a flag when that event happens
if c.someODEevent <= 999 && exist ('flag.txt') == 0
dlmwrite ('flag.txt',1);
end
%% next iteration will either write the flag again or not. more importantly, if it exists, the constant will change because of this.
if exist ('flag.txt') == 2
c.changingconstant = c.changingconstant/2;
end
end
Please look into Horchlers kind answer where you have to take care that such a step may introduce inaccuracies and you have to be careful to check if your code does what it is supposed to do.
To do this accurately, you should use event detection within the ODE solver. I can't give you a specific answer because you've only provided the ode15s call it in your question, but you'll need to write an events function and then specify it via odeset. Something like this:
function acidity_main
% load c data
...
x0 = ...
options = odeset('Events',#events); % add any other options too
% integrate until critical value and stop
[Time1,Results1] = ode15s(#(x,c)f1(x,c),[0 c.length],x0,options);
x0 = Results(end,:); % set new initial conditions
% pass new parameters -it's not clear how you're passing parameters
% if desired, change options to turn off events for faster integration
[Time2,Results2] = ode15s(#(x,c)f1(x,c),[0 c.length],x0,options);
% append outputs, last of 1 is same as first of 2
Time = [Time1;Time2(2:end)];
Results = [Results1;Results2(2:end,:)];
...
function y=f1(x,c)
% your integration function
...
function [value,isterminal,direction] = events(x,c)
value = ... % crossing condition, evaluates to zero at event condition
isterminal = 1; % stop integration when event detected
direction = ... % see documentation
You'll want to use the events to integrate right to the point where the "acidicity reaches a critical point" and stop the integration. Then call ode15s again with the new value and continue the integration. This may seem crude, but it how this sort of thing can be done accurately.
You can see an example of basic event detection here. Type ballode in your command window to see the code for this. You can see a slightly more complex version of this demo in my answer here. Here's an example of using events to accurately change an ODE at specified times (rather than your case of specified state values).
Note: I find it strange that you're passing what you call "constants", c, as the second argument to ode15s. This function has strict input argument requirements: the first is the independent variable (often time), and the second is the array of state variables (same as your initial condition vector). Also if f1 only takes two arguments, #(x,c)f1(x,c) is superfluous – it's sufficient to pass in #f1.
I would like to ensure that the input arguments to a user-defined MATLAB function (contained in an m-file) are of a certain type. I understand that MATLAB automatically assigns data types to variables (to the liking of some and the dismay of others), but I would like to know if there is an option of "strict data typing" in MATLAB, or something of the sort, especially for input arguments for a user-defined function.
I found a helpful explanation of MATLAB's "fundamental classes" (data types) at these two webpages:
http://www.mathworks.com/help/matlab/matlab_prog/fundamental-matlab-classes.html
http://www.mathworks.com/help/matlab/data-types_data-types.html
However, I have been unable to find an answer to the question of strict data typing, particularly for function input arguments. I thought it would be a pretty basic question that already had been answered in numerous places, but after extensive searching I have not yet found a conclusive answer. For now, I have been manually checking the data type using the is[TYPE]() functions and displaying an error message if it does not comply, though this seems sloppy and I wish I could just get MATLAB to enforce it for me.
Below is an example of a function in which I would like to specify the input argument data type. It resides in a file called strict_data_type_test.m in MATLAB's current path. In this function, I would like to force the variable yes_or_no to be of MATLAB's logical data type. I know I can use the islogical() function to manually check, but my question is if it is possible to have MATLAB enforce it for me. I also know that any non-zero double evaluates to true and a zero evaluates to false, but I want to force the user to send a logical to make sure the wrong argument was not sent in by accident, for example. Here is the example function:
function y = strict_data_type_test( x, yes_or_no )
% manual data type check can go here, but manual check is not desirable
if (yes_or_no)
y = 2 .* x;
else
y = -5 .* x;
end
end
Adding the data type before the input argument variable name (like in most programming languages) treats the data type text as another variable name instead of a data type identifier. From that it would seem that strict data typing is not possible in MATLAB by any means, but maybe one of you many gurus knows a useful trick, feature, or syntax that I have not been able to find.
validateattributes might also work for you, if there is an appropriate attribute for your case. For example if you want to enforce that yes_or_no is a logical scalar, you could try:
validateattributes(yes_or_no,{'logical'},{'scalar'})
Otherwise maybe an attribute like 'nonempty'.
I've gotten some great responses so I can't pick just one as the "accepted answer", but to summarize what I've learned from you all so far:
No, MATLAB does not have built-in strict data typing for function input arguments
MATLAB compiles the code before running, so manual validation checking should not be very taxing on performance (the profiler can be used to assess this)
Many helpful methods of doing the manual validation checking exist, listed here in order of most relevant to least relevant for what I was trying to do:
inputParser class
validateattributes()
Error/exception handling (throw(), error(), assert(), etc.)
MATLAB's built-in state detection functions (a.k.a predicate functions)
I can look through some MathWorks-provided MATLAB functions (or Statistics toolbox functions) for ideas on how to validate input arguments by typing edit followed by the function name. Two suggested functions to look at are normpdf() (from the Statistics toolbox) and integral(). Some other functions I found helpful to look at are dot() and cross().
Other thoughts:
It would appear that the inputParser class was the overall concensus on the most professional way to validate input arguments. It was noted on a related (but not duplicate) stackoverflow post that the newer MathWorks functions tend to make use of this class, suggesting that it may be the best and most up-to-date choice.
Since the MathWorks-provided MATLAB functions do not appear to enforce strict input argument data typing, this further suggests that even if it was possible to do so, it may not be a recommended approach.
MATLAB seems to regard "error handling" and "exception handling" as two different concepts. For example, here are two links to MATLAB's Documentation Center that show how MathWorks considers "error handling" and "exception handling" differently: MathWorks Documentation Center article on Error Handling, MathWorks Documentation Center article on Exception Handling. A relevant StackOverflow post has been made on this topic and can be found here (link). I contacted MathWorks and added some new information about this topic to that post, so if you are interested you may read more by following that link.
Matlab provides an 'inputParser' which allows to check inputs. Besides this you can use assertions:
assert(islogical(yes_or_no),'logical input expected')
To ensure the correct number of input arguments, use narginchk.
btw: Take a look in some Matlab functions like edit integral and check how tmw deals with this.
You may find writing this sort of code tedious or worry that it degrades performance:
if ~islogical(yes_or_no) && ~isscalar(yes_or_no)
error('test:NotLogicalType','Second argument must be logical (Boolean).');
end
if yes_or_no
y = 2 .* x;
else
y = -5 .* x;
end
Recall, however, that Matlab compiles the code before running so even if you need to test many conditions it will be quite fast. Run the profiler to see.
Another option in some cases (maybe not your example) is to use a lazier method. This option lets your code run with whatever inputs were provided, but uses a try/catch block to trap any error:
try
if yes_or_no
y = 2 .* x;
else
y = -5 .* x;
end
catch me
...
error('test:NotLogicalType','Second argument must be logical (Boolean).');
% rethrow(me);
end
The code above would produce an error if yes_or_no was a cell array for example (it will still allow non-Boolean, non-scalar, etc. values for yes_or_no though, but Matlab is often overly permissive). You can then either generate a custom error message, detect, what kind of error was thrown and try something else, etc. Many of the functions in the Statistics toolbox use this approach (e.g., type edit normpdf in your command window) for better or worse.
When using a multiple-output matlab function, do i need to callback all variables? or can I just take the first two variables? (if so..is it not recommended?)
lets say in function.m
[a, b, c] = function( )
in main.m
[var1, var2] = function;
When calling (almost) any function in matlab you can request fewer outputs than it specifies. So, yes the example you give should work perfectly fine.
There are some clever things you can do with this, such as using nargout within a function to see how many output arguments have been requested and only calculating the values that have been requested as an optimisation trick.
It depends on the definition of the function, and exactly which of the outputs you want to get.
Not all the function allow to do it, you can find all the options for each function in the beginning of the help documentation on the specific function.
If you want only the 2nd, or 3rd outputs, and you want also to save the computation-time of the results that does not interesting, you can use ~ option, like this (for versions 2009b and later):
[~, var1, var2]=function
Many functions allow for options to passed that change how the function behaves. I used/wrote various numerical solving functions a bit and one that nice amount of option, for instance is the LSMR function(s).
Otherwise, if you can manipulate the original either introduce an input(s) to do so before or at the end with an inline subroutine to generate the outputs you want.
Or if you can't it will return as either a cell array or a vector and you can pass an anonymous function to generate the desired outputs that way.
Really, can be done many ways. Very contextual.
Suppose you have a loop with 50000 iterations and want to calculate mean values (scalars) from alot of matrices. This is not complete, but roughly like this:
for k=1:50000
...
mean=sum(sum(matrix))/numel(matrix); %Arithmetic mean
...
end
And now want to include different mean equations to choose from. First I tried this:
average='arithmetic'
for k=1:50000
...
switch average
case 'arithmetic'
mean=sum(sum(matrix))/numel(matrix); %Arithmetic mean
case 'geometric'
mean=prod(prod(matrix)).^(1/numel(matrix)); %Geometric mean
case 'harmonic'
mean=numel(matrix)/sum(sum(1./matrix)); %Harmonic mean
end
...
end
This is obviously alot slower than the first loop because it needs to find the matching string for every iteration which feels really unnecessary. Then I tried this:
average='arithmetic'
switch average
case 'arithmetic'
eq=#(arg)sum(sum(arg))/numel(arg); %Arithmetic mean
case 'geometric'
eq=#(arg)prod(prod(arg)).^(1/numel(arg)); %Geometric mean
case 'harmonic'
eq=#(arg)numel(arg)/sum(sum(1./arg)); %Harmonic mean
end
for k=1:50000
...
mean=eq(matrix); %Call mean equation
...
end
This is still about twice as slow as the first loop and I don't get why. The two last loops are almost similar in speed.
Am I doing something wrong here? How can I achieve the same performance as the first loop with this extra feature?
Help is very much appreciated!
Having the switch inside the loop is performing a comparison 50000 times which only needs to be performed once, something I'd advise against.
The second is a little more subtle, but it's quite probable the eq function is being dynamically looked up every iteration and possibly interpreted each time as well (not sure how MATLAB does optimisation). Your best bet for performance is probably to put the for loop inside of the switch
switch average
case 'arithmetic'
for ... end
case 'geometric'
for ... end
case 'harmonic'
for ... end
end
Well, every function, even anonymous functions, can be expected to have some amount of extra overhead involved in calling it, making them slightly slower than their single-line expression counterparts in your example. However, in this case there may be extra overhead due to the fact that functions by the name eq already exist in abundance in MATLAB, since eq is the method name of the overloaded == operator. Using the WHICH command like so:
>> which eq -all
Will show you that eq is heavily overloaded, with one existing for each of the fundamental data types and most objects.
I would try using a different name for your anonymous function handle just to see if dispatching may be a factor, although I kinda doubt it based on the function precedence order (i.e. variables always appear to take precedence). Your best solution performance-wise may be to avoid the extra function call overhead by doing something like what DavW suggests.
I would like to make one other suggestion. Many of the mathematical operations you are doing can be greatly improved to make them more efficient, specifically by making use of the function MEAN and the colon operator to reshape an entire matrix into a column vector:
result = mean(matrix(:)); %# For the arithmetic mean
result = prod(matrix(:))^(1/numel(matrix)); %# For the geometric mean
result = 1/mean(1./matrix(:)); %# For the harmonic mean
Note that I didn't use the name mean for my variable since that is already used for the built-in function, and you definitely don't want to shadow it.
I hope I am on topic here. I'm asking here since it said on the faq page: a question concerning (among others) a software algorithm :) So here it goes:
I need to solve a system of ODEs (like $ \dot x = A(t) x$. The Matrix A may change and is given as a string in the function call (Calc_EDS_v2('Sys_EDS_a',...)
Then I'm using ode45 in a loop to find my x:
function [intervals, testing] = EDS_calc_v2(smA,options,debug)
[..]
for t=t_start:t_step:t_end)
[Te,Qe]=func_int(#intQ_2_v2,[t,t+t_step],q);
q=Qe(end,:);
[..]
end
[..]
with func_int being ode45 and #intQ_2_v2 my m-file. q is given back to the call as the starting vector. As you can see I'm just using ode45 on the intervall [t, t+t_step]. That's because my system matrix A can force ode45 to use a lot of steps, leading it to hit the AbsTol or RelTol very fast.
Now my A is something like B(t)*Q(t), so in the m-file intQ_2_v2.m I need to evaluate both B and Q at the times t.
I first done it like so: (v1 -file, so function name is different)
function q=intQ_2_v1(t,X)
[..]
B(1)=...; ... B(4)=...;
Q(1)=...; ...
than that is naturally only with the assumption that A is a 2x2 matrix. With that setup it took a basic system somewhere between 10 and 15 seconds to compute.
Instead of the above I now use the files B1.m to B4.m and Q1.m to B4.m (I know that that's not elegant, but I need to use quadgk on B later and quadgk doesn't support matrix functions.)
function q=intQ_2_v2(t,X)
[..]
global funcnameQ, funcnameB, d
for k=1:d
Q(k)=feval(str2func([funcnameQ,int2str(k)]),t);
B(k)=feval(str2func([funcnameB,int2str(k)]),t);
end
[..]
funcname (string) referring to B or Q (with added k) and d is dimension of the system.
Now I knew that it would cost me more time than the first version but I'm seeing the computing times are ten times as high! (getting 150 to 160 seconds) I do understand that opening 4 files and evaluate roughly 40 times per ode-loop is costly... and I also can't pre-evalute B and Q, since ode45 uses adaptive step sizes...
Is there a way to not use that last loop?
Mostly I'm interested in a solution to drive down the computing times. I do have a feeling that I'm missing something... but can't really put my finger on it. With that one taking nearly three minutes instead of 10 seconds I can get a coffee in between each testrun now... (plz don't tell me to get a faster computer)
(sorry for such a long question )
I'm not sure that I fully understand what you're doing here, but I can offer a few tips.
Use the profiler, it will help you understand exactly where the bottlenecks are.
Using feval is slower than using function handles directly, especially when using str2func to build the handle each time. There is also a slowdown from using the global variables (and it's a good habit to avoid these unless absolutely necessary). Each of these really adds up when using them repeatedly (as it looks like here). Store function handles to each of your mfiles in a cell array and either pass them directly to the function or use nested function for the optimization so that the cell array of handles is visible to the function being optimized. Personally, I prefer the nested method, but passing is better if you will use those mfiles elsewhere.
I expect this will get your runtime back to close to what the first method gave. Be sure to tell us if this was the problem or if you found another solution.