Skip to content

Commit 161e01f

Browse files
Elvand-Lievgvassilev
authored andcommitted
Fix reverse division tape use in loops
Materialize the reverse-sweep divisor once before reusing it in division adjoints, avoiding forward push reuse and duplicate tape pops. Add a regression for inline divisor loops and named quotient cases. Fixes: #1865
1 parent 496c05f commit 161e01f

2 files changed

Lines changed: 61 additions & 4 deletions

File tree

lib/Differentiator/ReverseModeVisitor.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2690,9 +2690,12 @@ Expr* ReverseModeVisitor::getStdInitListSizeExpr(const Expr* E) {
26902690
auto RDelayed = DelayedGlobalStoreAndRef(R, /*prefix=*/"_t",
26912691
/*forceStore=*/true);
26922692
StmtDiff& RResult = RDelayed.Result;
2693+
Expr* RRev = RResult.getRevSweepAsExpr();
2694+
if (dfdx())
2695+
RRev = StoreAndRef(RRev, direction::reverse);
26932696
Expr* dl = nullptr;
26942697
if (dfdx())
2695-
dl = BuildOp(BO_Div, dfdx(), RResult.getExpr());
2698+
dl = BuildOp(BO_Div, dfdx(), Clone(RRev));
26962699
Ldiff = Visit(L, dl);
26972700
StmtDiff LStored = Ldiff;
26982701
// Catch the pop statement and emit it after
@@ -2715,8 +2718,7 @@ Expr* ReverseModeVisitor::getStdInitListSizeExpr(const Expr* E) {
27152718
// produced instead of 1 / (R * R).
27162719
Expr* dr = nullptr;
27172720
if (dfdx()) {
2718-
Expr* RxR = BuildParens(
2719-
BuildOp(BO_Mul, RResult.getExpr(), RResult.getExpr()));
2721+
Expr* RxR = BuildParens(BuildOp(BO_Mul, RRev, Clone(RRev)));
27202722
dr = BuildOp(BO_Mul, dfdx(),
27212723
BuildOp(UO_Minus,
27222724
BuildParens(BuildOp(
@@ -2882,7 +2884,7 @@ Expr* ReverseModeVisitor::getStdInitListSizeExpr(const Expr* E) {
28822884
direction::reverse);
28832885
if (isInsideLoop)
28842886
addToCurrentBlock(LCloned, direction::forward);
2885-
Expr* RxR = BuildParens(BuildOp(BO_Mul, RStored, RStored));
2887+
Expr* RxR = BuildParens(BuildOp(BO_Mul, RStored, Clone(RStored)));
28862888
Expr* dr = BuildOp(BO_Mul, oldValue,
28872889
BuildOp(UO_Minus, BuildOp(BO_Div, LCloned, RxR)));
28882890
dr = StoreAndRef(dr, direction::reverse);

test/Regressions/issue-1865.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// RUN: %cladclang -std=c++17 -I%S/../../include %s -o %t 2>&1 | %filecheck %s
2+
// RUN: %t | %filecheck_exec %s
3+
// XFAIL: valgrind
4+
5+
#include "clad/Differentiator/Differentiator.h"
6+
#include <cstdio>
7+
8+
double inline_divisor_2(double* p) {
9+
double a = p[0], s = 0.0;
10+
for (int i = 0; i < 2; ++i) {
11+
double x = i + 1.0;
12+
s += 1.0 / (x + a * a);
13+
}
14+
return s;
15+
}
16+
17+
// CHECK: void inline_divisor_2_grad(double *p, double *_d_p) {
18+
// CHECK: double _r{{[0-9]+}} = clad::pop(_t{{[0-9]+}});
19+
// CHECK-NEXT: double _r{{[0-9]+}} = _d_s * -(1. / (_r{{[0-9]+}} * _r{{[0-9]+}}));
20+
21+
// Correct at one iteration before #1865, wrong for two or more.
22+
double inline_divisor_3(double* p) {
23+
double a = p[0], s = 0.0;
24+
for (int i = 0; i < 3; ++i) {
25+
double x = i + 1.0;
26+
s += 1.0 / (x + a * a);
27+
}
28+
return s;
29+
}
30+
31+
// Naming the quotient did not avoid #1865.
32+
double named_quotient_4(double* p) {
33+
double a = p[0], s = 0.0;
34+
for (int i = 0; i < 4; ++i) {
35+
double x = i + 1.0;
36+
double r = 1.0 / (x + a * a);
37+
s += r;
38+
}
39+
return s;
40+
}
41+
42+
#define CHECK_GRAD(F) \
43+
do { \
44+
auto grad = clad::gradient(F, "p"); \
45+
double p[1] = {1.3}; \
46+
double d[1] = {0.0}; \
47+
grad.execute(p, d); \
48+
printf(#F " %.6f\n", d[0]); \
49+
} while (0)
50+
51+
int main() {
52+
CHECK_GRAD(inline_divisor_2); // CHECK-EXEC: inline_divisor_2 -0.550260
53+
CHECK_GRAD(inline_divisor_3); // CHECK-EXEC: inline_divisor_3 -0.668463
54+
CHECK_GRAD(named_quotient_4); // CHECK-EXEC: named_quotient_4 -0.748769
55+
}

0 commit comments

Comments
 (0)