{"action":"created","comment":{"url":"https://api.github.com/repos/numpy/numpy/pulls/comments/225772968","pull_request_review_id":165446428,"id":225772968,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIyNTc3Mjk2OA==","diff_hunk":"@@ -648,15 +779,70 @@ def block(arrays):\n \n \n     \"\"\"\n-    bottom_index, arr_ndim = _block_check_depths_match(arrays)\n+    arrays, list_ndim, result_ndim, final_size = _block_setup(arrays)\n+\n+    # It was found through benchmarking that making an array of final size\n+    # around 256x256 was faster by straight concatenation on a\n+    # i7-7700HQ processor and dual channel ram 2400MHz.\n+    # It didn't seem to matter heavily on the dtype used.\n+    #\n+    # A 2D array using repeated concatenation requires 2 copies of the array.\n+    #\n+    # The fastest algorithm will depend on the ratio of CPU power to memory\n+    # speed.\n+    # One can monitor the results of the benchmark\n+    # https://pv.github.io/numpy-bench/#bench_shape_base.Block2D.time_block2d\n+    # to tune this parameter until a C version of the `_block_info_recusion`","path":"numpy/core/shape_base.py","position":202,"original_position":202,"commit_id":"b2db60c202928e05599f7612da5461e34400a97c","original_commit_id":"b2db60c202928e05599f7612da5461e34400a97c","user":{"login":"eric-wieser","id":425260,"node_id":"MDQ6VXNlcjQyNTI2MA==","avatar_url":"https://avatars3.githubusercontent.com/u/425260?v=4","gravatar_id":"","url":"https://api.github.com/users/eric-wieser","html_url":"https://github.com/eric-wieser","followers_url":"https://api.github.com/users/eric-wieser/followers","following_url":"https://api.github.com/users/eric-wieser/following{/other_user}","gists_url":"https://api.github.com/users/eric-wieser/gists{/gist_id}","starred_url":"https://api.github.com/users/eric-wieser/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/eric-wieser/subscriptions","organizations_url":"https://api.github.com/users/eric-wieser/orgs","repos_url":"https://api.github.com/users/eric-wieser/repos","events_url":"https://api.github.com/users/eric-wieser/events{/privacy}","received_events_url":"https://api.github.com/users/eric-wieser/received_events","type":"User","site_admin":false},"body":"typo","created_at":"2018-10-17T03:43:46Z","updated_at":"2018-10-17T03:43:46Z","html_url":"https://github.com/numpy/numpy/pull/11971#discussion_r225772968","pull_request_url":"https://api.github.com/repos/numpy/numpy/pulls/11971","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/numpy/numpy/pulls/comments/225772968"},"html":{"href":"https://github.com/numpy/numpy/pull/11971#discussion_r225772968"},"pull_request":{"href":"https://api.github.com/repos/numpy/numpy/pulls/11971"}}},"pull_request":{"url":"https://api.github.com/repos/numpy/numpy/pulls/11971","id":215878195,"node_id":"MDExOlB1bGxSZXF1ZXN0MjE1ODc4MTk1","html_url":"https://github.com/numpy/numpy/pull/11971","diff_url":"https://github.com/numpy/numpy/pull/11971.diff","patch_url":"https://github.com/numpy/numpy/pull/11971.patch","issue_url":"https://api.github.com/repos/numpy/numpy/issues/11971","number":11971,"state":"open","locked":false,"title":"MAINT: Block algorithm with a single copy per call to `block`","user":{"login":"hmaarrfk","id":90008,"node_id":"MDQ6VXNlcjkwMDA4","avatar_url":"https://avatars0.githubusercontent.com/u/90008?v=4","gravatar_id":"","url":"https://api.github.com/users/hmaarrfk","html_url":"https://github.com/hmaarrfk","followers_url":"https://api.github.com/users/hmaarrfk/followers","following_url":"https://api.github.com/users/hmaarrfk/following{/other_user}","gists_url":"https://api.github.com/users/hmaarrfk/gists{/gist_id}","starred_url":"https://api.github.com/users/hmaarrfk/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hmaarrfk/subscriptions","organizations_url":"https://api.github.com/users/hmaarrfk/orgs","repos_url":"https://api.github.com/users/hmaarrfk/repos","events_url":"https://api.github.com/users/hmaarrfk/events{/privacy}","received_events_url":"https://api.github.com/users/hmaarrfk/received_events","type":"User","site_admin":false},"body":"Block used to make repeated calls to concatenate. For a 3D block, this would copy the arrays 3 times. 1 time for each dimension of the block. This is 2 times too many.\r\n\r\nThis proposed algorithm does so with 1 memory copy. \r\n\r\nWisdom allows numpy to guess which algorithm is better performing and chooses that one automatically. We can add a switch, to let the user decide.\r\n\r\nTODO:\r\n- [x] Add tests that trigger both code paths.\r\n- [x] Ensure that the docstrings are sensible.\r\n- [x] Decide on how to test the other branch of block function.\r\n- [x] Decide on how to treat F order matricies (or mixes of dimensions).\r\n- [x] Decide on how to deal with masked array objects. concatenate supports them. Seems like we still don't know how to deal with subclasses. See https://github.com/numpy/numpy/issues/8881 and  https://github.com/numpy/numpy/issues/9270\r\n\r\nXREF: Other issues I found regarding concatenate that we might want to test for\r\n- endianness: https://github.com/numpy/numpy/issues/7829 -- should test\r\n- Empty lists: https://github.com/numpy/numpy/issues/1586  -- Block doesn't support empty lists\r\n- F/C ordering: See https://github.com/numpy/numpy/pull/11971#discussion_r223183338, and previous https://github.com/numpy/numpy/pull/9209#discussion_r138170238 and issue https://github.com/numpy/numpy/pull/2696\r\n\r\nThe general steps are:\r\n1. Sanitize the input.\r\n1. Cast each block as a numpy array of the final dimension\r\n2. Calculate the shape of each block\r\n3. Concatenate the shapes\r\n5. Keep track of the slice of a particular block within the larger whole.\r\n4. Combines dtypes to find the `dtype` of the result.\r\n6. Create the new array.\r\n7. Copy the blocks in.\r\n\r\nA benchmark was added to estimate the 2D blocking performance in a straightforward manner.\r\n\r\n# Approach details\r\n# 2D results\r\nFor small arrays, this approach seems to suffer from large overhead. Benchmarks show that \"small arrays\" are anything as large as `256x256` arrays a modern i7 from 2017.\r\n\r\nThe performance of `master` is optimized in PR #11991.  This shaves the overhead time for a 2x2 block from 20us to 15 us. Benchmarks in this section are compared to that PR. The overhead for this method is 30 us when blocking a small 2x2 array.\r\n\r\nMy general sense is that small arrays are pretty important. While the `concatenate` approach was \"wasteful\" for large arrays, it was quick for small arrays. There is probably room for both approaches.\r\n\r\n<details>\r\n<summary>Benchmark results compared to PR #11991 </summary>\r\n\r\n```\r\n       before           after         ratio\r\n     [1af752aa]       [0b1d866f]\r\n     <block_optimize_order>       <block_single_assignment>\r\n+      15.6±0.3μs       30.0±0.8μs     1.92  bench_shape_base.Block2D.time_block2d((16, 16), 'uint8', (2, 2))\r\n+     15.8±0.08μs         30.2±1μs     1.91  bench_shape_base.Block2D.time_block2d((16, 16), 'uint32', (2, 2))\r\n+      39.4±0.2μs         73.1±2μs     1.85  bench_shape_base.Block2D.time_block2d((32, 32), 'uint8', (4, 4))\r\n+      16.9±0.3μs         31.1±1μs     1.84  bench_shape_base.Block2D.time_block2d((32, 32), 'uint64', (2, 2))\r\n+      16.8±0.3μs       31.0±0.9μs     1.84  bench_shape_base.Block2D.time_block2d((32, 32), 'uint32', (2, 2))\r\n+      40.3±0.3μs       73.7±0.9μs     1.83  bench_shape_base.Block2D.time_block2d((32, 32), 'uint16', (4, 4))\r\n+      16.4±0.6μs       29.8±0.7μs     1.82  bench_shape_base.Block2D.time_block2d((32, 32), 'uint8', (2, 2))\r\n+      16.9±0.3μs       30.8±0.9μs     1.82  bench_shape_base.Block2D.time_block2d((32, 32), 'uint16', (2, 2))\r\n+      39.6±0.7μs       71.8±0.9μs     1.81  bench_shape_base.Block2D.time_block2d((16, 16), 'uint8', (4, 4))\r\n+      16.2±0.3μs       29.3±0.5μs     1.81  bench_shape_base.Block2D.time_block2d((16, 16), 'uint16', (2, 2))\r\n+      16.6±0.1μs       30.0±0.3μs     1.80  bench_shape_base.Block2D.time_block2d((64, 64), 'uint8', (2, 2))\r\n+      41.4±0.3μs         74.5±2μs     1.80  bench_shape_base.Block2D.time_block2d((16, 16), 'uint32', (4, 4))\r\n+      42.3±0.7μs         75.7±2μs     1.79  bench_shape_base.Block2D.time_block2d((32, 32), 'uint64', (4, 4))\r\n+      16.6±0.6μs       29.7±0.4μs     1.79  bench_shape_base.Block2D.time_block2d((16, 16), 'uint64', (2, 2))\r\n+      18.1±0.1μs       32.3±0.8μs     1.79  bench_shape_base.Block2D.time_block2d((64, 64), 'uint32', (2, 2))\r\n+      17.3±0.6μs       30.9±0.3μs     1.78  bench_shape_base.Block2D.time_block2d((64, 64), 'uint16', (2, 2))\r\n+      41.7±0.6μs         74.2±2μs     1.78  bench_shape_base.Block2D.time_block2d((64, 64), 'uint16', (4, 4))\r\n+      40.8±0.9μs       72.0±0.7μs     1.77  bench_shape_base.Block2D.time_block2d((16, 16), 'uint16', (4, 4))\r\n+      42.7±0.4μs       75.0±0.3μs     1.76  bench_shape_base.Block2D.time_block2d((64, 64), 'uint32', (4, 4))\r\n+        41.9±1μs         72.9±2μs     1.74  bench_shape_base.Block2D.time_block2d((16, 16), 'uint64', (4, 4))\r\n+        41.9±1μs       72.8±0.5μs     1.74  bench_shape_base.Block2D.time_block2d((32, 32), 'uint32', (4, 4))\r\n+        46.0±1μs         79.8±2μs     1.73  bench_shape_base.Block2D.time_block2d((128, 128), 'uint16', (4, 4))\r\n+      18.2±0.3μs       31.4±0.7μs     1.72  bench_shape_base.Block2D.time_block2d((128, 128), 'uint8', (2, 2))\r\n+      44.1±0.9μs       75.1±0.8μs     1.70  bench_shape_base.Block2D.time_block2d((128, 128), 'uint8', (4, 4))\r\n+        45.1±1μs         75.7±2μs     1.68  bench_shape_base.Block2D.time_block2d((64, 64), 'uint64', (4, 4))\r\n+        44.0±1μs         73.4±2μs     1.67  bench_shape_base.Block2D.time_block2d((64, 64), 'uint8', (4, 4))\r\n+      49.4±0.3μs       79.3±0.4μs     1.60  bench_shape_base.Block2D.time_block2d((256, 256), 'uint8', (4, 4))\r\n+      20.6±0.4μs       32.9±0.4μs     1.60  bench_shape_base.Block2D.time_block2d((128, 128), 'uint16', (2, 2))\r\n+      19.7±0.5μs       31.4±0.2μs     1.59  bench_shape_base.Block2D.time_block2d((64, 64), 'uint64', (2, 2))\r\n+        50.0±2μs         78.9±3μs     1.58  bench_shape_base.Block2D.time_block2d((128, 128), 'uint32', (4, 4))\r\n+      54.3±0.2μs         81.4±1μs     1.50  bench_shape_base.Block2D.time_block2d((128, 128), 'uint64', (4, 4))\r\n+      23.5±0.6μs         34.6±1μs     1.47  bench_shape_base.Block2D.time_block2d((128, 128), 'uint32', (2, 2))\r\n+        57.8±1μs         85.0±2μs     1.47  bench_shape_base.Block2D.time_block2d((256, 256), 'uint16', (4, 4))\r\n+      24.5±0.7μs       35.4±0.4μs     1.45  bench_shape_base.Block2D.time_block2d((256, 256), 'uint8', (2, 2))\r\n+      28.3±0.3μs         38.4±1μs     1.36  bench_shape_base.Block2D.time_block2d((128, 128), 'uint64', (2, 2))\r\n+      29.8±0.2μs         40.2±1μs     1.35  bench_shape_base.Block2D.time_block2d((256, 256), 'uint16', (2, 2))\r\n-       175±200μs          150±4μs     0.85  bench_shape_base.Block2D.time_block2d((1024, 1024), 'uint8', (4, 4))\r\n-      72.0±100μs       59.6±0.8μs     0.83  bench_shape_base.Block2D.time_block2d((512, 512), 'uint16', (2, 2))\r\n-      70.8±100μs       56.9±0.1μs     0.80  bench_shape_base.Block2D.time_block2d((256, 256), 'uint64', (2, 2))\r\n-       167±200μs          133±1μs     0.80  bench_shape_base.Block2D.time_block2d((512, 512), 'uint32', (4, 4))\r\n-       132±200μs         89.4±3μs     0.68  bench_shape_base.Block2D.time_block2d((1024, 1024), 'uint8', (2, 2))\r\n-       131±200μs       82.4±0.8μs     0.63  bench_shape_base.Block2D.time_block2d((512, 512), 'uint32', (2, 2))\r\n-       377±500μs        191±0.8μs     0.51  bench_shape_base.Block2D.time_block2d((512, 512), 'uint64', (4, 4))\r\n-       403±500μs          203±4μs     0.51  bench_shape_base.Block2D.time_block2d((1024, 1024), 'uint16', (4, 4))\r\n-      1.20±0.8ms         472±20μs     0.39  bench_shape_base.Block2D.time_block2d((1024, 1024), 'uint32', (4, 4))\r\n-        6.14±2ms         985±20μs     0.16  bench_shape_base.Block2D.time_block2d((1024, 1024), 'uint64', (4, 4))\r\n-        6.28±2ms         983±50μs     0.16  bench_shape_base.Block2D.time_block2d((1024, 1024), 'uint64', (2, 2))\r\n-        2.94±1ms         360±20μs     0.12  bench_shape_base.Block2D.time_block2d((1024, 1024), 'uint32', (2, 2))\r\n-      1.27±0.5ms          146±3μs     0.12  bench_shape_base.Block2D.time_block2d((1024, 1024), 'uint16', (2, 2))\r\n-      1.32±0.5ms          126±4μs     0.10  bench_shape_base.Block2D.time_block2d((512, 512), 'uint64', (2, 2))\r\n```\r\n</details>\r\n\r\n## A few small micro optimizations\r\n\r\nThis PR builds on-top of pretty optimized code already in numpy. Getting the performance close hard/impossible.\r\n\r\nList comprehensions are really expensive. Unfortunately, blocking allows for really fancy block shapes, which means that we cant do much but to use them in python.\r\n\r\nA few things can be optimized:\r\n\r\n1. Generators are slow. Thanks @eric-wieser for teaching me about that.\r\n2. Empty lists are falsy. You can use this to test for unlikely cases using list comprehensions.\r\n3. Creating tuples is expensive. Create them once, reuse them.\r\n\r\nI'm unsure how these optimizations affect the performance in PyPy \r\n\r\n# 3D results:\r\nFor large arrays, the benchmark https://github.com/numpy/numpy/pull/11965 shows that there is now little room to improve compared to a straight concatenate operation. This is really expected since here we are probably copying the arrays more than the cost it takes to generate the slices.\r\n\r\n<details>\r\n<summary> benchmarks </summary>\r\nThe benchmarks show results for a final array of size `5 n`^3. Therefore, for n=10, the final array has 125,000 elements, each 8 bytes (int 64), so close to 1MB. `n=100` is closer to 1GB\r\n\r\nNew results\r\n```\r\n===== ========== =============\r\n--              mode          \r\n----- ------------------------\r\n  n     block     concatenate \r\n===== ========== =============\r\n  1    74.0±2μs    2.03±0.1μs \r\n  10   150±6μs      37.6±1μs  \r\n 100   366±7ms      393±10ms  \r\n===== ========== =============\r\n```\r\n\r\n(I'm pretty convinced that the difference in time here between block and concatenate for n=100 is artificial, though not sure how to prove it.)\r\n\r\nImprovement compared to the old results\r\n\r\n```\r\nasv continuous -E conda:3.6 -b Block.time_3d master block_single_concatenate_call \r\n```\r\n```\r\n       before           after         ratio\r\n     [b5f56572]       [a2b4b356]\r\n     <master>         <block_single_concatenate_call>\r\n+      40.7±0.2μs         74.0±2μs     1.82  bench_shape_base.Block.time_3d(1, 'block')\r\n-      1.10±0.02s          366±7ms     0.33  bench_shape_base.Block.time_3d(100, 'block')\r\n-        681±20μs          150±6μs     0.22  bench_shape_base.Block.time_3d(10, 'block')\r\n```\r\n\r\n</details>\r\n\r\n# Extensions\r\n## Unblocking\r\n@eric-wieser discussed the possibility of using this algorithm to `unblock` arrays. This is rather straightforward to implement once we lock down the implementation. Details are in the comments below\r\n\r\n## User friendly options\r\nFinally, this probably lends itself well to offering options like `order`, which would allow one to choose the order of the final array, or even to specify the array that they want to provide through an `out` parameter.\r\n\r\n\r\nClosures are avoided entirely, so I  think that gh-10620 is not an issue.","created_at":"2018-09-17T05:48:32Z","updated_at":"2018-10-17T03:43:46Z","closed_at":null,"merged_at":null,"merge_commit_sha":"438bd79ee021b6d86fcd7ac40463a3643f7d5825","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":36825825,"node_id":"MDU6TGFiZWwzNjgyNTgyNQ==","url":"https://api.github.com/repos/numpy/numpy/labels/03%20-%20Maintenance","name":"03 - Maintenance","color":"fef2c0","default":false},{"id":16917029,"node_id":"MDU6TGFiZWwxNjkxNzAyOQ==","url":"https://api.github.com/repos/numpy/numpy/labels/component:%20numpy.core","name":"component: numpy.core","color":"009800","default":false}],"milestone":null,"commits_url":"https://api.github.com/repos/numpy/numpy/pulls/11971/commits","review_comments_url":"https://api.github.com/repos/numpy/numpy/pulls/11971/comments","review_comment_url":"https://api.github.com/repos/numpy/numpy/pulls/comments{/number}","comments_url":"https://api.github.com/repos/numpy/numpy/issues/11971/comments","statuses_url":"https://api.github.com/repos/numpy/numpy/statuses/b2db60c202928e05599f7612da5461e34400a97c","head":{"label":"hmaarrfk:block_single_concatenate_call","ref":"block_single_concatenate_call","sha":"b2db60c202928e05599f7612da5461e34400a97c","user":{"login":"hmaarrfk","id":90008,"node_id":"MDQ6VXNlcjkwMDA4","avatar_url":"https://avatars0.githubusercontent.com/u/90008?v=4","gravatar_id":"","url":"https://api.github.com/users/hmaarrfk","html_url":"https://github.com/hmaarrfk","followers_url":"https://api.github.com/users/hmaarrfk/followers","following_url":"https://api.github.com/users/hmaarrfk/following{/other_user}","gists_url":"https://api.github.com/users/hmaarrfk/gists{/gist_id}","starred_url":"https://api.github.com/users/hmaarrfk/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hmaarrfk/subscriptions","organizations_url":"https://api.github.com/users/hmaarrfk/orgs","repos_url":"https://api.github.com/users/hmaarrfk/repos","events_url":"https://api.github.com/users/hmaarrfk/events{/privacy}","received_events_url":"https://api.github.com/users/hmaarrfk/received_events","type":"User","site_admin":false},"repo":{"id":135739763,"node_id":"MDEwOlJlcG9zaXRvcnkxMzU3Mzk3NjM=","name":"numpy","full_name":"hmaarrfk/numpy","private":false,"owner":{"login":"hmaarrfk","id":90008,"node_id":"MDQ6VXNlcjkwMDA4","avatar_url":"https://avatars0.githubusercontent.com/u/90008?v=4","gravatar_id":"","url":"https://api.github.com/users/hmaarrfk","html_url":"https://github.com/hmaarrfk","followers_url":"https://api.github.com/users/hmaarrfk/followers","following_url":"https://api.github.com/users/hmaarrfk/following{/other_user}","gists_url":"https://api.github.com/users/hmaarrfk/gists{/gist_id}","starred_url":"https://api.github.com/users/hmaarrfk/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hmaarrfk/subscriptions","organizations_url":"https://api.github.com/users/hmaarrfk/orgs","repos_url":"https://api.github.com/users/hmaarrfk/repos","events_url":"https://api.github.com/users/hmaarrfk/events{/privacy}","received_events_url":"https://api.github.com/users/hmaarrfk/received_events","type":"User","site_admin":false},"html_url":"https://github.com/hmaarrfk/numpy","description":"Numpy main repository","fork":true,"url":"https://api.github.com/repos/hmaarrfk/numpy","forks_url":"https://api.github.com/repos/hmaarrfk/numpy/forks","keys_url":"https://api.github.com/repos/hmaarrfk/numpy/keys{/key_id}","collaborators_url":"https://api.github.com/repos/hmaarrfk/numpy/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/hmaarrfk/numpy/teams","hooks_url":"https://api.github.com/repos/hmaarrfk/numpy/hooks","issue_events_url":"https://api.github.com/repos/hmaarrfk/numpy/issues/events{/number}","events_url":"https://api.github.com/repos/hmaarrfk/numpy/events","assignees_url":"https://api.github.com/repos/hmaarrfk/numpy/assignees{/user}","branches_url":"https://api.github.com/repos/hmaarrfk/numpy/branches{/branch}","tags_url":"https://api.github.com/repos/hmaarrfk/numpy/tags","blobs_url":"https://api.github.com/repos/hmaarrfk/numpy/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/hmaarrfk/numpy/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/hmaarrfk/numpy/git/refs{/sha}","trees_url":"https://api.github.com/repos/hmaarrfk/numpy/git/trees{/sha}","statuses_url":"https://api.github.com/repos/hmaarrfk/numpy/statuses/{sha}","languages_url":"https://api.github.com/repos/hmaarrfk/numpy/languages","stargazers_url":"https://api.github.com/repos/hmaarrfk/numpy/stargazers","contributors_url":"https://api.github.com/repos/hmaarrfk/numpy/contributors","subscribers_url":"https://api.github.com/repos/hmaarrfk/numpy/subscribers","subscription_url":"https://api.github.com/repos/hmaarrfk/numpy/subscription","commits_url":"https://api.github.com/repos/hmaarrfk/numpy/commits{/sha}","git_commits_url":"https://api.github.com/repos/hmaarrfk/numpy/git/commits{/sha}","comments_url":"https://api.github.com/repos/hmaarrfk/numpy/comments{/number}","issue_comment_url":"https://api.github.com/repos/hmaarrfk/numpy/issues/comments{/number}","contents_url":"https://api.github.com/repos/hmaarrfk/numpy/contents/{+path}","compare_url":"https://api.github.com/repos/hmaarrfk/numpy/compare/{base}...{head}","merges_url":"https://api.github.com/repos/hmaarrfk/numpy/merges","archive_url":"https://api.github.com/repos/hmaarrfk/numpy/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/hmaarrfk/numpy/downloads","issues_url":"https://api.github.com/repos/hmaarrfk/numpy/issues{/number}","pulls_url":"https://api.github.com/repos/hmaarrfk/numpy/pulls{/number}","milestones_url":"https://api.github.com/repos/hmaarrfk/numpy/milestones{/number}","notifications_url":"https://api.github.com/repos/hmaarrfk/numpy/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/hmaarrfk/numpy/labels{/name}","releases_url":"https://api.github.com/repos/hmaarrfk/numpy/releases{/id}","deployments_url":"https://api.github.com/repos/hmaarrfk/numpy/deployments","created_at":"2018-06-01T16:21:29Z","updated_at":"2018-10-15T04:29:00Z","pushed_at":"2018-10-17T02:12:20Z","git_url":"git://github.com/hmaarrfk/numpy.git","ssh_url":"git@github.com:hmaarrfk/numpy.git","clone_url":"https://github.com/hmaarrfk/numpy.git","svn_url":"https://github.com/hmaarrfk/numpy","homepage":"http://www.numpy.org/","size":59991,"stargazers_count":0,"watchers_count":0,"language":"C","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":2,"license":{"key":"other","name":"Other","spdx_id":"NOASSERTION","url":null,"node_id":"MDc6TGljZW5zZTA="},"forks":0,"open_issues":2,"watchers":0,"default_branch":"master"}},"base":{"label":"numpy:master","ref":"master","sha":"dc9b616828f7eda0a932319a24cd61c3a39598c4","user":{"login":"numpy","id":288276,"node_id":"MDEyOk9yZ2FuaXphdGlvbjI4ODI3Ng==","avatar_url":"https://avatars2.githubusercontent.com/u/288276?v=4","gravatar_id":"","url":"https://api.github.com/users/numpy","html_url":"https://github.com/numpy","followers_url":"https://api.github.com/users/numpy/followers","following_url":"https://api.github.com/users/numpy/following{/other_user}","gists_url":"https://api.github.com/users/numpy/gists{/gist_id}","starred_url":"https://api.github.com/users/numpy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/numpy/subscriptions","organizations_url":"https://api.github.com/users/numpy/orgs","repos_url":"https://api.github.com/users/numpy/repos","events_url":"https://api.github.com/users/numpy/events{/privacy}","received_events_url":"https://api.github.com/users/numpy/received_events","type":"Organization","site_admin":false},"repo":{"id":908607,"node_id":"MDEwOlJlcG9zaXRvcnk5MDg2MDc=","name":"numpy","full_name":"numpy/numpy","private":false,"owner":{"login":"numpy","id":288276,"node_id":"MDEyOk9yZ2FuaXphdGlvbjI4ODI3Ng==","avatar_url":"https://avatars2.githubusercontent.com/u/288276?v=4","gravatar_id":"","url":"https://api.github.com/users/numpy","html_url":"https://github.com/numpy","followers_url":"https://api.github.com/users/numpy/followers","following_url":"https://api.github.com/users/numpy/following{/other_user}","gists_url":"https://api.github.com/users/numpy/gists{/gist_id}","starred_url":"https://api.github.com/users/numpy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/numpy/subscriptions","organizations_url":"https://api.github.com/users/numpy/orgs","repos_url":"https://api.github.com/users/numpy/repos","events_url":"https://api.github.com/users/numpy/events{/privacy}","received_events_url":"https://api.github.com/users/numpy/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/numpy/numpy","description":"Numpy main repository","fork":false,"url":"https://api.github.com/repos/numpy/numpy","forks_url":"https://api.github.com/repos/numpy/numpy/forks","keys_url":"https://api.github.com/repos/numpy/numpy/keys{/key_id}","collaborators_url":"https://api.github.com/repos/numpy/numpy/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/numpy/numpy/teams","hooks_url":"https://api.github.com/repos/numpy/numpy/hooks","issue_events_url":"https://api.github.com/repos/numpy/numpy/issues/events{/number}","events_url":"https://api.github.com/repos/numpy/numpy/events","assignees_url":"https://api.github.com/repos/numpy/numpy/assignees{/user}","branches_url":"https://api.github.com/repos/numpy/numpy/branches{/branch}","tags_url":"https://api.github.com/repos/numpy/numpy/tags","blobs_url":"https://api.github.com/repos/numpy/numpy/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/numpy/numpy/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/numpy/numpy/git/refs{/sha}","trees_url":"https://api.github.com/repos/numpy/numpy/git/trees{/sha}","statuses_url":"https://api.github.com/repos/numpy/numpy/statuses/{sha}","languages_url":"https://api.github.com/repos/numpy/numpy/languages","stargazers_url":"https://api.github.com/repos/numpy/numpy/stargazers","contributors_url":"https://api.github.com/repos/numpy/numpy/contributors","subscribers_url":"https://api.github.com/repos/numpy/numpy/subscribers","subscription_url":"https://api.github.com/repos/numpy/numpy/subscription","commits_url":"https://api.github.com/repos/numpy/numpy/commits{/sha}","git_commits_url":"https://api.github.com/repos/numpy/numpy/git/commits{/sha}","comments_url":"https://api.github.com/repos/numpy/numpy/comments{/number}","issue_comment_url":"https://api.github.com/repos/numpy/numpy/issues/comments{/number}","contents_url":"https://api.github.com/repos/numpy/numpy/contents/{+path}","compare_url":"https://api.github.com/repos/numpy/numpy/compare/{base}...{head}","merges_url":"https://api.github.com/repos/numpy/numpy/merges","archive_url":"https://api.github.com/repos/numpy/numpy/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/numpy/numpy/downloads","issues_url":"https://api.github.com/repos/numpy/numpy/issues{/number}","pulls_url":"https://api.github.com/repos/numpy/numpy/pulls{/number}","milestones_url":"https://api.github.com/repos/numpy/numpy/milestones{/number}","notifications_url":"https://api.github.com/repos/numpy/numpy/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/numpy/numpy/labels{/name}","releases_url":"https://api.github.com/repos/numpy/numpy/releases{/id}","deployments_url":"https://api.github.com/repos/numpy/numpy/deployments","created_at":"2010-09-13T23:02:39Z","updated_at":"2018-10-17T03:41:03Z","pushed_at":"2018-10-17T03:40:08Z","git_url":"git://github.com/numpy/numpy.git","ssh_url":"git@github.com:numpy/numpy.git","clone_url":"https://github.com/numpy/numpy.git","svn_url":"https://github.com/numpy/numpy","homepage":"https://www.numpy.org/","size":61201,"stargazers_count":8381,"watchers_count":8381,"language":"C","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":3045,"mirror_url":null,"archived":false,"open_issues_count":2002,"license":{"key":"other","name":"Other","spdx_id":"NOASSERTION","url":null,"node_id":"MDc6TGljZW5zZTA="},"forks":3045,"open_issues":2002,"watchers":8381,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/numpy/numpy/pulls/11971"},"html":{"href":"https://github.com/numpy/numpy/pull/11971"},"issue":{"href":"https://api.github.com/repos/numpy/numpy/issues/11971"},"comments":{"href":"https://api.github.com/repos/numpy/numpy/issues/11971/comments"},"review_comments":{"href":"https://api.github.com/repos/numpy/numpy/pulls/11971/comments"},"review_comment":{"href":"https://api.github.com/repos/numpy/numpy/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/numpy/numpy/pulls/11971/commits"},"statuses":{"href":"https://api.github.com/repos/numpy/numpy/statuses/b2db60c202928e05599f7612da5461e34400a97c"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"eric-wieser"}}