确保MATLAB不重新计算符号表达式 [英] Make sure MATLAB does not recalculate symbolic expression

查看:135
本文介绍了确保MATLAB不重新计算符号表达式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在构建(我的第一个……)MatLab程序,它需要象征性地微分方程,然后多次使用此解决方案(具有不同的数字输入).

I am building (my first...) MatLab program, it needs to differentiate an equations symbolically and then use this solution many many times (with different numeric inputs).

我不希望它每次需要输入一组新的数值时都重新计算符号微分.这可能会大大增加运行该程序所花费的时间(鉴于其性质,一个数字优化器,可能已经是数小时).

I do not want it to recalculate the symbolic differentiation every time it needs to put in a new set of numeric values. This would probably greatly add to the time taken to run this program (which - given its nature, a numeric optimiser, will probably already be hours).

我的问题是如何构造程序,使其不会重新计算符号差异?

有问题的课程是:

function [ result ] = GradOmega(numX, numY, numZ, numMu)
syms x y z mu
omega = 0.5*(x^2+y^2+z^2) + (1-mu)/((x+mu)^2+y^2+z^2)^0.5 + mu/((x+mu-1)^2+y^2+z^2)^0.5;
symGradient = gradient(omega);
%//Substitute the given numeric values back into the funtion
result = subs(symGradient, {x,y,z,mu}, {numX, numY, numZ, numMu});
end

我知道我可以象征性地计算导数,然后将其复制粘贴到代码中,例如

I know that I could just symbolically calculate the derivative and then copy-paste it into the code e.g.

gradX = x + ((2*mu + 2*x)*(mu - 1))/(2*((mu + x)^2 + y^2 + z^2)^(3/2)) - (mu*(2*mu + 2*x - 2))/(2*((mu + x - 1)^2 + y^2 + z^2)^(3/2));
gradY = y - (mu*y)/((mu + x - 1)^2 + y^2 + z^2)^(3/2) + (y*(mu - 1))/((mu + x)^2 + y^2 + z^2)^(3/2);
gradZ = z - (mu*z)/((mu + x - 1)^2 + y^2 + z^2)^(3/2) + (z*(mu - 1))/((mu + x)^2 + y^2 + z^2)^(3/2);

但是然后我的代码有点神秘,这在共享项目中是个问题. 这里有一个相关的查询:

But then my code is a bit cryptic, which is a problem in a shared project. There is a related query here: http://uk.mathworks.com/matlabcentral/answers/53542-oop-how-to-avoid-recalculation-on-dependent-properties-i-hope-a-mathwork-developer-could-give-me-a But I'm afraid I couldn't follow the code. Also I am much more familiar with Java and Python, if that helps explain anything.

推荐答案

您可以将函数包装到某种Function-Factory中,该函数工厂不返回数值结果,但是可以求值:

You could wrap your function into some kind of Function-Factory, which does not return numerical results, but a function that can be evaluated:

(我不得不用sym('mu')替换调用syms,因为由于某种原因它一直在行omega = ...中调用mutools函数.我也确实将调用更改为gradient以确保参数的顺序正确,并且mu将被视为常量.)

(I had to replace the call syms with sym('mu'), because for some reason it kept calling a mutools function in line omega = .... I did also change the call to gradient to make sure the arguments are in correct order, and mu will be treated as constant.)

function GradOmega = GradOmegaFactory()
x = sym('x');
y = sym('y');
z = sym('z');
mu = sym('mu');
omega = 0.5*(x^2+y^2+z^2) + (1-mu)/((x+mu)^2+y^2+z^2)^0.5 + mu/((x+mu-1)^2+y^2+z^2)^0.5;
symGradient = gradient(omega,{'x','y','z'});
GradOmega = matlabFunction(symGradient, 'vars', {'x','y','z','mu'});
end

然后您将通过以下方式调用它:

Then you would call it via:

GradOmega = GradOmegaFactory();
result1 = GradOmega(numX1, numY1, numZ1, numMu1);
result2 = GradOmega(numX2, numY2, numZ2, numMu2);
result3 = GradOmega(numX3, numY3, numZ3, numMu3);
...

更好:

您甚至可以更喜欢使用包装函数GradOmega,该函数在内部构建此类函数并使之成为persistent,以获得与您最初使用的方法相同的接口.第一次调用函数GradOmega时,会评估符号表达式,但是在每次连续调用中,您只需要评估生成的函数句柄,这意味着它应该几乎与您对其进行硬编码一样快.

Even better:

You could go even more fancy and use a wrapper function GradOmega which builds such a function inside and makes it persistent, to get the same interface you had with your initial approach. The first time you call the function GradOmega the symbolic expression is evaluated, but on each consecutive call you will only have to evaluate the generated function handle, which means it should be nearly as fast as if you hard-coded it.

function result = GradOmega(numX, numY, numZ, numMu)
persistent numericalGradOmega;
if isempty(numericalGradOmega)
    numericalGradOmega = GradOmegaFactory();
end
result = numericalGradOmega(numX, numY, numZ, numMu);
end

像使用原始版本一样使用

Use this like you would use your original version

result = GradOmega(numX, numY, numZ, numMu);

只需将两个函数复制并粘贴到单个GradOmega.m文件中. (GradOmega应该是文件中的第一个函数.)

Just copy and paste both functions into a single GradOmega.m file. (GradOmega should be the first function in the file.)

另一个提示:您甚至可以使用向量来评估此功能.不用事后再调用GradOmega(1,2,3,4)GradOmega(5,6,7,8),您可以使用行向量通过调用GradOmega([1,5], [2,6], [3,7], [4,8])节省时间开销.

Another tip: You can even evaluate this function using vectors. Instead of calling GradOmega(1,2,3,4) and GradOmega(5,6,7,8) afterwards, you can save the time overhead via the call GradOmega([1,5], [2,6], [3,7], [4,8]) using row vectors.

另一个提示:要进一步清理代码,您还可以将第一行放入单独的symOmega.m文件中.

Yet another tip: To clean up your code even more, you could also put the first lines into a separate symOmega.m file.

function omega = symOmega()
x = sym('x');
y = sym('y');
z = sym('z');
mu = sym('mu');
omega = 0.5*(x^2+y^2+z^2) + (1-mu)/((x+mu)^2+y^2+z^2)^0.5 + mu/((x+mu-1)^2+y^2+z^2)^0.5;

这样,您不必在使用它的每个文件中都拥有此符号表达式的副本.如果您还想评估Omega本身,这可能会很有用,因为您可以使用此答案中列出的相同工厂方法.您将得到以下文件:symOmega.mOmega.mGradOmega.m,其中只有文件symOmega.m具有实际的数学公式,而其他两个文件都使用symOmega.m.

This way you don't have to have a copy of this symbolic expression in every file you use it. This can be beneficial if you also want to evaluate Omega itself, as you then can make use of the same Factory-approach listed in this answer. You would end up with the following files: symOmega.m, Omega.m and GradOmega.m, where only the file symOmega.m has the actual mathematical formula and the other two files make use of symOmega.m.

这篇关于确保MATLAB不重新计算符号表达式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆