it seemed easier to go for a sparse implementation than try to make the dense implementation from part 1 work