Allow `GraphOperator` to act on specified sites or subsystems
Created by: femtobit
Imagine a composite Hilbert space with two subsystems like this:
>>> hi = Spin(1/2, N=n1) * Fock(N=n2)
Then we have n1 + n2
sites [0, ..., n1 - 1]
corresponds to the first and [n1, ..., n1 + n2 - 1]
to the second subsystem.
Constructing some Hamiltonian as sum of LocalOperator
s is easy enough. But GraphOperator
(and also our built-in physical Hamiltonians like Ising
and Heisenberg
) does not currently support that. It acts on the sites of the given graph, but currently it is expected that the graph and site indices match exactly, so there is no direct way to specify a GraphOperator
acting only on, e.g., the second subsystem.
I think the best way to address this is to allow users to specify a mapping of graph site indices to Hilbert sites like this:
>>> g1 = Chain(n1)
>>> g2 = Chain(n2)
>>> h1 = Heisenberg(hi, g1, acting_on_sites=list(range(n1)))
>>> h2 = GraphOperator(hi, g2, acting_on_sites=list(range(n1, n1 + n2)), ...)
so that for both operators, the graph node with index Ig
corresponds the Hilbert space site with index acting_on_sites[Ig]
. For the common pattern of having a start index and a number of sites, we could also support specifying tuples (start, n_sites)
like this:
>>> h1 = Heisenberg(hi, g1, acting_on_sites=(0, n1))
>>> h2 = GraphOperator(hi, g2, acting_on_sites=(n1, n2), ...)
I think this is fully backwards compatible and makes GraphOperator
and the like more useful in composite spaces. What do you think?
A more fancy alternative, would be to label subsystems and allow to specify that label, like
>>> hi = Spin(1/2, N=n1, label="spin") * Fock(N=n2, label="fock")
>>> hi.subsystem("spin") # returns subsystem indices
[0, 1, ..., n1]
>>> h2 = GraphOperator(hi, g2, subsystem="fock", ...)
This would be a bit less flexible, though (since only subsystems, not arbitrary indices, could be passed).
EDIT: Improved interface in examples a bit.