'Fit model to data.
Parameters
X : array-like, shape = [n_samples, n_features]
Training vectors, where n_samples is the number of samples and
n_features is the number of predictors.
Y : array-like, shape = [n_samples, n_targets]
Target vectors, where n_samples is the number of samples and
n_targets is the number of response variables.'

def fit(self, X, Y):

    check_consistent_length(X, Y)
    X = check_array(X, dtype=np.float64, copy=self.copy)
    Y = check_array(Y, dtype=np.float64, copy=self.copy, ensure_2d=False)
    if (Y.ndim == 1):
        Y = Y.reshape((-1), 1)
    n = X.shape[0]
    p = X.shape[1]
    q = Y.shape[1]
    if ((self.n_components < 1) or (self.n_components > p)):
        raise ValueError(('Invalid    number    of    components:    %d' % self.n_components))
    if (self.algorithm not in ('svd', 'nipals')):
        raise ValueError(("Got    algorithm    %s    when    only    'svd'    and    'nipals'    are    known" % self.algorithm))
    if ((self.algorithm == 'svd') and (self.mode == 'B')):
        raise ValueError('Incompatible    configuration:    mode    B    is    not    implemented    with    svd    algorithm')
    if (self.deflation_mode not in ['canonical', 'regression']):
        raise ValueError('The    deflation    mode    is    unknown')
    (X, Y, self.x_mean_, self.y_mean_, self.x_std_, self.y_std_) = _center_scale_xy(X, Y, self.scale)
    Xk = X
    Yk = Y
    self.x_scores_ = np.zeros((n, self.n_components))
    self.y_scores_ = np.zeros((n, self.n_components))
    self.x_weights_ = np.zeros((p, self.n_components))
    self.y_weights_ = np.zeros((q, self.n_components))
    self.x_loadings_ = np.zeros((p, self.n_components))
    self.y_loadings_ = np.zeros((q, self.n_components))
    self.n_iter_ = []
    for k in range(self.n_components):
        if np.all((np.dot(Yk.T, Yk) < np.finfo(np.double).eps)):
            warnings.warn(('Y    residual    constant    at    iteration    %s' % k))
            break
        if (self.algorithm == 'nipals'):
            (x_weights, y_weights, n_iter_) = _nipals_twoblocks_inner_loop(X=Xk, Y=Yk, mode=self.mode, max_iter=self.max_iter, tol=self.tol, norm_y_weights=self.norm_y_weights)
            self.n_iter_.append(n_iter_)
        elif (self.algorithm == 'svd'):
            (x_weights, y_weights) = _svd_cross_product(X=Xk, Y=Yk)
        (x_weights, y_weights) = svd_flip(x_weights, y_weights.T)
        y_weights = y_weights.T
        x_scores = np.dot(Xk, x_weights)
        if self.norm_y_weights:
            y_ss = 1
        else:
            y_ss = np.dot(y_weights.T, y_weights)
        y_scores = (np.dot(Yk, y_weights) / y_ss)
        if (np.dot(x_scores.T, x_scores) < np.finfo(np.double).eps):
            warnings.warn(('X    scores    are    null    at    iteration    %s' % k))
            break
        x_loadings = (np.dot(Xk.T, x_scores) / np.dot(x_scores.T, x_scores))
        Xk -= np.dot(x_scores, x_loadings.T)
        if (self.deflation_mode == 'canonical'):
            y_loadings = (np.dot(Yk.T, y_scores) / np.dot(y_scores.T, y_scores))
            Yk -= np.dot(y_scores, y_loadings.T)
        if (self.deflation_mode == 'regression'):
            y_loadings = (np.dot(Yk.T, x_scores) / np.dot(x_scores.T, x_scores))
            Yk -= np.dot(x_scores, y_loadings.T)
        self.x_scores_[:, k] = x_scores.ravel()
        self.y_scores_[:, k] = y_scores.ravel()
        self.x_weights_[:, k] = x_weights.ravel()
        self.y_weights_[:, k] = y_weights.ravel()
        self.x_loadings_[:, k] = x_loadings.ravel()
        self.y_loadings_[:, k] = y_loadings.ravel()
    self.x_rotations_ = np.dot(self.x_weights_, pinv2(np.dot(self.x_loadings_.T, self.x_weights_), check_finite=False))
    if (Y.shape[1] > 1):
        self.y_rotations_ = np.dot(self.y_weights_, pinv2(np.dot(self.y_loadings_.T, self.y_weights_), check_finite=False))
    else:
        self.y_rotations_ = np.ones(1)
    if (True or (self.deflation_mode == 'regression')):
        self.coef_ = np.dot(self.x_rotations_, self.y_loadings_.T)
        self.coef_ = (self.coef_ * self.y_std_)
    return self
