-
Notifications
You must be signed in to change notification settings - Fork 635
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use dispatchers to allow Qobj to use any backing data #1351
Conversation
@jakelishman I merged #1342, you can rebase. |
These are specifically for matrices which are used in base constructions, and in places such as `Qobj`. Operators in `core/operators.py` and the like should not get their own _data-layer_ dispatchers, but should define a dispatcher in their own file.
The type conversion of the output goes the other way!
Just for improving self-documentation, no meaningful changes.
Comparison function for checking something is a zero matrix. This may lead in the future to an `isequal` function for direct comparisons between two matrices.
To achieve this, we have to swap the order of `scale` and `out` in the call structure, because the dispatchers need to have a "compatible" signature, and they can't achieve this if `left, right, scale` are passed in positional form. This can possibly cause problems in Cython code; preliminary testing seemed to suggest that Cython would do something wrong if I passed the last parameter as a keyword (out) but not the penultimate one (scale), which still had a default. I was doing this in a period when there were other problems, however, so this may not have been the exact cause.
In previous versions of this function (before the fast_csr_matrix/CSR switchover) the old C-struct CSR_Matrix would be resized if enough elements had been deleted. Since our CSR type may be backed by numpy storage, this isn't as clearly a safe operation any more. This may be a solveable problem, but right now it's not a high priority as the downsides to _not_ doing it are not large.
With QuTiP's default settings, this is one of the most important functions to define to make sure that `Qobj` really uses a new data type, since many mathematical operations will implicitly include a call to `data.tidyup`. Without a specialisation for it, this will end up in the data getting converted to a different type immediately.
The most obvious change is that `ptrace` now does something sensible when faced with an `operator-ket` or `operator-bra` (it swaps back to matrix form for the operator, performs the operation, and reverts), rather than just loudly failing. The documentation is now written for what happens when given a superoperator, but the behaviour is unchanged from how QuTiP has generally handled them.
I suppose the answer is "yes", but there's still that huge to do list at the top that needs to be handled (including some really really important bits like the tests). I'm just rebasing it now. By the way, I'm getting a lot of |
f7d6f7f
to
44f36d9
Compare
That's the rebase done. Those tests should pass now; they do on my machine. |
Which warnings? |
jake@tauros$ python
Python 3.7.7 (default, May 6 2020, 04:59:01)
[Clang 4.0.1 (tags/RELEASE_401/final)] :: Anaconda, Inc. on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import qutip
/Users/jake/.anaconda3/anaconda3/envs/qutip-dev/lib/python3.7/site-packages/setuptools/distutils_patch.py:26: UserWarning: Distutils was imported before Setuptools. This usage is discouraged and may exhibit undesirable behaviors or errors. Please use Setuptools' objects directly or at least import Setuptools first.
"Distutils was imported before Setuptools. This usage is discouraged "
>>> It was caused by the original coefficients PR. Could be interplay between At any rate, it would be very good to drop the |
qutip/tests/core/test_qobjevo.py
Outdated
pytest.param('spline', | ||
[[cplx_qobj, cplx_coeff.spline(tlist, args)], cte_qobj], | ||
{}, id='spline'), | ||
pytest.param('array', [cte_qobj, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you prefer this spacing, at least be consistent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh, that was a mistake. I didn't even mean to change the first bit
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or more, I didn't mean to commit it - I just fiddle around with it while I'm reading it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll revert it and fix the commit
Mostly this is a simple change; we just remove the `_csr` or `_csr_dense_dense` (or whatever) suffix from the data operations to make them dispatching. In a few places of old code (like in steadystate) we manually force the data types into the CSR format so the rest of the code can continue unimpeded. In theory, this now means that QuTiP can use any data-layer type for every single operation, and mix them completely freely. In reality, there may be a couple of places where CSR format is assumed in ways I forgot to check for, and certainly the creation of objects still _strongly_ favours creating CSR types. The ergonomics of creating Qobjs and selecting dispatch methods (such as for expm) where it may be beneficial to convert the input into another type still need to be improved.
44f36d9
to
11195f9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Qobj
's backing going through the Dispatcher
means your work is online with this. Great!
Do we merge this like this or wait for more specializations (isherm_dense
, tidyup
with rtol
, etc.)
I would prefer the data layer to be more hidden: not ask the user to access it for feature previously available. But I don't have clean solution to propose.
if np.any(np.imag(out) > settings.core['atol']) or not self.isherm: | ||
return out | ||
else: | ||
return np.real(out) | ||
|
||
@_tidyup | ||
def expm(self, method='dense'): | ||
def expm(self, dtype=_data.Dense): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why ask for the data type here, instead of the string? This force the user to know where to find the data layer object, which I don't like... But the string are messy and cannot be extended as easily to new types... I don't like it but it has it's advantages.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I don't like this either. It's a similar problem with eigs
, but that's even less obvious. I'm going to think about it a bit more, and hopefully I'll have some more ideas to suggest - it's one of my to do bullet points.
_SINGLE_QUBIT_PAULI_BASIS = (identity(2), sigmax(), sigmay(), sigmaz()) | ||
# TODO: revisit when creation routines have dispatching. | ||
_SINGLE_QUBIT_PAULI_BASIS = ( | ||
identity(2).to(_data.CSR), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't it be better to have these as Dense
per default?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Possibly? They're only used in the next function down in superop_reps
, and I didn't test enough of what it was doing to know if a sparse or dense representation was better for that function. It looks sort of sparse, maybe?
I'm happy to go either way on whether to merge this now or later. I'm happy to keep adding to it, but I'm also mindful that I don't want this to turn into another +15000/-15000 PR. I possibly need to look into that test failure a little more - it's temperamental, and I'm not sure if it's something where it's just a case of a too strict tolerance, or if there is an actually numerical precision problem. |
I prefer smaller PRs, this is big enough. |
It's ~caused by the swap to the data-layer - probably it's just minor floating-point uncertainties due to slightly changed algorithms, but I'm not 100% sure on that. |
Finally,
Qobj
can use any backing data store. This fairly small and simple PR is effectively the culmination of all the work ondev.major
over the last few months, and effectively is just like flicking a switch to turn on all the capabilities that we've built up through #1282, #1296, #1332, #1338 and #1341.There is still a lot of work to be done, but I'm trying to transition to smaller, easier-to-check PRs to make review easier.
Possibly incomplete to do list:
data.create
data.Data
mathematical methods (e.g.__matmul__
)Qobj
with both typesDense
andCSR
/Dense
Dense
specialisation ofeigs
even if you pass it aCSR
)qutip.basis
function, and how will users add specialisations?)add_csr
andmatmul_csr
to usecsr.Accumulator
(should provide a speedup and remove some sorts)isherm_csr
(see Incorrect results from zcsr_isherm #1350 -isherm_csr
uses the same algorithm, so has the same problem)