jfeist / QuantumAlgebra.jl

Quantum operator algebra in Julia
MIT License
60 stars 10 forks source link

Define multiple fermion operators #9

Closed longisland-icetea closed 3 years ago

longisland-icetea commented 3 years ago

Here I use this code to define two different fermion operators

@fermion_ops c
@fermion_ops d

and it's expected comm(cdag(),d()) to be 2cdag()d().

However I got 0 here. This might make some non-Hermitian problem.

I know use comm(fdag(1),f(2)) will give the right answer, but it makes the result become hard to comprehend.

Thank you if you can fix this.

jfeist commented 3 years ago

Hi, in principle, the current behavior is by design, as @fermion_ops x defines a new fermionic "species", i.e., type of (quasi)particle. Operators belonging to different species (e.g., electrons and a fermionic nucleus) should then commute.

Do I understand correctly that in your case, c and d should represent two specific (distinct) states for the same fermionic species? In the current design, that's exactly what indices are for, where symbolic indices are always "variables" that could represent any state, while integer ones represent specific states. So, as you mentioned correctly, integer indices behave like you want:

julia> using QuantumAlgebra
julia> QuantumAlgebra.auto_normal_form()

julia> comm(fdag(:c),f(:d))
-δ(cd) + 2 f†(c) f(d)

julia> comm(fdag(1),f(2))
2 f†(1) f(2)

If it is only about convenience in typing, you could do, e.g.,

julia> c(args...) = f(1,args...);
julia> cdag(args...) = fdag(1,args...);
julia> d(args...) = f(2,args...);
julia> ddag(args...) = fdag(2,args...);

julia> comm(cdag(),d())
2 f†(1) f(2)

but the resulting output might admittedly be somewhat confusing. If you use the (text or LaTeX) output programmatically, it should be relatively easy to simply replace f(1) -> c and f(2) -> d in the end.

I would prefer to keep the possibility to have different unrelated (=commuting) fermionic species, so I don't think i'll merge the change you proposed, but maybe something could be added to better support what you're looking for. I have a few ideas, let me know what you think. 1) Symbolic but "definite" indices where δ(cd) = 0. Not sure about a good interface to indicate this, let's say a ! after the index name: This would give comm(fdag(:c!),f(:d!)) = 2 f†(c) f(d) (not sure if the output should/would also indicate this). That's still not as clean output as 2 c†() d(), but at least the symbols are there. 2) Something like aliases where c and d are defined as alternative names for, e.g., f(1) and f(2), and also used in the output. This could look like

julia> @alias c f(1)
julia> @alias d f(2)
julia> comm(cdag(),d())
2 c†() d()

The risk is that it could be confusing if f is also used separately, because you would have, e.g.,

julia> comm(cdag(),f(:j))
-δ(1j) + 2 c†() f(j)

but that's probably manageable, and you could always define a new species that you are unlikely to use by mistake somewhere else, e.g.,

julia> @fermion_ops glorbax
julia> @alias c glorbax(1)
julia> @alias d glorbax(2)
julia> comm(cdag(),d())
2 c†() d()
longisland-icetea commented 3 years ago

Hi,

I know what you mean now.

I need this kind of notation based on some condensed matter calculation, such as RKKY model. Here we have Itinerant electron and localized electron, which are in completely different states. In this situation, they are all anti-commute. Thus we can use different notation to simplify the calculation and prettify the display.

julia> @fermion_ops glorbax
julia> @alias c glorbax(1)
julia> @alias d glorbax(2)
julia> comm(cdag(),d())
2 c†() d()

Your suggestion of using @alias seems suitable for this condition. In fact, maybe pre-defined fermion f and boson a is not that necessary in this package?

jfeist commented 3 years ago

Hi, I had a quick stab at this and realized that a "general" @alias command would be very brittle, and that in any case, this only seems to be relevant to fermionic operators (since different boson operators commute no matter whether they refer to different species or different types of states). So I made a new macro @anticommuting_fermion_group that allows to define a group of fermionic operators that behave exactly as you want (the implementation uses something like the alias concept, but for the external interface, that doesn't really matter). The interface is much cleaner like this, you can use indices for the operators without problems, and you do not have to make up a "fake" fermion operator name like glorbax yourself:

julia> using QuantumAlgebra; QuantumAlgebra.auto_normal_form()
julia> @anticommuting_fermion_group c d
julia> comm(cdag(),d())
2 c†() d()

julia> d(:i)*c(:k)
-c(k) d(i)

BTW, as a small curiosity, the operators within a group are ordered by definition order, not alphabetically as normally:

julia> @anticommuting_fermion_group y x
julia> x()*y()
-y() x()

For now, this feature is available in the branch aliases, install with ]add QuantumAlgebra#aliases. I've opened a pull request (#11), and will merge that (and probably make a new release soonish) once I've added some documentation and done a bit more testing. If you try this out, let me know how it goes and if you notice any problems.

longisland-icetea commented 3 years ago

It works well here. Thank you very much.

jfeist commented 3 years ago

This is now included in the latest release (v1.1.0), so you can again use the released version (and I'll delete the branch aliases soon).