What is the best way to pass lots of constants and

2019-07-19 00:18发布

问题:

Calling globals requires a ridiculous amount of time to load compared to not using them at all:

Consider a loop with 1000 iterations doing some calculation with those variables: 0,6 sec no globals (~1000 variables), 2,2 sec one defined global variable (and the other variables), 6 sec ~1000 globals (and the other variables). So you see DEFINING already one global is the step which slows down iterations in a function that uses globals considerably, in contrast to not using them in the first place.

My current challenge is the fsolve function which calls another function and seemingly requires global variables. And this is a big problem for me. I read you can pass variables differently to the function, for instance by using struct but this struct would have to be "unpacked" inside my iterations, slowing down iterations again.

Now my question: I dont want to use globals. How can I circumvent them in fsolve? My idea is to load them before entering the loop. Please tell me there is something I can do here.

Thank you for reading, please help!

UPDATE I:

   % load workspacevars.mat % I'm loading some variables that are going to be used.

one_of_the_variables_that_is_imported = 1;

for loop=1:1000
x(loop,:)=linspace(rand(),1,13); % x is going to change all the time, so I simulate this here
x1=x(loop,1); % 
x2=x(loop,2); % 
x13=x(loop,13); % shortened so you get the general idea.

result_1 = x1 * one_of_the_variables_that_is_imported
result_2 = x2 * one_of_the_variables_that_is_imported
result_13 = x13 * one_of_the_variables_that_is_imported

end

So again, I wish to use nor globals nor load workspace to pass the variables, how would that work out?

UPDATE II:

Upon request, here is a very, very close example to my actual problem (please dont be intimidated by the length or display, the code works but is just not overly efficient). Again, please focus on the main problem that I have ~1000 constants that I have to call from a .m workspace file or with globals and dont wish to do that.

**Minor modification: I find pastebin more useful for this purpose: http://pastebin.com/6e1K90fR

UPDATE III:

big thanks to @SCFrench!

I think I just figured it out myself how horribly long globals take compared to structs! Let me share this funny story with you:

Working in the script of the function took terribly long, I couldnt figure out why (it had some strange lag!). Until I started editing the variables to become structure - I deleted all globals definitions and poof! everything light-blue disappeared and I have no more lags in editing the code!!! I cant believe this!

So my plan is now to ctrl+H every single variable I have and replace it with c.Var. Its around 1000 Var so I better ask one last time before starting this tedious task. It will work afterwards I hope. Your example was very good, and the more often I read it the more I get. Could you maybe explain one last time how the variable constants is passed into a lambda and passed to myfun? I fear I dont know the term lambda in this context and would like to understand you better. I cant comment on your comment so sorry for this lengthy update and many thanks in advance!

UPDATE IV:

The code without globals works DARN WELL !!!!!! many thanks to everybody, this is fantastic. I reduced the total time it took from ridiculous 20 sec per iteration to less than one sec. that a 95% increase in efficiency!!!

Even though I am jumping of joy, there is one thing that needs to be adjusted: one of my results in fsolve is iterated successfully, thats ok. but I included a further calculation in f2 (the function to be fsolved) that doesnt need to be fsolved but I still want the output of it in my f1 that calls fsolve. Now my code reads

[x,fval,exitflag,output,jacobian] = fsolve(@(x) f2(x, c), x0, options);

although Id rather have

[x,y,fval,exitflag,output,jacobian] = fsolve(@(x) f2(x, c), x0, options);

but I get too many output parameters as error when I attempt that. So I had to reort to desperate measures and call global y again so both functions know y. How else would you do that since I now know how horrible globals are?

回答1:

Here is a simplified example of how I would go about solving this:

function y = example

% a1 = -2; a2 = -1; save('example_constants.mat')

constants = load('example_constants.mat');

y = fsolve(@(x) myfun(x, constants), [-5;-5]);

end

function F = myfun(x, c)
F = [ 2 * x(1) - x(2) - exp(c.a1 * x(1))
      -x(1) + 2 * x(2) - exp(c.a2 * x(2))];
end

This uses two features of MATLAB. First, if you request an output from load, it stores all the loaded variables as fields of a structure and returns the structure as its output. After the call to load, you refer to each constant in the MAT-file by using expressions like constants.a1 (constants because that is the name of the variable assigned the output of load, and a1 because that is the name of the variable that had been stored in example_constants.mat). The other feature this uses are anonymous functions, to capture the value of the constants structure into a lambda and pass it to myfun as the second input (c) on each iteration.

(Your question mentions the overhead of "unpacking" structure arrays. Such unpacking costs, if they are even noticeable, will be far, far less than the cost of either global variables or a load statement executed each time the objective function is called.)

This is assuming you don't need your objective function to update the values of the constants (in which case, they aren't really constants, and your "load w.mat" variant wouldn't work). If you do need that, you should look at a similar technique using nested functions. Both of these techniques are discussed further here.