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

Allow FrozenObjects to control param init order #1493

Merged
merged 1 commit into from
Nov 21, 2018
Merged

Conversation

drasmuss
Copy link
Member

Motivation and context:

With our Parameter validation system, sometimes parameters need to be initialized in a particular order. When copying an object the order is random by default, so we need to impose an order on this. We had this in place for NengoObjects, but not for FrozenObjects. Previously this was fine because we didn't have any FrozenObjects where order mattered, but for the new Convolution object it does matter.

I also added a seed for the Convolution test. I had a random test failure at some point that I wasn't able to reproduce again, so I'm not even 100% sure if it was real. But adding a seed here doesn't hurt.

How has this been tested?

Added a new test that fails without this change and passes with it.

How long should this take to review?

  • Quick (less than 40 lines changed or changes are straightforward)

Types of changes:

  • Bug fix (non-breaking change which fixes an issue)

Checklist:

  • I have read the CONTRIBUTING.rst document.
  • I have updated the documentation accordingly.
  • I have included a changelog entry.
  • I have added tests to cover my changes.
  • I have run the test suite locally and all tests passed.

@jgosmann
Copy link
Collaborator

I think this warrants to revive the discussion whether to have the copy code in a mixin class.

@drasmuss
Copy link
Member Author

drasmuss commented Nov 19, 2018

I don't have a strong opinion one way or the other, but it would be nice to get this resolved quickly as this is breaking NengoDL master (albeit very rarely).

if isinstance(v, Parameter) and not isinstance(v, ObsoleteParam)}
self._paramdict = collections.OrderedDict(
(k, v) for k, v in inspect.getmembers(type(self))
if isinstance(v, Parameter) and not isinstance(v, ObsoleteParam))
Copy link
Member Author

@drasmuss drasmuss Nov 19, 2018

Choose a reason for hiding this comment

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

Just taking a guess what you're going for here, but keep in mind that inspect.getmembers returns the members in alphabetical order, not the order they're defined in the code.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yes, I think that's fine. I just wanted to make them have a consistent order, so that we can rely on some order. Does that make sense?

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, can't hurt 👍

Copy link
Collaborator

@hunse hunse left a comment

Choose a reason for hiding this comment

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

I've added a few little fixups. One makes sure the parameters always have a consistent order, just to make things consistent. It also saves a bit of time in __repr__ because we don't have to sort them then.

The other changes are just minor ones for speed: not turning an iterator into a list (since we always just iterate over it), and not having to check if the param is in state each time through the loop in __setstate__.

This looks ready to go to me. I don't think we need to hold this up for a discussion about making copying a mixin; that's a discussion that can happen on its own.

@drasmuss
Copy link
Member Author

Fixups look good to me.

Copy link
Member

@tbekolay tbekolay left a comment

Choose a reason for hiding this comment

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

Made an inline comment to explain why something was the way it was. Will change it back in the merge. Aside from that LGTM, merging!

nengo/params.py Outdated
for p in self._params:
if not p.readonly:
msg = "All parameters of a FrozenObject must be readonly"
raise ReadonlyError(attr=p, obj=self, msg=msg)

@property
def _params(self):
return list(itervalues(self._paramdict))
return itervalues(self._paramdict)
Copy link
Member

Choose a reason for hiding this comment

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

So the reason this was a list and not an iterator is because it's a property. When you do thing.attribute you do not expect to get back an iterator, conventionally iterators are only returned from methods (hence why we have dict.values() etc rather than dict.values). This is important because:

param = self._params
for p in param:
   # this works fine
for p in param:
   # this now fails because the iterator is exhausted

I definitely wouldn't expect this behavior, as an attribute should just give me data. I would be more likely to expect something like this with params = self._iterparams().

Copy link
Collaborator

Choose a reason for hiding this comment

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

Sure, makes sense!

@tbekolay tbekolay merged commit 9713a29 into master Nov 21, 2018
@tbekolay tbekolay deleted the frozen-order branch November 21, 2018 03:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants