JuliaAttic / QuBase.jl

A foundational library for quantum mechanics in Julia
Other
43 stars 6 forks source link

Types/labels indicating quantum pictures #8

Open i2000s opened 9 years ago

i2000s commented 9 years ago

As discussed in #7, we may want to define types/labels to denote quantum pictures of the workspace. Transformation of propagators and states between different pictures may be also helpful.

jrevels commented 9 years ago

Hmmm. We're talking about the same types of quantum objects no matter which picture we're in - what changes is those objects' dynamical behavior with respect to each other. In that sense, I'm not sure that a picture is a "property" of any quantum object, but rather a specification on how we define that object's dynamic relationship to other objects.

Perhaps the solution, then, is to namespace picture-specific functions by putting them in submodules; then you could define Schrodinger.schrodinger_version_of_an_evolution(state::QuVector) and Heisenburg.heisenburg_version_of_an_evolution(operator::QuMatrix).

The above is a pretty silly example, since if that's all we were going to do we could just utilize multiple dispatch to have an_evolution(state::QuVector), and an_evolution(operator::QuMatrix)...what is the use case for disambiguating the "picture" to which special constructors and evolution functions belong that can't already be done through multiple dispatch?

(Note: when I say quantum object, I mean states and operators.)

i2000s commented 9 years ago

The idea of tagging pictures makes sense only when we have propagator or evolution operator defined in a quantum dynamics calculation. We can consider the following scenario that a user defines the Hamiltonian with a Schrodinger picture tag, then the evolutionary operator or the propagator as a function of a given time list can be generated, then he can define all the other quantum operators he needs in the Schrodinger picture simply and clearly without involving any time-dependent parts. After that, he wants to calculate the time evolution of the expectation value of the particle number operator in the Heisenberg picture, and hence he can just switch the picture label and plug the initial state, the propagator and the number operator into an equation of motion solver and retrieve the result in the Heisenberg picture. Now he wants to calculate how the state of the system evolve in the Interaction picture. He can just point out to the computer the propagator and the bare Hamiltonian for the system, and switch the workspace to be Interaction picture, the transformation relationship between Heisenberg and Interaction picture is uniquely defined by the QuBase.jl he is using. When he inserts the input operators and states into some dynamics solver, he just use the operators and states that have been defined initially in the Schrodinger picture and the output objects will be automatically aligned to the Interaction picture as he wants. In the last step, the solver just recall QuBase.jl to do the switching work. In this way, users of the programs do not need to redefine operators and states separately when switching representations as a result of tagging picture labels to the workspace. Do you guys think this is useful and implementable?

It hasn't been clear to me how should we easily implement this feature. The label may not necessarily be a global variable, it could be just attached to particular quantum objects. But here are the things in my mind we need to work out for the minimum of work/requirements:

acroy commented 9 years ago

Like you both said, the different pictures only make sense if you have information about the time evolution. A quantum object given by a QuArray doesn't know about this. My ad hoc idea would be to have types, which contain a state or an operator (a QuArray) and a propagator. Additionally, we would need (a) time label(s). Roughly,

type HeisenbergPic{QA,P}
    qa::QA
    p::P
    t::Real
end

Then you could for instance define multiplication, such that HeisenbergPic(a,p,t)*HeisenbergPic(b,p,t)=HeisenbergPic(a*b,p,t) and so on. A function evaluate could return the QuArray representing the operator at time t. The advantage of having "Picture" types would be that we can possibly reduce the number of propagations, which are costly.

jrevels commented 9 years ago

What about the following?

abstract Picture
abstract Heisenberg <: Picture
abstract Schrodinger <: Picture

type PicturedObj{P<:Picture, PR, Q}
    prop::PR
    obj::Q
end

PicturedObj{P<:Picture,Q,PR}(::Type{P}, prop::PR, obj::Q) = PicturedObj{P,Q,PR}(obj, prop)
# default to Heisenberg picture; this might make more sense as
# an actual default arg but I wanted the argument order to match the
# type parameter order
PicturedObj(prop, obj) = PicturedObj(Heisenberg, obj, prop) 

typealias HeisenbergPic{Q, PR} PicturedObj{Heisenburg, Q, PR}
typealias SchrodingerPic{Q, PR} PicturedObj{Schrodinger, Q, PR}

# Easily dispatch operations for same-picture args
*{P, PR}(a::PicturedObj{P, PR}, b::PicturedObj{P, PR}) = PicturedObj(P, a.obj*b.obj, a.prop*b.prop)

Parameterizing the picture type would also allow users to easily define new subtypes of Picture and define their behavior without needing to construct a wrapper type for each pictuce. This also means that the wrapper type can easily fall back to default behaviors if users do not properly define behaviors with new subtypes of Picture.

Would having efficient composable propogators as the above multiplication implies be out of the question for modern solvers? It would be really cool if we could realize a tensor product structure for propogators, though my knowledge here is weak (i.e. tensor(A(x,t;x't'), B(y,t;y',t')) -> AB(x,y,t;x',y',t')).

acroy commented 9 years ago

Using a Type parameter seems to be a better solution. But in any case we need to have a propagator type before we can work out the details.

Note that composability of propagators is a different issue. If you have an operator in the Heisenberg picture A(t) it is connected to the Schroedinger picture operator A via A(t)=U'(t,t0) A U(t,t0), where U(t,t0) is the propagator. If you "multiply" two Heisenberg operators at the same time you get

A(t)B(t)=U'(t,t0)AU(t,t0)U'(t,t0)BU(t,t0)=U'(t,t0)ABU(t,t0)

since U'(t,t0)U(t,t0)=I. In this case one can "save" one propagation and only propagate the product of the Schrödinger operators. You can also see that this is basically independent of the implementation of the propagtor itself (although the two versions, propagating separately and multiply or propagating the product, could give different numerical results because the propagtor might not be exactly unitary).

The tensor product of the two Heisenberg operators would amount to (denoting the tensor product by x)

A(t)xB(x) = U_A'(t,t0)xU'_B(t,t0) AxB U_A(t,t0)xU_B(t,t0)

Where I added subscripts to the propagators to distinguish them. I am not sure one can in general implement the tensor product of individual (numerical) propagations, but this is a question of realizing the propagators.