intervals.py: use itertools for speedup and cleanup
Another optimization

By creating the selectors used in joint_prob_cached ahead of time we save time
and the paths can be stored as a list of indices instead of actually containing
the component tuples