def fit_arrays(uv, xy):
    """ Performs a generalized fit between matched lists of positions
        given by the 2 column arrays xy and uv.

        This function fits for translation, rotation, and scale changes
        between 'xy' and 'uv', allowing for different scales and
        orientations for X and Y axes.

        =================================
        DEVELOPMENT NOTE:
            Checks need to be put in place to verify that
            enough objects are available for a fit.
        =================================

        Output:
           (Xo,Yo),Rot,(Scale,Sx,Sy)
           where
                Xo,Yo:  offset,
                Rot:    rotation,
                Scale:  average scale change, and
                Sx,Sy:  scale changes in X and Y separately.

        Algorithm and nomenclature provided by: Colin Cox (11 Nov 2004)
    """

    if not isinstance(xy,np.ndarray):
        # cast input list as numpy ndarray for fitting
        xy = np.array(xy)
    if not isinstance(uv,np.ndarray):
        # cast input list as numpy ndarray for fitting
        uv = np.array(uv)

    # Set up products used for computing the fit
    Sx = xy[:,0].sum()
    Sy = xy[:,1].sum()
    Su = uv[:,0].sum()
    Sv = uv[:,1].sum()

    Sux = np.dot(uv[:,0], xy[:,0])
    Svx = np.dot(uv[:,1], xy[:,0])
    Suy = np.dot(uv[:,0], xy[:,1])
    Svy = np.dot(uv[:,1], xy[:,1])
    Sxx = np.dot(xy[:,0], xy[:,0])
    Syy = np.dot(xy[:,1], xy[:,1])
    Sxy = np.dot(xy[:,0], xy[:,1])

    n = len(xy[:,0])
    M = np.array([[Sx, Sy, n], [Sxx, Sxy, Sx], [Sxy, Syy, Sy]])
    U = np.array([Su, Sux, Suy])
    V = np.array([Sv, Svx, Svy])

    # The fit solutioN...
    # where
    #   u = P0 + P1*x + P2*y
    #   v = Q0 + Q1*x + Q2*y
    #
    try:
        invM = np.linalg.inv(M.astype(np.float64))
    except np.linalg.LinAlgError:
        raise SingularMatrixError(
            "Singular matrix: suspected colinear points."
        )
    P = np.dot(invM, U).astype(np.float64)
    Q = np.dot(invM, V).astype(np.float64)
    if not (np.all(np.isfinite(P)) and np.all(np.isfinite(Q))):
        raise ArithmeticError('Singular matrix.')

    # Return the shift, rotation, and scale changes
    return build_fit(P, Q, 'general')