import math


def computeErrors(predictedRDD, actualRDD):
    """ Compute the RMSE and MAE between predicted and actual RDD
    Args:
        predictedRDD: predicted ratings for each movie and each user where each entry is in the form
                      (UserID, MovieID, Rating)
        actualRDD: actual ratings where each entry is in the form (UserID, MovieID, Rating)
    Returns:
        (RMSE, MAE)
        RMSE (float): computed RMSE value
        MAE (float): computed MAE value
    """
    # Transform predictedRDD into the tuples of the form ((UserID, MovieID), Rating)
    predictedReformattedRDD = predictedRDD.map(lambda rec: ((rec[0], rec[1]), rec[2]))
    # Transform actualRDD into the tuples of the form ((UserID, MovieID), Rating)
    actualReformattedRDD = actualRDD.map(lambda rec: ((rec[0], rec[1]), rec[2]))
    # Join the two RDD
    joinedRDD = predictedReformattedRDD.join(actualReformattedRDD)
    # Errors
    squaredErrorsRDD = joinedRDD.map(lambda x: (x[1][0] - x[1][1])*(x[1][0] - x[1][1]))
    absErrorsRDD = joinedRDD.map(lambda x: abs(x[1][0] - x[1][1]))
    # Compute the total error
    totalSquareError = squaredErrorsRDD.reduce(lambda v1, v2: v1 + v2)
    totalAbsoluteError = absErrorsRDD.reduce(lambda v1, v2: v1 + v2)
    # Count the number of entries for which you computed the total squared error
    numRatings = squaredErrorsRDD.count()
    return (math.sqrt(float(totalSquareError) / numRatings), float(totalAbsoluteError) / numRatings)