dH/dE is a negative diagonal matrix with -1 or 0 entries
This part is not obvious to me
site_offsets = np.cumsum( + [len(arr) for arr in self.site_arrays]) # Site array where next cell starts next_cell = bisect.bisect(site_offsets, self.cell_size) - 1
_system.pyand serves to find the index of the first site array that corresponds to the "next cell".
cell_size. It would be more robust and simpler to simply store
next_celldirectly. However, this does not seem possible, because
cell_sizeis actually provided directly by someone who implements the system API.
It seems to me that this wouldn't be a problem. There's no problem with consumers that use
hamiltonian_submatrix(): user code using this remains efficient even after vectorization. Consumers that use
hamiltonian directly (like tkwant or
kwant.operator) have to be rewritten anyway (or they don't profit from vectorization). The rewriting can work such that there's a case distinction: the old code (that is already written) is used for old-style systems, and new code is used for new systems.
That means some additional if clauses, but the overall complexity should be smaller, because we do not have to be careful to write the new code in such a way that it remains efficient for old systems. It also means that it will be easy to remove old cruft once we no longer support old systems.
isinstance(syst, system.FiniteSystem)for instance
Actually, I realize, vectorized low-level systems do not even have to implement the old API. That doesn't break backwards-compatibility, because old code is not supposed to trigger vectorization.
The only thing that matters is that it remains reasonably simple to accept either old or new systems. Taking the example that you gave, we could add a method
number_of_dimensions() or something similar), and add it also to old systems. Instead of continuing to provide the old API, we would define a new API, and inject small bits of it into the old systems, so that old systems partially ducktype as new ones.
I think the hierarchy of the new systems would be simple: a single class
graph, and lots of other cruft. That means less historical ballast in the future and simpler code in the long run.
In https://gitlab.kwant-project.org/kwant/kwant/issues/302, I wrote: "I propose to extend the low-level system API in the following way", so indeed that's what I had in mind. But recently I've been wondering whether making a cleaner cut wouldn't be preferable (for the above-stated reasons). Of course there would be still backwards compatibility, in the sense that old scripts would continue to work. It would be even higher compatibility, since the MR introduces some restrictions also on old systems.
The downside of splitting is that system consumers will have to adapt, but they have to anyway, if they want to profit from vectorization. And I'm not aware of any third-party system consumers beyond tkwant.
hamiltonian()wouldn't be necessary, neither
builder._Sites. So overall, the number of lines to be actively maintained would decrease. Also, backwards compatibility would be better: for example, the old fully general
hamiltonian_submatrixwould continue to exist.
I think we could only explain vectorized usage (in the tutorial) and state that non-vectorized usage is still supported for backwards compatibility.
In the reference, non-vectorized stuff should be marked as deprecated.
Is there a difference in this respectto the current MR?