【问题标题】:Struct with abstract-type field or with concrete-type Union in Julia?在 Julia 中使用抽象类型字段还是使用具体类型 Union 的结构?
【发布时间】:2019-10-24 09:14:52
【问题描述】:

我有两个具体类型,分别称为 CreationOperatorAnnihilationOperator,我想定义一个新的具体类型,它表示一串运算符和一个乘以它的实系数。

我发现定义一个抽象类型 FermionicOperator 是很自然的,CreationOperatorAnnihilationOperator 都从该类型继承,即

abstract type FermionicOperator end

struct CreationOperator <: FermionicOperator
  ...
end

struct AnnihilationOperator <: FermionicOperator
  ...
end

因为我可以定义很多带有function(op1::FermionicOperator, op2::FermionicOperator) = ...类型签名的函数,比如算术运算(我正在构建一个代数系统,所以我必须在运营商)。
然后我会继续定义一个具体类型OperatorString

struct OperatorString
  coef::Float64
  ops::Vector{FermionicOperator}
end

但是,根据 Julia 手册,我认为 OperatorString 对性能来说并不理想,因为编译器对 FermionicOperator 一无所知,因此涉及 OperatorString 的函数将是低效的(我会有很多操作字符串的函数)。

我找到了以下解决方案,但我不确定它的含义以及它是否真的有所作为。
我没有将FermionicOperator定义为抽象类型,而是将其定义为CreationOperatorAnnihilationOperatorUnion,即

struct CreationOperator
  ...
end

struct AnnihilationOperator
  ...
end

FermionicOperator = Union{CreationOperator,AnnihilationOperator}

这仍然允许function(op1::FermionicOperator, op2::FermionicOperator) = ... 形式的函数,但同时,据我了解,Union{CreationOperator,AnnihilationOperator} 是一个具体类型,因此OperatorString 是明确定义的,编译器可以优化事情,如果它是案例。

我特别怀疑,因为我还考虑使用内置的Expr 结构来定义我的运算符字符串(实际上它会更通用),其字段args 是具有抽象类型元素的向量: 与我的第一次设计尝试非常相似。然而,在Expr 上实现算术运算时,我感觉自己做错了什么,最好定义自己的类型。

【问题讨论】:

  • > Union{CreationOperator,AnnihilationOperator} 是一个具体类型。很不幸的是,不行。您可以使用isconcretetype 进行检查。我认为julialang.org/blog/2018/08/union-splitting 会在一定程度上帮助你。
  • 确实联合拆分是我认为编译器能够对联合进行的操作。实际上,如果它们不是具体类型的,只要可以优化结果函数,我并不在意。

标签: performance struct julia union-types abstract-type


【解决方案1】:

如果您的 ops 字段是一个向量,在任何给定实例中,要么全是 CreationOperators 要么全是 AnnihilationOperators,那么推荐的解决方案是使用参数化结构。

abstract type FermionicOperator end

struct CreationOperator <: FermionicOperator
    ...
end

struct AnnihilationOperator <: FermionicOperator
    ...
end

struct OperatorString{T<:FermionicOperator}
  coef::Float64
  ops::Vector{T}

  function OperatorString(coef::Float64, ops::Vector{T}) where {T<:FermionicOperator}
      return new{T}(coef, ops)
  end
end

如果您的ops 字段是一个向量,在任何给定情况下,它可能是CreationOperatorsAnnihilationOperators 的混合,那么您可以使用联合。因为联合体很小(2 种类型),所以您的代码将保持高性能。

struct CreationOperator
    value::Int
end

struct AnnihilationOperator
    value::Int
end

const Fermionic = Union{CreationOperator, AnnihilationOperator}

struct OperatorString
  coef::Float64
  ops::Vector{Fermionic}

  function OperatorString(coef::Float64, ops::Vector{Fermionic})
      return new(coef, ops)
  end
end

尽管没有显示,即使使用Union 方法,您也可能希望使用抽象类型——只是为了将来函数调度的简单性和灵活性。它有助于开发健壮的多调度驱动逻辑。

【讨论】:

  • 是第二种情况。你是什​​么意思也使用抽象类型?要在方法签名中使用 const Operator = Union{CreationOperator, AnnihilationOperator}' as well as abstract 类型 FermionicOperator end` 以进行调度?
  • 是的。这正是我的意思。
猜你喜欢
  • 1970-01-01
  • 2016-06-13
  • 2019-02-05
  • 2014-05-22
  • 2017-09-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-13
相关资源
最近更新 更多