code: def _prepare_data_XY(self, X, Y, D, F):
          
          XTY, XTDY, XTFY = self._make_templates(D, F, X, Y)
  
          YTY_diag = np.sum(Y * Y, axis=0)
          YTDY_diag = np.sum(Y * np.dot(D, Y), axis=0)
          YTFY_diag = np.sum(Y * np.dot(F, Y), axis=0)
  
          XTX, XTDX, XTFX = self._make_templates(D, F, X, X)
  
          return XTY, XTDY, XTFY, YTY_diag, YTDY_diag, YTFY_diag, XTX, \
              XTDX, XTFX
docs: Prepares different forms of products of design matrix X
              and data Y, or between themselves.
              These products are re-used a lot during fitting.
              So we pre-calculate them. Because these are reused,
              it is in principle possible to update the fitting
              as new data come in, by just incrementally adding
              the products of new data and their corresponding parts
              of design matrix to these pre-calculated terms.