Calculates the Within-Class Scatter matrix
    
    Parameters:
    -----------
    X : array-like, shape (m, n) - the samples
    y : array-like, shape (m, ) - the class labels
    
    Returns:
    --------
    within_class_scatter_matrix : array-like, shape (n, n)

def calculate_within_class_scatter_matrix(X, y):
    """Calculates the Within-Class Scatter matrix
    
    Parameters:
    -----------
    X : array-like, shape (m, n) - the samples
    y : array-like, shape (m, ) - the class labels
    
    Returns:
    --------
    within_class_scatter_matrix : array-like, shape (n, n)
    
    """

    mean_vectors = calculate_mean_vectors(X, y)
    n_features = X.shape[1]
    Sw = np.zeros((n_features, n_features))

    for cl, m in zip(np.unique(y), mean_vectors):
        Si = np.zeros((n_features, n_features))
        m = m.reshape(n_features, 1)

        for x in X[y == cl, :]:
            v = x.reshape(n_features, 1) - m
            Si += v @ v.T
        Sw += Si

    return Sw