Skip to content
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

Op repr updates #1394

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open

Op repr updates #1394

wants to merge 9 commits into from

Conversation

kohr-h
Copy link
Member

@kohr-h kohr-h commented Jun 25, 2018

(I just realized that this is based on the #1380 branch, so that should go in first.)
Ready for review now.

Here's the next bunch of commits from #1276, kept to the minimum of space, discr and operator. Other submodules follow.

Biggest changes:

  • __repr__ makes use of the new functionality with automatic line width adjustment (using np.get_printoptions()['linewidth']).
  • All __repr__ methods now have a doctest, to make sure the code runs and does something useful at least in one case.
  • Several operators that lacked custom range got it now.
  • Several operators changed from ...Base with common children to inner class pattern to share context.

Questionable stuff:

  • Spaces have asweighted, not quite sure about this
  • Some optimization of operator arithmetic, any problems?
  • Attribute repr doesn't quite work that well with linewidth. The reason is that it calls repr(parent_op) without knowing about the correct linewidth to use, and then appends its attribute string. I don't quite know how to solve this, but it doesn't feel like a pressing issue either.
  • To implement custom (e.g. weighted) range for product space operators (e.g., PointwiseInner), we need to consider spaces as compatible (in this narrow context) that have different weightings but are otherwise the same. Needs some thought about the consequences though.

Additional changes/fixes:

  • Add Numpy 1.14 to Travis
  • Travis setup with Numpy versions wasn't ideal, it would always take the 1.*.0 version, but 1.14.0 is broken, for instance. Changed to take the latest compatible.
  • Exclude Numpy 1.14.0 to 1.14.2 due to printing bugs, messes up doctests and such. Easy to get newer version
  • Product space elements are printed slightly more compactly
  • Adapted TODO comments
  • Default print of Operator is better now IMO
  • Removed separate __str__ mostly, doesn't really add value very often. The base Operator class defaults to __str__ = __repr__ (not literally)
  • Imports now sorted with isort. Also added an .isort.cfg.

TODOs (after review):

  • Make repr precision controllable by user (look at numpy.getprintoptions()['precision']
  • Remove .isort.cfg
  • Pull out the operator arithmetic stuff into a separate PR to /dev/null

@pep8speaks
Copy link

pep8speaks commented Jun 25, 2018

Checking updated PR...

Line 549:80: E501 line too long (80 > 79 characters)

  • Complete extra results for this file :
    ProductSpace(uniform_discr([-1., -1.], [ 1.,  1.], (1, 2)), 2).element([                                                                               ^---
Comment last updated on August 30, 2018 at 21:51 Hours UTC

@kohr-h kohr-h added this to Needs review in PR Status Jun 28, 2018
[[ 2., 2., 2., 2., -3.],
[ 2., 2., 2., 2., -4.],
[ -1., -2., -3., -4., -12.]]
)

Verify adjoint:

>>> g = div.range.element(data ** 2)
>>> adj_div_g = div.adjoint(g)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove line

@kohr-h
Copy link
Member Author

kohr-h commented Aug 22, 2018

Hey, could someone please have a look at this?

It may seem like a daunting task with so many lines of diff, but it's actually not that much. Most of it is documentation and doesn't need that close of a look, in the sense that errors that slip through won't break anything.

I've listed the most important changes above.

@adler-j
Copy link
Member

adler-j commented Aug 23, 2018

I'll try to review this!

Copy link
Member

@adler-j adler-j left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall good changes, but this really should have been 2 or even 3 different pull requests since it does wastly different things.

The only thing that needs discussion is the general addition of ranges where it does not seem obviously needed. Why has this been done?

.isort.cfg Outdated
@@ -0,0 +1,14 @@
[settings]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More spam of the top level directory. Why do we need this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That file slipped through, I'll ditch it.

posargs = [self.domain]
optargs = [('range', self.range, self.domain ** self.domain.ndim),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this a misstake?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was a bug, yes. Copy 'n paste from Gradient I suppose.

@@ -12,20 +12,21 @@
operators.
"""

from __future__ import print_function, division, absolute_import
from __future__ import absolute_import, division, print_function
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this just standardization? If so (for next time), I'd prefer if it had a separate PR and was done to all of these occurances.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I ran isort on the imports, so I don't have to think about where to put new imports. They'll be sorted and grouped nicely automatically.
I already did a few of the files in #1380, this part of the big PR #1276 just continues that. IMO the structure of the imports is better this way, compared to the "random" ordering we had before.

--------
>>> rect = odl.IntervalProd([0, 0], [1, 1])
>>> fspace = odl.FunctionSpace(rect)
>>> part = odl.uniform_partition_fromintv(rect, shape=(4, 2))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to use this very length version instead of the shorter options?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe not...

>>> resampling_inv(resampling([0.0, 1.0, 0.0]))
uniform_discr(0.0, 1.0, 3).element([ 0., 1., 0.])

However, it can fail in the other direction:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extremely nice doc!


Examples
--------
All rows and columns with an operator, i.e., domain and range
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wording could be improved. E.g. use something else that "with an operator", perhaps even drop it and only go with "Domain and range are inferred if there is at least one operator per row/column", or similar.

[0, IdentityOperator(rn(3))]]
)

Domain not completely determined (column with all zeros):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mention that we need to give domain in this case.

Domain not completely determined (column with all zeros):

>>> prod_op = odl.ProductSpaceOperator([[I, 0],
... [I, 0]], domain=pspace)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Push domain to next row

@@ -655,66 +672,70 @@ def __init__(self, space, index):

Projection on the 0-th component:

>>> proj_adj = odl.ComponentProjectionAdjoint(pspace, 0)
>>> proj_adj = odl.ComponentProjection(pspace, 0).adjoint
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason we think users might not want this "embeding"? I'm not 100% sure we only want this accessible like this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't really think about that. My assumption, given the name, was that it was just there as a "slave" to the "master" class ComponentProjection.
The class may certainly be of use on its own, if I think about it. How about we call it ComponentEmbedding? (It feels like we discussed this before.)

@@ -427,7 +439,8 @@ def examples(self):
self.element(np.random.uniform(size=self.shape) +
np.random.uniform(size=self.shape) * 1j))
else:
# TODO: return something that always works, like zeros or ones?
# TODO(kohr-h): return something that always works, like zeros
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For non-numeric dtypes there is basically nothing left. What would zeros be for e.g. strings?

Copy link
Member Author

@kohr-h kohr-h Aug 26, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think zeros actually works with any type, meaningful or not.

>>> np.zeros(2, dtype=bool)
array([False, False], dtype=bool)
>>> np.zeros(2, dtype="U2")
array(['', ''],
      dtype='<U2')
>>> np.ones(2, dtype=bool)
array([ True,  True], dtype=bool)
>>> np.ones(2, dtype="U2")
array(['1', '1'],
      dtype='<U2')

Copy link
Member

@adler-j adler-j Aug 27, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll be damned

>>> np.zeros(2, dtype=object)
array([0, 0], dtype=object)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I think that one at least makes a bit of sense. Doesn't matter for us since we don't allow dtype=object. I personally find np.ones with string type hilarious.

>>> resampling = odl.Resampling(coarse_discr, fine_discr)
>>> resampling_inv = resampling.inverse

The inverse is proper left inverse if the resampling goes from a
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

slight wording issue

@@ -258,6 +259,21 @@ def astype(self, dtype):
else:
return self._astype(dtype)

def asweighted(self, weighting):
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about this? It's going to be needed at some point, but not strictly here.

Another idea with this functionality would be to stuff it inside astype in kwargs, and to extend that function with more stuff that we might want to change. For instance interpolation, impl, or even trivial stuff like axis labels.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bumping this

@kohr-h kohr-h force-pushed the op_repr_updates branch 2 times, most recently from ac9aaa8 to 67f5b17 Compare August 26, 2018 22:11
@kohr-h
Copy link
Member Author

kohr-h commented Aug 31, 2018

This is largely done, up to some open questions.

@adler-j adler-j mentioned this pull request Sep 11, 2018
20 tasks
@kohr-h kohr-h added this to In Progress in Release 1.0.0 Sep 11, 2018
@kohr-h kohr-h moved this from Needs review to Work in progress in PR Status Jul 18, 2019
@kohr-h
Copy link
Member Author

kohr-h commented Apr 13, 2020

I marked this as obsolete. It can be considered as a cherry-pick-from PR. So keeping it open until the changes are implemented some other way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
PR Status
Work in progress
Release 1.0.0
  
In Progress
Development

Successfully merging this pull request may close these issues.

None yet

3 participants