%% Compute Gradients Involving Complex Numbers
% Use dlgradient and dlfeval to compute the value and gradient of a function that involves complex numbers. You can compute complex gradients, or restrict the gradients to real numbers only.
% Define the function complexFun, listed at the end of this example. This function implements the following complex formula:
% f\left(x\right)=\left(2+3i\right)x
% Define the function gradFun, listed at the end of this example. This function calls complexFun and uses dlgradient to calculate the gradient of the result with respect to the input. For automatic differentiation, the value to differentiate — i.e., the value of the function calculated from the input — must be a real scalar, so the function takes the sum of the real part of the result before calculating the gradient. The function returns the real part of the function value and the gradient, which can be complex.
% Define the sample points over the complex plane between -2 and 2 and -2i and 2i and convert to dlarray.

functionRes = linspace(-2,2,100);
x = functionRes + 1i*functionRes.';
x = dlarray(x);

% Calculate the function value and gradient at each sample point.

[y, grad] = dlfeval(@gradFun,x);
y = extractdata(y);

% Define the sample points at which to display the gradient.

gradientRes = linspace(-2,2,11);
xGrad = gradientRes + 1i*gradientRes.';

%  Extract the gradient values at these sample points.

[~,gradPlot] = dlfeval(@gradFun,dlarray(xGrad));
gradPlot = extractdata(gradPlot);

% Plot the results. Use imagesc to show the value of the function over the complex plane. Use quiver to show the direction and magnitude of the gradient.

imagesc([-2,2],[-2,2],y);
axis xy
colorbar
hold on
quiver(real(xGrad),imag(xGrad),real(gradPlot),imag(gradPlot),"k");
xlabel("Real")
ylabel("Imaginary")
title("Real Value and Gradient","Re$(f(x)) = $ Re$((2+3i)x)$","interpreter","latex")

% The gradient of the function is the same across the entire complex plane. Extract the value of the gradient calculated by automatic differentation.

grad(1,1)

% By inspection, the complex derivative of the function has the value
% \frac{\textrm{df}\left(x\right)}{\textrm{dx}}=2+3i
% However, the function Re(f\left(x\right)) is not analytic, and therefore no complex derivative is defined. For automatic differentiation in MATLAB, the value to differentiate must always be real, and therefore the function can never be complex analytic. Instead, the derivative is computed such that the returned gradient points in the direction of steepest ascent, as seen in the plot. This is done by interpreting the function Re\left(f\left(x\right)\right): C \to R as a function Re\left(f\left(x_R +ix_I \right)\right): R \times R \to R.
%

function y = complexFun(x)
    y = (2+3i)*x;    
end

function [y,grad] = gradFun(x)
    y = complexFun(x);
    y = real(y);

    grad = dlgradient(sum(y,"all"),x);
end

% Copyright 2021 The MathWorks, Inc.
%
%