在Julia中使用抽象类型字段或具体类型的Union构造?

时间:2019-10-24 09:14:52

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

我有两种具体的类型,分别称为CreationOperatorAnnihilationOperator,我想定义一个新的具体类型,该类型代表一串运算符和一个将其相乘的实系数。

我很自然地定义了一个抽象类型FermionicOperatorCreationOperatorAnnihilationOperator都从中继承,即

abstract type FermionicOperator end

struct CreationOperator <: FermionicOperator
  ...
end

struct AnnihilationOperator <: FermionicOperator
  ...
end

因为我可以定义许多类型为function(op1::FermionicOperator, op2::FermionicOperator) = ...的签名的函数,例如算术运算(我正在构建代数系统,所以我必须定义诸如*,{{1} }等)。
然后我继续定义一个具体的类型+

OperatorString

但是,根据Julia手册,我认为struct OperatorString coef::Float64 ops::Vector{FermionicOperator} end 对于性能不是理想的,因为编译器对OperatorString一无所知,因此涉及FermionicOperator的函数将效率低下(并且我将有许多函数可操作运算符的字符串)。

我找到了以下解决方案,但是我不确定其含义以及它是否真的有所帮助。
我没有将OperatorString定义为抽象类型,而是将其定义为FermionicOperatorUnion的{​​{1}},即

CreationOperator

这仍然允许使用AnnihilationOperator形式的函数,但是据我了解,同时struct CreationOperator ... end struct AnnihilationOperator ... end FermionicOperator = Union{CreationOperator,AnnihilationOperator} 是一种具体类型,因此function(op1::FermionicOperator, op2::FermionicOperator) = ...的定义很明确,在这种情况下,编译器可以优化事情。

我尤其感到怀疑,因为我也考虑过使用内置的Union{CreationOperator,AnnihilationOperator}结构来定义我的运算符字符串(实际上会更通用),其字段OperatorString是一个向量抽象类型的元素:非常类似于我的第一次设计尝试。但是,在Expr上执行算术运算时,我感到自己做错了事,最好定义自己的类型。

1 个答案:

答案 0 :(得分:0)

如果您的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的混合,那么您可以使用联合。因为联合很小(两种类型),所以您的代码将保持高性能。

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方法,您也可能希望使用抽象类型-只是为了将来函数分配中的简化和灵活性。这对开发鲁棒的多调度驱动逻辑很有帮助。