no longer dependent on numpy