def gradient_affine(self):
    """Gradient of L2 norm for affine matrices only"""

    numTransforms = len(self.centers)

    gradA_list = []

    Phi = DeformationCL(self.fixedCL)
    Phi.set_identity()

    CoordCL = [Phi.hx, Phi.hy, Phi.hz]

    for q in range(numTransforms):
      C = self.centers[q]
      r = self.radii[q]
      A = self.affines[q]
      T = self.translations[q]

      F = self.fixedCL.getROI(C, r)
      M = self.movingCL.getROI(C, r)

      XList = []
      for d in range(3):
        XList.append(CoordCL[d].getROI(C, r))

      DiffFM = F.subtract(M)

      GList = M.gradient()

      CF = numpy.array(F.shape, dtype=numpy.single) / 2.0

      if self.normalizeWeights:
        W = self.weights[q].divide(self.sum_weights.getROI(C, r))
      else:
        W = self._get_weights(F.shape, CF, r)

      #W = self.weights[q]
      #W = self._get_weights(F.shape, C, r)

      WD = W.multiply(DiffFM)

      gradA = numpy.zeros((3,3), dtype=numpy.single)
      for i in range(3):
        for j in range(3):
          GX = GList[i].multiply(XList[j])
          gradA[i,j] = -2.0 * WD.multiply(GX).sum()

      gradA_list.append(gradA)

    return gradA_list
  def gradient_anchor(self):
    """Gradient of L2 norm for anchor positions only"""

    numTransforms = len(self.centers)

    gradC_list = []

    Phi = DeformationCL(self.fixedCL)
    Phi.set_identity()

    CoordCL = [Phi.hx, Phi.hy, Phi.hz]

    for q in range(numTransforms):
      C = self.centers[q]
      r = self.radii[q]
      A = self.affines[q]
      T = self.translations[q]

      F = self.fixedCL.getROI(C, r)
      M = self.movingCL.getROI(C, r)

      XList = []
      for d in range(3):
        XList.append(CoordCL[d].getROI(C, r))

      DiffFM = F.subtract(M)

      GList = M.gradient()

      CF = numpy.array(F.shape, dtype=numpy.single) / 2.0

      if self.normalizeWeights:
        W = self.weights[q].divide(self.sum_weights.getROI(C, r))
      else:
        W = self._get_weights(F.shape, CF, r)

      #W = self.weights[q]
      #W = self._get_weights(F.shape, C, r)

      WD = W.multiply(DiffFM)

      gradC = numpy.zeros((3,), dtype=numpy.single)

      dot_G_XC = F.clone()
      dot_G_XC.fill(0.0)

      ATList = []

      for d in range(3):
        AT = F.clone()
        AT.fill(0.0)
        for j in range(3):
          Y = XList[d].clone()
          Y.scale(A[d,j])
          AT.add_inplace(Y)
        AT.shift(T[d])

        ATList.append(AT)

        XC = XList[d].clone()
        XC.shift(-C[d])
        XC.scale(2.0 / r[d]**2)

        dot_G_XC.add_inplace(GList[d].multiply(XC))

      for d in range(3):
        gradC[d] = -WD.multiply(ATList[d].multiply(dot_G_XC)).sum()

      gradC_list.append(gradC)

    return gradC_list
  def gradient(self):
    """Gradient of L2 norm"""

    numTransforms = len(self.centers)

    gradA_list = []
    gradT_list = []

    gradC_list = []
    gradR_list = []

    Phi = DeformationCL(self.fixedCL)
    Phi.set_identity()

    CoordCL = [Phi.hx, Phi.hy, Phi.hz]

    for q in range(numTransforms):
      C = self.centers[q]
      r = self.radii[q]
      A = self.affines[q]
      T = self.translations[q]

      F = self.fixedCL.getROI(C, r)
      M = self.movingCL.getROI(C, r)

      XList = []
      for d in range(3):
        XList.append(CoordCL[d].getROI(C, r))

      DiffFM = F.subtract(M)

      GList = M.gradient()

      CF = numpy.array(F.shape, dtype=numpy.single) / 2.0

      if self.normalizeWeights:
        W = self.weights[q].divide(self.sum_weights.getROI(C, r))
      else:
        W = self._get_weights(F.shape, CF, r)

      #W = self.weights[q]
      #W = self._get_weights(F.shape, C, r)

      WD = W.multiply(DiffFM)

      gradA = numpy.zeros((3,3), dtype=numpy.single)
      for i in range(3):
        for j in range(3):
          GX = GList[i].multiply(XList[j])
          gradA[i,j] = -2.0 * WD.multiply(GX).sum()

      gradT = numpy.zeros((3,), dtype=numpy.single)
      for d in range(3):
        gradT[d] = -2.0 * WD.multiply(GList[d]).sum()

      gradC = numpy.zeros((3,), dtype=numpy.single)
      gradR = numpy.zeros((3,), dtype=numpy.single)

      dot_AT_XC = F.clone()
      dot_AT_XC.fill(0.0)

      dot_AT_XR = F.clone()
      dot_AT_XR.fill(0.0)

      for d in range(3):
        AT = F.clone()
        AT.fill(0.0)
        for j in range(3):
          Y = XList[d].clone()
          Y.scale(A[d,j])
          AT.add_inplace(Y)
        AT.shift(T[d])

        XC = XList[d].clone()
        XC.shift(-C[d])
        XC.scale(2.0 / r[d]**2)

        dot_AT_XC.add_inplace(AT.multiply(XC))

        XR = XList[d].clone()
        XR.shift(-C[d])
        XR.scale(4.0 / r[d]**3)

        dot_AT_XR.add_inplace(AT.multiply(XR))

      for d in range(3):
        gradC[d] = -WD.multiply(GList[d].multiply(dot_AT_XC)).sum()
        gradR[d] = WD.multiply(GList[d].multiply(dot_AT_XR)).sum()

      gradA_list.append(gradA)
      gradT_list.append(gradT)

      gradC_list.append(gradC)
      gradR_list.append(gradR)

    return gradA_list, gradT_list, gradC_list, gradR_list