在Julia中区分两个具有相同形式的结构体的最佳方法是什么?

huangapple go评论52阅读模式
英文:

What is the best way to distingish between two structures with the same form in Julia?

问题

Here's the translated code portion:

所以我有面向对象编程的背景,所以下面的问题似乎非常简单。

class Hermitian:
  def __init__(self, mat::np.ndarray):  
    self.mat::np.ndarray = mat

class Hamiltonian(Hermitian):
  ...

class Correlation(Hermitian):
  ...

对于了解一些物理学的人来说,哈密顿量和相关函数都可以用矩阵形式表示,但在我的上下文中,它们只是一个矩阵,因此它们可以是Hermitian的子类。

我之所以要将它们分开,是因为有一些子例程必须对每个对象进行不同的处理。

例如,计算特征值的操作,它们可以共享为Hermitian定义的操作,但对于像仅针对Correlation的特定解缠缠积的情况,那么在Python中,我可以编写def ee(corr::Correlation)来标记这仅适用于Correlation,或者使用isinstance方法进行显式断言。

然而,在Julia中,没有从抽象结构体继承的概念,我必须明确定义这两个结构体。

struct Hamiltonian
  mat::Matrix{Complex}
end

struct Correlation
  mat::Matrix{Complex}
end

这是真实的,现在我可以仅为特定类型定义函数,但共享的方法现在不可能存在,或者要为这些类型重载方法。

有人能提出一种构建这种问题的事实上的方法吗?

*我不想在通用结构Hermitian内部放置一个specifier::Symbol来标记对象类型,如下所示:

struct Hermitian
  specifier::Symbol
  mat::Matrix
end

hamiltonian::Hermitian = Hermitian(:hamiltonian, ...)
英文:

So I am from OOP background, so the following problem seems very easy.

class Hermitian:
  def __init__(self, mat::np.ndarray):  
    self.mat::np.ndarray = mat

class Hamiltonian(Hermitian):
  ...

class Correlation(Hermitian):
  ...

So for people who knows a bit Physics Hamiltonian and Correlation function can both be expressed in matrix form, but since they really are just a matrix in my context, so they can be a subclass of a Hermitian.

The reason I want to partition them is because they are some subroutines that have to handle differently for each of these objects.

Such as the operation to compute the eigenvalues, they can share the operation defined for Hermitian, but for something else like resolving for entanglement entropy which is specific only for Correlation, then in Python I can write def ee(corr::Correlation) to label that this is for Correlation only, or explicitly assert with the isinstance method.

Yet in Julia, there are no such thing as inheriting from a abstract struct, I have to define the two structures explicitly.

struct Hamiltonian
  mat::Matrix{Complex}
end

struct Correlation
  mat::Matrix{Complex}
end

Which is true that now I can define functions only for a specific type, but the shared methods are now impossible or to overload the method for each of these types.

Can someone suggest a defacto way to structure this kind of problem?

*I don't want to put a specifier::Symbol within a general struct Hermitian to label the type of the object like:

struct Hermitian
  specifier::Symbol
  mat::Matrix
end

hamiltonian::Hermitian = Hermitian(:hamiltonian, ...)

答案1

得分: 1

这个问题的代码部分已经翻译完成,如果您有任何其他问题或需要进一步解释,请随时提出。

英文:

This could be handled in several different ways, but the one that is probably closest to what you want is:

julia> abstract type Hermitian end

julia> struct Hamiltonian{T} <: Hermitian
           mat::Matrix{Complex{T}}
       end

julia> struct Correlation{T} <: Hermitian
           mat::Matrix{Complex{T}}
       end

julia> getmat(::Hermitian) = error("getmat must be defined by concrete subtypes")
getmat (generic function with 1 method)

julia> getmat(x::Hamiltonian) = x.mat
getmat (generic function with 2 methods)

julia> getmat(x::Correlation) = x.mat
getmat (generic function with 3 methods)

julia> matsum(x::Hermitian) = sum(getmat(x)) # function common for all subtypes
matsum (generic function with 1 method)

julia> ee(corr::Correlation) = "defined only for Correlation"
ee (generic function with 1 method)

Things to note:

  1. Abstract type does not have fields. They can be only defined for concrete types.
  2. However, you can dispatch on abstract type, as in matsum definition.
  3. The way I typically want to handle such things is to define a getter for a field, like getmat in our case. Note that this has an additional benefit that in general Hamiltonian and Correlation do not have to share mat as their field. This matrix e.g. could be computed on the flight in one case, and stored in a struct in other case. Defining such getter allows for a level of abstraction that might be handy (i.e. not all subtypes of Hermitian might want to store mat matrix in general)
  4. A small thing is that Matrix{Complex} is not a concrete type as Complex can be complex of e.g. floats, or integers. Therefore, if you want performance it is usually better to make the type parametric. I used T as a parameter. In this way your code will be type stable.
  5. When you use the pattern I described above, what is crucial is that you define the interface methods required to be defined by Hermitian abstract type subtypes (and make sure that such subtypes define this interface; in my example the interface requires that the getmat function is defined).

If something is not clear please comment and I can expand on this.

huangapple
  • 本文由 发表于 2023年5月7日 16:04:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/76192810.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定