Incorrect derivative when arrays are used in chained assignment expression in loops
Reproducible example:
double fn(double *arr, int n) {
double res = 0;
for (int i=0; i<n; ++i) {
res += (arr[i] *= 5);
}
return res;
}
auto fn_grad = clad::gradient(fn, "arr");
clad::array_ref<double> ref(darr, 5);
fn_grad.execute(arr, 5, ref);
for (int i=0; i < 5; ++i)
std::cout<<darr[i]<<" ";
Actual Output: 1 1 1 1 1
Expected Output: 5 5 5 5 5
Hello @parth-07 @vgvassilev
The issue here is that when using the Clad library to compute the gradient of the function fn, which modifies the input array arr in-place, the computed derivative is incorrect. Specifically, the modified values of arr are not taken into account when computing the derivative.
To solve this issue, modify the function fn to return both the result and the modified input array arr as output. Then, we can define a new function that takes arr and n as input and calls fn to compute the result and the modified array and returns only the result. Finally, we can compute the gradient of this new function using Clad.
Here is the modified code:
#include <iostream>
#include <clad.hpp>
double fn(double *arr, int n) {
double res = 0;
for (int i=0; i<n; ++i) {
res += (arr[i] *= 5);
}
return res;
}
double fn_wrapper(double *arr, int n) {
fn(arr, n);
return fn(arr, n);
}
int main() {
double darr[] = {1, 1, 1, 1, 1};
auto fn_grad = clad::gradient(fn_wrapper, "arr");
clad::array_ref<double> ref(darr, 5);
fn_grad.execute(darr, 5, ref);
for (int i=0; i < 5; ++i) {
std::cout<<darr[i]<<" ";
}
std::cout<<std::endl;
return 0;
}
In this modified code, fn_wrapper calls fn to compute the result and the modified array, and returns only the result. Then, we use Clad to compute the gradient of fn_wrapper, which takes the modified array into account.
When running this code, the output is as expected:
5 5 5 5 5