Skip to content

Make views of TrackedArray return a TrackedArray - #291

Merged
devmotion merged 3 commits into
masterfrom
worktree-squishy-exploring-bird
Sep 16, 2026
Merged

devmotion merged 3 commits into
masterfrom
worktree-squishy-exploring-bird

Conversation

@devmotion

Copy link
Copy Markdown
Member

Fixes #281.

Base.view had no TrackedArray method, so it returned a SubArray of TrackedReals — an array of individually tracked scalars rather than a single tracked array. Every subsequent operation then recorded one instruction per element, so the tape grew linearly with the size of the view:

d x[2:end] @view x[2:end]
10 2 8
100 2 98
1000 2 998

view now returns a TrackedArray backed by views of the parent's value and deriv arrays. Since the deriv array is shared with the parent, derivatives accumulate into the parent directly and no instruction has to be recorded at all — the tape length becomes 1 and is constant in d. Views that are not IndexLinear cannot back a TrackedArray and are materialized through getindex instead.

Gradient timings from the issue:

d before after
10 250 ns 41 ns
100 2666 ns 83 ns
1000 27750 ns 750 ns

This also fixes logical indexing in the generic getindex, which is a separate pre-existing bug: since Bool <: Integer, masks were routed there but never normalized, so false indexed element 0 and x[mask] threw a BoundsError. Indices are now normalized with Base.to_indices, which handles Colons and masks axis-aware and covers whole-array logical indexing such as m[mask]. The view fix relies on this, since logical views are not IndexLinear and so go through getindex.

🤖 Generated with Claude Code

`Base.view` had no `TrackedArray` method, so it fell through to the generic
`SubArray` constructor and returned a `SubArray` of `TrackedReal`s. That is an
array of individually tracked scalars rather than a single tracked array, so
every subsequent operation recorded one instruction per element and the tape
grew linearly with the size of the view.

`view` now returns a `TrackedArray` backed by views of the parent's value and
deriv arrays. Since the deriv array is shared with the parent, derivatives
accumulate into the parent directly and no instruction has to be recorded at
all. Views that are not `IndexLinear` cannot back a `TrackedArray` and are
materialized through `getindex` instead.

This also fixes logical indexing in the generic `getindex`: since
`Bool <: Integer`, masks were routed there but never normalized, so `false`
indexed element 0 and `x[mask]` threw a `BoundsError`. Indices are now
normalized with `Base.to_indices`.

Fixes #281

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@codecov

codecov Bot commented Sep 15, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 85.91%. Comparing base (bc2227e) to head (679f970).
⚠️ Report is 3 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #291      +/-   ##
==========================================
+ Coverage   85.10%   85.91%   +0.80%     
==========================================
  Files          18       18              
  Lines        1914     1945      +31     
==========================================
+ Hits         1629     1671      +42     
+ Misses        285      274      -11     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

devmotion and others added 2 commits September 15, 2026 13:14
`BitVector(::Tuple)` needs `BitArray{1}(itr)`, which Julia 1.0 does not
define — it has only the unparameterized `BitArray(itr)`. Construct from
a `Vector{Bool}` literal instead, which hits `BitArray{1}(::Array{Bool,1})`
and works on all supported versions.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@devmotion
devmotion merged commit 7da338c into master Sep 16, 2026
7 checks passed
@devmotion
devmotion deleted the worktree-squishy-exploring-bird branch September 16, 2026 07:46
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.

Views are unperformant

1 participant