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

RFC: Change iteratorsize trait of product(itr1, itr2) #16437

Merged
merged 5 commits into from
May 29, 2016
Merged

RFC: Change iteratorsize trait of product(itr1, itr2) #16437

merged 5 commits into from
May 29, 2016

Conversation

gasagna
Copy link
Contributor

@gasagna gasagna commented May 18, 2016

  1. Fixes Issue iterator traits for Base.product depend on number of arguments #16436.
  2. Adds many tests to product function and tests more thoroughly the iterator traits
  3. Adds a Prod1 type

Currently product seems not be exported. I can a commit if needed.

@test length(Base.product(1:2,1:10,4:6)) == 60
@test Base.iteratorsize(Base.product(1:2, countfrom(1))) == Base.IsInfinite()
# empty?
let
Copy link
Contributor

Choose a reason for hiding this comment

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

the let isn't really needed here since this is just a for loop

Copy link
Contributor Author

Choose a reason for hiding this comment

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

true

@tkelman
Copy link
Contributor

tkelman commented May 18, 2016

Not exporting was intentional in #14596, given the naming is not obvious that it would return an iterator. The eventual plan is to move iterators into their own module within Base.

eltype{I}(::Type{Prod1{I}}) = Tuple{eltype(I)}
size(p::Prod1) = size(p.a)

@inline start(p::Prod1) = (start(p.a),)
Copy link
Member

Choose a reason for hiding this comment

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

It doesn't seem necessary to wrap the state in a tuple. I see Zip1 does that too, which I didn't notice before. Should be changed, unless I'm missing something.

Copy link
Member

@nalimilan nalimilan May 19, 2016

Choose a reason for hiding this comment

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

It doesn't seem necessary to wrap the state in a tuple. I see Zip1 does that too, which I didn't notice before. Should be changed, unless I'm missing something.

Please don't do this again. :-) #13979

But of course here it's not needed. EDIT: it's needed just like for Zip1

Copy link
Member

Choose a reason for hiding this comment

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

No, of course the value needs to be wrapped in a tuple; my question is why the state should be.

Copy link
Member

Choose a reason for hiding this comment

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

As I said on the other issue, the function must always return a tuple to allow generic programming. See the (real) example I provided there.

Copy link
Member

Choose a reason for hiding this comment

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

This is the start function. It only returns a state, which is private to the iterator. The state is different from the elements generated by the iterator.

Copy link
Member

Choose a reason for hiding this comment

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

Ah, sorry. For some reason I thought the state had to be used. And indeed I see that I did that for Zip1 without really thinking about it.

@JeffBezanson
Copy link
Member

What should be the size of a product of two iterators which themselves are N-d? In e7d9b64 I had it concatenate the shapes, which seems consistent e.g. with the APL indexing rules.

@mschauer
Copy link
Contributor

Concatenation is the most natural thing to do.

*) Fixes Issue #16436.
*) Adds many tests to product function and tests more thoroughly the iterator traits
*) Adds a Prod1 type
*) Adds ndims(::Base.Prod*)
*) Change state of Prod1 iterator from tuple to integer

removed let block

removed trailing whitespace

changed state of Prod1 from tuple to integer

changed eltype of iterators for more generality

added ndims(::Base.Prod*)
@gasagna
Copy link
Contributor Author

gasagna commented May 19, 2016

I have done a few more things.

  • changed state of Prod1 iterator from tuple to integer, (I can do the same for Zip1 later on).
  • added ndims to Prod*

There are a couple of methods _size before the IteratorND that can be probably eliminated, as they are only used in IteratorND.

@mschauer
Copy link
Contributor

Regarding the _size methods: Before product had no size function, but as IteratorND wraps products, there was a need for a "shadow" _size method to make size information available underhandedly. With products having shape, _size can become size.

eltype{I1,I2}(::Type{Prod{I1,I2}}) = tuple_type_cons(eltype(I1), eltype(I2))
size(p::Prod) = (length(p.a), size(p.b)...)
Copy link
Contributor

Choose a reason for hiding this comment

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

This is tricky: depending on who HasShape or HasLength,
(length(p.a), size(p.b)...) or (size(p.a)..., size(p.b)...) or (size(p.a)..., length(p.b)). You can define _prod_size in a similar way as _min_length or _diff_length

Copy link
Contributor Author

Choose a reason for hiding this comment

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

mmm, not sure I follow. Can you write a test here that would make the current implementation fail?

@mschauer
Copy link
Contributor

mschauer commented May 22, 2016

  1. I saw that you figured out the workings of _prod_size. 👍

@mschauer
Copy link
Contributor

mschauer commented May 22, 2016

  1. Looking at this again I see that one cannot infer that products with infinite components are infinite because the other component might be empty. :-/

@JeffBezanson
Copy link
Member

Looks like a couple of these definitions are ambiguous. Please fix; would like to merge this soon.

throw(ArgumentError("Cannot compute size for object of type $(typeof(a))"))
_prod_size(a, b, ::Union{HasShape, HasLength}, B) =
throw(ArgumentError("Cannot compute size for object of type $(typeof(b))"))

Copy link
Contributor

Choose a reason for hiding this comment

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

This one is ambiguous

@JeffBezanson JeffBezanson mentioned this pull request May 27, 2016
4 tasks
@gasagna
Copy link
Contributor Author

gasagna commented May 28, 2016

Going to squash soon.. (thanks for the tip)

removed old _size methods

Fixed ambiguous methods
@JeffBezanson JeffBezanson merged commit 26a6bfc into JuliaLang:master May 29, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants