Skip to content

Commit 6e7ccfc

Browse files
author
pevnak
committed
Merge branch '2025W' of github.com:JuliaTeachingCTU/Scientific-Programming-in-Julia into 2025W
2 parents 281154b + 9a455c2 commit 6e7ccfc

File tree

2 files changed

+40
-1
lines changed

2 files changed

+40
-1
lines changed

docs/make.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ pages = [
5050
"6: Language introspection" => "lecture_06/lecture.md",
5151
"7: Macros" => "lecture_07/lecture.md",
5252
"8: Automatic differentiation 1" => "lecture_08/lecture.md",
53-
"9: Automatic differentiation 2" => "lecture_09/lecture_v2.md"
53+
"9: Automatic differentiation 2" => "lecture_09/lecture_v2.md",
5454
"X: Manipulating Intermediate Represenation (IR)" => "lecture_09/lecture_v1.md"
5555
]),
5656
"Labs" => add_prefix("./lectures", [

docs/src/lectures/lecture_09/lab.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,45 @@ end
5858
### Tangent types
5959
The types of tangents and cotangents depend on the types of the primals. However, sometimes our functions may have arguments which derivatives we can not compute or do not need. In that case, we represent it as `NoTangent`. `ZeroTangent` is used when tangent is equal to zero.
6060

61+
!!! note "Quick rrule recipe (template)"
62+
1. Compute the primal output `y = f(args...)`.
63+
2. Capture any intermediate values you need for the backward pass.
64+
3. Return `(y, pullback)` where `pullback(ȳ)` returns a tuple of tangents for `(f, args...)`.
65+
4. Use `NoTangent()` for arguments that are not differentiable and `ZeroTangent()` when appropriate.
66+
67+
Minimal template:
68+
69+
```julia
70+
function ChainRulesCore.rrule(::typeof(f), arg1::A, arg2::B) where {A,B}
71+
# 1) primal
72+
y = f(arg1, arg2)
73+
74+
# 2) capture intermediates if needed
75+
# e.g. cached = some_intermediate(arg1, arg2)
76+
77+
# 3) define pullback
78+
function pullback(ȳ)
79+
# compute cotangents for args; shapes must match original args
80+
∂arg1 = ... # same shape/type as arg1
81+
∂arg2 = ... # same shape/type as arg2
82+
# first return value corresponds to the function object itself
83+
return NoTangent(), ∂arg1, ∂arg2
84+
end
85+
86+
return y, pullback
87+
end
88+
89+
```
90+
91+
!!! note "General Hints for rrules"
92+
- Always return `NoTangent()` as the first element in the pullback tuple (it denotes the function object).
93+
- Use `similar(x)` or `zeros(eltype(x), size(x))` for cotangent buffers to preserve type/shape.
94+
- Use `.+=` when writing into `` if segments can overlap (prevents losing accumulated contributions).
95+
- Watch out for shapes: `Δy` passed to pullback has exactly the same shape as `y`.
96+
- For reductions (`sum/maximum`), think which inputs share the same contribution and broadcast the cotangent accordingly.
97+
- For `maxima/argmax`: decide tie semantics (equal split vs first index) and document your choice.
98+
- Mutating primals inside pullbacks breaks the purity assumption — avoid it.
99+
61100

62101
!!! warning "Exercise"
63102
```@example lab09

0 commit comments

Comments
 (0)