【问题标题】:Function accepting ndarray and float at the same time同时接受ndarray和float的函数
【发布时间】:2020-12-24 16:50:22
【问题描述】:

我想写一个函数来计算某种材料的折射率作为波长的函数。我对数组使用ndarray crate,类似于 Python 中的 numpy。 目前该功能的实现方式如下:

fn calc_refractive_index(l: &Array1<f64>) -> Array1<f64> {
    fn refractive_index(&self, l: &Array1<f64>) -> Array1<f64> {
        let V =
            self.A[0] + self.A[1] / (1. + self.A[2] * (self.A[3] * l / self.pitch).mapv(f64::exp));
        let W =
            self.B[0] + self.B[1] / (1. + self.B[2] * (self.B[3] * l / self.pitch).mapv(f64::exp));
        (self.material.refractive_index(&l).powi(2)
            - 3. * l.powi(2) / 4. / (consts::PI * self.pitch).powi(2) * (V.powi(2) - W.powi(2)))
            .mapv(f64::sqrt)
    }
}

实现了以下特征,以缩短增强时间:

trait Squared<T> {
    fn powi(&self, e: i32) -> T;
}

impl Squared<Array1<f64>> for Array1<f64> {
    fn powi(&self, e: i32) -> Array1<f64> {
        self.mapv(|a| a.powi(e))
    }
}

但是,我可能还想只计算一个特定波长的折射率,所以我也想接受 float64 值。在不实现两个单独的功能的情况下,实现这一点的最佳方法是什么?

编辑: 该函数使用 ndarray 的语法进行平方:l.mapv(|x| x.powi(2)),不幸的是,这与 float64 不同

编辑 2: 按照要求,我包含了函数体。

【问题讨论】:

  • 您能否更新您的答案以显示该函数的两个版本的实现?此外,单个函数处理这两种情况是否是一项硬性要求,或者您只是想看看这是否可能?
  • @pretzelhammer:我的问题现在包括函数体。单个函数处理这两种情况并不是硬性要求,只是好奇,因为我正试图更熟悉 rust,看看有什么可能。

标签: arrays generics rust


【解决方案1】:

这绝对是可能的,尽管它可能比简单地添加另一个功能需要更多的工作。您需要首先定义两个辅助特征,为f64Array1&lt;f64&gt; 指定mapvpowi(很像Squared)操作:

trait PowI {
    fn powi(&self, e: i32) -> Self;
}

impl PowI for f64 {
    fn powi(&self, e: i32) -> Self {
        f64::powi(*self, e)
    }
}

impl PowI for Array1<f64> {
    fn powi(&self, e: i32) -> Self {
        self.mapv(|a| a.powi(e))
    }
}

trait MapV {
    fn mapv(&self, f: impl FnMut(f64) -> f64) -> Self;
}

impl MapV for f64 {
    fn mapv(&self, mut f: impl FnMut(f64) -> f64) -> Self {
        f(*self)
    }
}

impl MapV for Array1<f64> {
    fn mapv(&self, f: impl FnMut(f64) -> f64) -> Self {
        Array1::mapv(self, f)
    }
}

然后,您可以使您的折射率计算函数对实现这两个特征的类型T 通用(即T: PowI + MapV)。

请注意,您还需要在 T 上指定附加边界,以指定它可以与 Ts 和 f64s 相加、除法和相乘(我假设这是 self.pitch 的类型和元素在self.Aself.B 数组中)。您可以通过要求 T&amp;'a T 甚至 f64 实现适当的 AddMulDiv 特征来做到这一点。例如,您的实现可能需要f64: Mul&lt;&amp;'a T, Output=T&gt;T: Div&lt;f64, Output=T&gt; 以及许多其他边界。编译器错误将帮助您准确确定需要哪些错误。

【讨论】:

  • 虽然这可能会解决我的问题,但我注意到使用实现的特征而不是直接使用 .mapv(|x| x.powi(e)) 导致执行时间增加了近 30%,所以我现在暂时放弃了这个想法
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-11-28
  • 2018-10-18
  • 2012-01-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多