Adjoint operators |
The filter impulse response is seen in any column in the middle of the matrix, namely . In the transposed matrix, the filter-impulse response is time-reversed to . So, mathematically, we can say that the adjoint of the time derivative operation is the negative time derivative. This corresponds also to the fact that the complex conjugate of is . We can also speak of the adjoint of the boundary conditions: we might say that the adjoint of ``no boundary condition'' is a ``specified value'' boundary condition.
A complicated way to think about the adjoint of equation (2.3) is to note that it is the negative of the derivative and that something must be done about the ends. A simpler way to think about it is to apply the idea that the adjoint of a sum of terms is a collection of assignments. This is done in subroutine igrad1(), which implements equation (2.3) and its adjoint.
void sf_igrad1_lop(bool adj, bool add, int nx, int ny, float *xx, float *yy) /*< linear operator >*/ { int i; sf_adjnull(adj,add,nx,ny,xx,yy); for (i=0; i < nx-1; i++) { if (adj) { xx[i+1] += yy[i]; xx[i] -= yy[i]; } else { yy[i] += xx[i+1] - xx[i]; } } } |
Notice that the do loop in the code covers all the outputs for the operator itself, and that in the adjoint operation it gathers all the inputs. This is natural because in switching from operator to adjoint, the outputs switch to inputs.
As you look at the code, think about matrix elements being or and think about the forward operator ``pulling'' a sum into yy(i), and think about the adjoint operator ``pushing'' or ``spraying'' the impulse yy(i) back into xx().
You might notice that you can simplify the program by merging the ``erase output'' activity with the calculation itself. We will not do this optimization however because in many applications we do not want to include the ``erase output'' activity. This often happens when we build complicated operators from simpler ones.
Adjoint operators |