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

Use 0-size tidyverse recycling rules consistently #416

Merged
merged 16 commits into from
Jun 27, 2019

Conversation

DavisVaughan
Copy link
Member

@DavisVaughan DavisVaughan commented Jun 14, 2019

Closes #299

These changes to vec_size2() and shape_broadcast() enforce correct tidyverse recycling rules when comparing length-0 dimensions (those laid out in tidyverse/design#13 (comment)).

Specifically, the common length of 0 and 2 is now an error.

x  <- array(1, c(1, 2))
to <- array(1, c(1, 0))
vctrs:::shape_common(x, to)
#> Incompatible lengths: 2, 0.

The common length of 0 and 1 is 0, as it was before.

x  <- array(1, c(1, 1))
to <- array(1, c(1, 0))
vctrs:::shape_common(x, to)
#> [1] 0

When broadcasting to a shape, the dimensions you are broadcasting to must be exactly the same, unless the dimension you are broadcasting from is 1, in which case that can be broadcast to anything. All but the last of these examples produce the same result as before this PR, but I present them as a group to make the argument (the last one previously allowed you to broadcast from 2 down to 0)

# 1 can be broadcast _to_ anything
x  <- array(1, c(1, 1))
to <- array(1, c(1, 0))
vctrs:::shape_broadcast(x, to)
#>     
#> [1,]

to <- array(1, c(1, 2))
vctrs:::shape_broadcast(x, to)
#>      [,1] [,2]
#> [1,]    1    1
# everything else must be broadcast
# to the _exact_ same dimensions to be allowed

# 0 cannot be broadcast to 1
x  <- array(1, c(1, 0))
to <- array(1, c(1, 1))
vctrs:::shape_broadcast(x, to)
#> Can't cast <double[,0]> to <double[,1]>
#> Non-recyclable dimensions

# 2 cannot be broadcast to 0
x  <- array(1, c(1, 2))
to <- array(1, c(1, 0))
vctrs:::shape_broadcast(x, to)
#> Can't cast <double[,2]> to <double[,0]>
#> Non-recyclable dimensions

I think the only thing you might have a question about is the fact that this means you can't broadcast from 2 down to 0. You can currently do this with vec_recycle().

vctrs::vec_recycle(1:2, 0)
#> integer(0)

It also occurred to me while thinking about this that there are really two types of recycling rules. One set for determining a common length. And one set for determining if you can actually recycle from length X to length Y. The result of the first set of rules is guaranteed to be an allowed length in the second set of rules. The current impl of vec_recycle() implies that the second set of rules might be more flexible though, allowing that you can recycle from 2 down to 0, where the first set of rules would have never generated 0 as the common length of 2 and something else.

@DavisVaughan DavisVaughan requested a review from hadley June 14, 2019 21:14
@DavisVaughan
Copy link
Member Author

DavisVaughan commented Jun 14, 2019

Hmm I also think this should be an error, which would imply that you can't vec_recycle_common() those inputs either. (this would match the tibble example tidyverse/tibble#435 (comment))

vctrs::vec_size_common(1:2, numeric())
#> [1] 0

Copy link
Member

@lionel- lionel- left a comment

Choose a reason for hiding this comment

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

I think we should first reach a conclusion in the principles issues, before making any changes to vctrs.

This PR also needs to make broadcasting and recycling rules consistent by changing the common size code in size.c.

R/size.R Outdated Show resolved Hide resolved
@DavisVaughan
Copy link
Member Author

DavisVaughan commented Jun 17, 2019

  • The table in man/figures/size-recycling.png needs to be updated. Should the 0 row / col be removed entirely since it is now not a special case?

sizes-recycling

  • vec_recycle()'s documentation suggests that that table should have been included in the docs. Should it be?

@DavisVaughan DavisVaughan changed the title Use tidyverse recycling rules in common shape computations Use 0-size tidyverse recycling rules consistently Jun 21, 2019
@DavisVaughan
Copy link
Member Author

DavisVaughan commented Jun 27, 2019

  • If you have a better idea than shape_size2() I'm open to it. What I'm trying to do is find the common size of, say, x and y's 2nd dimension. Maybe axis2()?

Changed to axis2()

  • For the recycling image above, should the first row and first column be removed since 0 is not a special case?

Removed them

  • vec_recycle()'s documentation suggests that that table should have been included in the docs. Should it be?

Added the table png to the docs page

sizes-recycling

@DavisVaughan
Copy link
Member Author

DavisVaughan commented Jun 27, 2019

@lionel- good to go for a final review when you have time! (I don't know why the travis build isn't completing, it passed)

Copy link
Member

@lionel- lionel- left a comment

Choose a reason for hiding this comment

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

Looks good!

@DavisVaughan DavisVaughan merged commit da4c2ba into r-lib:master Jun 27, 2019
@DavisVaughan DavisVaughan deleted the shape branch June 27, 2019 16:30
@hadley
Copy link
Member

hadley commented Jun 27, 2019

Thanks @DavisVaughan!

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.

0-length recycling with shape_broadcast()
3 participants