【问题标题】:How to make and use many fast functions in Matlab?Matlab中如何制作和使用许多快速函数?
【发布时间】:2013-12-26 15:25:39
【问题描述】:

你好地球搭便车的人,我刚刚偶然发现 Matlab 中的匿名函数有多慢。但是,我找不到方便的替代方法。我需要生成大约 12 个这样的通道,每个通道都有 8 个小功能。这是一个例子。

channels = [];
channel.name   = 'CHNAF';
channel.area   = 10;
channel.g      = 0.013;
channel.E      = 87.39;
channel.alphaa = @(V,ion) 0.9*(V+19)/(1-exp(-(V+19)/10));
channel.betaa  = @(V,ion) 36*exp(-0.055*(V + 44));
channel.infa   = @(a,b,V) a/(a+b);
channel.taua   = @(a,b,V) 1/(a+b);
channel.na     = 3;
channel.alphai = @(V,ion) 0.315*exp(-0.3*(V + 44));
channel.betai  = @(V,ion) 4.5/(1 + exp(-(V + 11)/5));
channel.infi   = @(a,b,V) a/(a+b);
channel.taui   = @(a,b,V) 1/(a+b);
channel.ni     = 1;
channels = [channels channel];

一代不是问题。但我想使用这些功能,下面的代码让它变得非常非常慢。

ch    = channels(1);
curr  = curr + ch.area*ch.g*ch.m^ch.na*ch.h^ch.ni*(V-ch.E);  
adot  = (ch.infa(ch.alphaa(V,ion),ch.betaa(V,ion),V) - ch.m)/ch.taua(ch.alphaa(V,ion),ch.betaa(V,ion),V);
idot  = (ch.infi(ch.alphai(V,ion),ch.betai(V,ion),V) - ch.h)/ch.taui(ch.alphai(V,ion),ch.betai(V,ion),V);

正如thread 中所指出的,它使用匿名函数又名fun = @(x) x; 使其如此。 我可以做些什么来让它更快?(注意我正在用这些解决 ODE,所以它们被调用了数千次)。

您可能有两个可能的顾虑。

  1. 那里确实有很多虚拟函数和变量。并不总是使用离子或 V。有时 channel.na 或 channel.ni 为零,因此无需调用任何函数。为了通用性和简单性,我需要这些。
  2. 我可以通过
    infaNEW = @(V,ion)
    ch.infa(ch.alphaa(V,ion),ch.betaa(V,ion),V)
    这样我可以减少函数的数量。

这两项增强功能都可能将性能各提高 2 倍,而不是 20 倍,因为匿名函数让我慢了下来。也许是一个更直接的问题:有没有办法将匿名函数转换为普通函数,也许会自动将它们打印到 .m 文件中?

【问题讨论】:

  • 您在那里所做的事情,包括作为struct 一部分的函数,都朝着面向对象编程的方向发展。也许您可以将您的频道定义为类,并用方法替换匿名函数?
  • @carandraug,我很乐意这样做。然而,它会增加代码的长度并引入许多难以使用的名称。正如我所说,我有 12 个通道,每个通道都有 alphaa 子功能。所以我将不得不手动编写函数 alphaaChannel1() alphaaChannel2()... 之后我将无法像现在一样循环并总结它们。
  • @A.Donda 实际上我已经开始将它们实现为类。问题是我仍然将 alphaa ... 函数作为参数传递给类,我没有将它们用作字段。 (因为这些 alphaa 函数具有不同的功能形状。)我可以为类描述之外的类生成一个字段吗?
  • 对不起,我从未在 Matlab 中使用过 OOP,我只知道它存在。我想象的是:您为每个“渠道”定义一个类。由于它们是单独定义的,因此它们包含不同版本的函数。但是由于它们都提供相同的接口,因此当您将它们传递给实现实际数值积分的函数时,它们可以互换使用。在 Java 中,要么不同的类implement 具有相同的接口,要么它们都派生自同一个抽象超类,其定义包含公共代码。
  • 顺便说一句,函数不是“字段”而是“方法”。

标签: performance matlab anonymous-function


【解决方案1】:

I have posted the same question Matlab Central. Walter Roberson 给出了很好的响应,将性能提高了一个数量级。

您可以将匿名函数转换为常规函数,是的,但开销不会有太大不同。让你慢下来的是函数调用开销,而不是函数是匿名的。

如果你有 Symbolic 工具箱,你可以传递符号 V 和 ion 进入你的公式,得到各种函数的表达式 扩大“就地”;简化()来优化它一点,然后 使用 matlabFunction() 将符号表达式转换为单个 匿名函数。

syms V ion 
curr  = ch.area*ch.g*ch.m^ch.na*ch.h^ch.ni*(V-ch.E);
adot  = (ch.infa(ch.alphaa(V,ion),ch.betaa(V,ion),V) - h.m)/ch.taua(ch.alphaa(V,ion),ch.betaa(V,ion),V);
idot  = (ch.infi(ch.alphai(V,ion),ch.betai(V,ion),V) - ch.h)/ch.taui(ch.alphai(V,ion),ch.betai(V,ion),V);
triple = [curr,adot,idot];
triplefcn = matlabFunction(simplify(triple), 'vars', [V, ion]);

现在调用 Triplefcn 传入实际的 V 和 ion 将 返回一个以 curr、adot、idot 为列的数组。 (这将是 也是矢量化的,而您当前的表达式不是。)

【讨论】:

  • 我不知道您是否仍将triplefcn 存储在struct 中,但不这样做也会使它更快一点。重复访问结构字段也会有成本。做这种事情的唯一更快的方法是使用矩阵/向量数学将你的 12 个函数写成一个大函数。
  • 我尝试在没有结构的情况下执行此操作,但使用句柄单元阵列,它没有任何明显的区别。但是,我做了大 MAMA 函数,它将所有参数作为向量并吐出大向量。 matlabFunction(fun,'file','myFile') 会为您自动生成文件。它的工作速度是原来的两倍。
猜你喜欢
  • 2018-02-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多