Belle II Software development
IoVSet Class Reference

Public Member Functions

def __init__ (self, iterable=None, *allow_overlaps=False, allow_startone=False)
 
def add (self, iov, allow_overlaps=None)
 
def remove (self, iov)
 
def intersect (self, iov)
 
def contains (self, iov)
 
def overlaps (self, iov)
 
def copy (self)
 
def clear (self)
 
def iovs (self)
 
def first (self)
 
def final (self)
 
def gaps (self)
 
def __bool__ (self)
 
def __contains__ (self, iov)
 
def __and__ (self, other)
 
def __or__ (self, other)
 
def __sub__ (self, other)
 
def __iter__ (self)
 
def __len__ (self)
 
def __repr__ (self)
 

Private Attributes

 __iovs
 The set of iovs.
 
 __allow_overlaps
 Whether or not we raise an error on overlaps.
 
 __allow_startone
 Whether or not run 1 will be also considered the first run when combining iovs between experiments.
 

Detailed Description

A set of iovs.

This class allows to combine iovs into a set. New iovs can be added with
`add()` and will be combined with existing iovs if possible.

The final, minimal number of iovs can be obtained with the `iovs` property

    >>> a = IoVSet()
    >>> a.add((0,0,0,2))
    >>> a.add((0,3,0,5))
    >>> a.add((0,8,0,9))
    >>> a
    {(0, 0, 0, 5), (0, 8, 0, 9)}

Definition at line 279 of file iov.py.

Constructor & Destructor Documentation

◆ __init__()

def __init__ (   self,
  iterable = None,
allow_overlaps = False,
  allow_startone = False 
)
Create a new set.

    >>> a = IoVSet([IntervalOfValidity(3,6,3,-1), (0,0,3,5)])
    >>> a
    {(0, 0, 3, inf)}

Parameters:
    iterable: if not None it should be an iterable of IntervalOfValidity
        objects or anything that can be converted to an IntervalOfValidity.
    allow_overlaps (bool): If False adding which overlaps with any
        existing iov in the set will raise a ValueError.
    allow_startone (bool): If True also join iovs if one covers the
        whole experiment and the next one starts at run 1 in the next
        experiment. If False they will only be joined if the next one
        starts at run 0.

Definition at line 295 of file iov.py.

295 def __init__(self, iterable=None, *, allow_overlaps=False, allow_startone=False):
296 """Create a new set.
297
298 >>> a = IoVSet([IntervalOfValidity(3,6,3,-1), (0,0,3,5)])
299 >>> a
300 {(0, 0, 3, inf)}
301
302 Parameters:
303 iterable: if not None it should be an iterable of IntervalOfValidity
304 objects or anything that can be converted to an IntervalOfValidity.
305 allow_overlaps (bool): If False adding which overlaps with any
306 existing iov in the set will raise a ValueError.
307 allow_startone (bool): If True also join iovs if one covers the
308 whole experiment and the next one starts at run 1 in the next
309 experiment. If False they will only be joined if the next one
310 starts at run 0.
311 """
312
313 self.__iovs = set()
314
315 self.__allow_overlaps = allow_overlaps
316
318 self.__allow_startone = allow_startone
319 if iterable is not None:
320 for element in iterable:
321 self.add(element)
322

Member Function Documentation

◆ __and__()

def __and__ (   self,
  other 
)
Return a new set that is the intersection between two sets

    >>> a = IoVSet([(0,0,1,-1)])
    >>> a & (1,0,2,-1)
    {(1, 0, 1, inf)}

Definition at line 622 of file iov.py.

622 def __and__(self, other):
623 """Return a new set that is the intersection between two sets
624
625 >>> a = IoVSet([(0,0,1,-1)])
626 >>> a & (1,0,2,-1)
627 {(1, 0, 1, inf)}
628 """
629 return self.intersect(other)
630

◆ __bool__()

def __bool__ (   self)
Return True if the set is not empty


    >>> a = IoVSet()
    >>> a.add((0,0,1,-1))
    >>> bool(a)
    True
    >>> a.clear()
    >>> a
    {}
    >>> bool(a)
    False

Definition at line 602 of file iov.py.

602 def __bool__(self):
603 """Return True if the set is not empty
604
605
606 >>> a = IoVSet()
607 >>> a.add((0,0,1,-1))
608 >>> bool(a)
609 True
610 >>> a.clear()
611 >>> a
612 {}
613 >>> bool(a)
614 False
615 """
616 return len(self.__iovs) > 0
617

◆ __contains__()

def __contains__ (   self,
  iov 
)
Check if an iov is fully covered by the set

Definition at line 618 of file iov.py.

618 def __contains__(self, iov):
619 """Check if an iov is fully covered by the set"""
620 return self.contains(iov)
621

◆ __iter__()

def __iter__ (   self)
Loop over the set of iovs

Definition at line 667 of file iov.py.

667 def __iter__(self):
668 """Loop over the set of iovs"""
669 return iter(self.__iovs)
670

◆ __len__()

def __len__ (   self)
Return the number of validity intervals in this set

Definition at line 671 of file iov.py.

671 def __len__(self):
672 """Return the number of validity intervals in this set"""
673 return len(self.__iovs)
674

◆ __or__()

def __or__ (   self,
  other 
)
Return a new set that is the combination of two sets: The new set will
be valid everywhere any of the two sets were valid.

No check for overlaps will be performed but the result will inherit the
settings for further additions from the first set

    >>> a = IoVSet([(0,0,1,-1)])
    >>> a | (1,0,2,-1)
    {(0, 0, 2, inf)}
    >>> a | (3,0,3,-1)
    {(0, 0, 1, inf), (3, 0, 3, inf)}

Definition at line 631 of file iov.py.

631 def __or__(self, other):
632 """
633 Return a new set that is the combination of two sets: The new set will
634 be valid everywhere any of the two sets were valid.
635
636 No check for overlaps will be performed but the result will inherit the
637 settings for further additions from the first set
638
639 >>> a = IoVSet([(0,0,1,-1)])
640 >>> a | (1,0,2,-1)
641 {(0, 0, 2, inf)}
642 >>> a | (3,0,3,-1)
643 {(0, 0, 1, inf), (3, 0, 3, inf)}
644 """
645 copy = self.copy()
646 copy.add(other, allow_overlaps=True)
647 return copy
648

◆ __repr__()

def __repr__ (   self)
Return a printable representation

Definition at line 675 of file iov.py.

675 def __repr__(self):
676 """Return a printable representation"""
677 return '{' + ', '.join(str(e) for e in sorted(self.__iovs)) + '}'

◆ __sub__()

def __sub__ (   self,
  other 
)
Return a new set which is only valid for where a is valid but not b.

See `remove` but this will not modify the set in place

    >>> a = IoVSet([(0,0,-1,-1)])
    >>> a - (1,0,2,-1)
    {(0, 0, 0, inf), (3, 0, inf, inf)}
    >>> a - (0,0,3,-1) - (10,0,-1,-1)
    {(4, 0, 9, inf)}
    >>> IoVSet([(0,0,1,-1)]) - (2,0,2,-1)
    {(0, 0, 1, inf)}

Definition at line 649 of file iov.py.

649 def __sub__(self, other):
650 """
651 Return a new set which is only valid for where a is valid but not b.
652
653 See `remove` but this will not modify the set in place
654
655 >>> a = IoVSet([(0,0,-1,-1)])
656 >>> a - (1,0,2,-1)
657 {(0, 0, 0, inf), (3, 0, inf, inf)}
658 >>> a - (0,0,3,-1) - (10,0,-1,-1)
659 {(4, 0, 9, inf)}
660 >>> IoVSet([(0,0,1,-1)]) - (2,0,2,-1)
661 {(0, 0, 1, inf)}
662 """
663 copy = self.copy()
664 copy.remove(other)
665 return copy
666

◆ add()

def add (   self,
  iov,
  allow_overlaps = None 
)
Add a new iov to the set.

The new iov be combined with existing iovs if possible. After the
operation the set will contain the minimal amount of separate iovs
possible to represent all added iovs

    >>> a = IoVSet()
    >>> a.add((0, 0, 0, 2))
    >>> a.add((0, 3, 0, 5))
    >>> a.add((0, 8, 0, 9))
    >>> a
    {(0, 0, 0, 5), (0, 8, 0, 9)}
    >>> a.add(IoVSet([(10, 0, 10, 1), (10, 2, 10, -1)]))
    >>> a
    {(0, 0, 0, 5), (0, 8, 0, 9), (10, 0, 10, inf)}

Be aware, by default it's not possible to add overlapping iovs to the set.
This can be changed either on construction or per `add` call using
``allow_overlap``

    >>> a.add((0, 2, 0, 3))
    Traceback (most recent call last):
        ...
    ValueError: Overlap between (0, 0, 0, 5) and (0, 2, 0, 3)
    >>> a.add((0, 2, 0, 3), allow_overlaps=True)
    >>> a
    {(0, 0, 0, 5), (0, 8, 0, 9), (10, 0, 10, inf)}

Parameters:
    iov (Union[IoVSet, IntervalOfValidity, tuple(int)]): IoV or
        set of IoVs to add to this set
    allow_overlaps (bool): Can be used to override global overlap setting
        of this set to allow/restrict overlaps for a single insertion
        operation

Warning:
    This method modifies the set in place

Definition at line 323 of file iov.py.

323 def add(self, iov, allow_overlaps=None):
324 """
325 Add a new iov to the set.
326
327 The new iov be combined with existing iovs if possible. After the
328 operation the set will contain the minimal amount of separate iovs
329 possible to represent all added iovs
330
331 >>> a = IoVSet()
332 >>> a.add((0, 0, 0, 2))
333 >>> a.add((0, 3, 0, 5))
334 >>> a.add((0, 8, 0, 9))
335 >>> a
336 {(0, 0, 0, 5), (0, 8, 0, 9)}
337 >>> a.add(IoVSet([(10, 0, 10, 1), (10, 2, 10, -1)]))
338 >>> a
339 {(0, 0, 0, 5), (0, 8, 0, 9), (10, 0, 10, inf)}
340
341 Be aware, by default it's not possible to add overlapping iovs to the set.
342 This can be changed either on construction or per `add` call using
343 ``allow_overlap``
344
345 >>> a.add((0, 2, 0, 3))
346 Traceback (most recent call last):
347 ...
348 ValueError: Overlap between (0, 0, 0, 5) and (0, 2, 0, 3)
349 >>> a.add((0, 2, 0, 3), allow_overlaps=True)
350 >>> a
351 {(0, 0, 0, 5), (0, 8, 0, 9), (10, 0, 10, inf)}
352
353 Parameters:
354 iov (Union[IoVSet, IntervalOfValidity, tuple(int)]): IoV or
355 set of IoVs to add to this set
356 allow_overlaps (bool): Can be used to override global overlap setting
357 of this set to allow/restrict overlaps for a single insertion
358 operation
359
360 Warning:
361 This method modifies the set in place
362 """
363 # check whether we override overlap settings
364 if allow_overlaps is None:
365 allow_overlaps = self.__allow_overlaps
366 # we can add a set to a set :D
367 if isinstance(iov, IoVSet):
368 for element in iov:
369 self.add(element, allow_overlaps)
370 return
371 # make sure it's actually an IoV, this will raise an error on failure
372 if not isinstance(iov, IntervalOfValidity):
373 iov = IntervalOfValidity(iov)
374 # and now check for all existing iovs ... (but use a copy since we modify the set)
375 for existing in list(self.__iovs):
376 # if there's an overlap to the new iov
377 if (not allow_overlaps) and (existing & iov):
378 raise ValueError(f"Overlap between {existing} and {iov}")
379 # and if they can be combined to a bigger iov
380 combined = existing.union(iov, self.__allow_startone)
381 # if we now have a combined iov, remove the one that we were able to
382 # combine it with from the existing iovs because we now check
383 # against the combined one. Since the only way to add a new iov is
384 # this loop we know all previous existing iovs we checked before
385 # didn't have a union with this new iov or any other existing iovs
386 # so if the just check the remaining iovs against the new combined
387 # one we can cascade combine all iovs in one go.
388 if combined is not None:
389 self.__iovs.remove(existing)
390 iov = combined
391 # done, we now have a new iov which combines all existing iovs it had an
392 # overlap with and we removed the existing iovs so nothing else to do
393 # but add the iov back in the list
394 self.__iovs.add(iov)
395

◆ clear()

def clear (   self)
Clear all iovs from this set

Definition at line 548 of file iov.py.

548 def clear(self):
549 """Clear all iovs from this set"""
550 self.__iovs = {}
551

◆ contains()

def contains (   self,
  iov 
)
Check if an iov is fully covered by the set

    >>> a = IoVSet([(0,0,2,-1), (5,0,5,-1)])
    >>> a.contains((0,0,1,-1))
    True
    >>> a.contains(IntervalOfValidity(0,0,3,2))
    False
    >>> a.contains(IoVSet([(0,1,1,23), (5,0,5,23)]))
    True
    >>> a.contains(IoVSet([(0,1,1,23), (5,0,6,23)]))
    False
    >>> a.contains((3,0,4,-1))
    False

Parameters:
    iov (Union[IoVSet, IntervalOfValidity, tuple(int)]): IoV or
        set of IoVs to be checked

Returns:
    True if the full iov or all the iovs in the given set are fully
    present in this set

Definition at line 468 of file iov.py.

468 def contains(self, iov):
469 """
470 Check if an iov is fully covered by the set
471
472 >>> a = IoVSet([(0,0,2,-1), (5,0,5,-1)])
473 >>> a.contains((0,0,1,-1))
474 True
475 >>> a.contains(IntervalOfValidity(0,0,3,2))
476 False
477 >>> a.contains(IoVSet([(0,1,1,23), (5,0,5,23)]))
478 True
479 >>> a.contains(IoVSet([(0,1,1,23), (5,0,6,23)]))
480 False
481 >>> a.contains((3,0,4,-1))
482 False
483
484 Parameters:
485 iov (Union[IoVSet, IntervalOfValidity, tuple(int)]): IoV or
486 set of IoVs to be checked
487
488 Returns:
489 True if the full iov or all the iovs in the given set are fully
490 present in this set
491 """
492 # check if the whole set is in this set: all iovs need to be in here
493 if isinstance(iov, IoVSet):
494 return all(e in self for e in iov)
495 # make sure it's actually an IoV, this will raise an error on failure
496 if not isinstance(iov, IntervalOfValidity):
497 iov = IntervalOfValidity(iov)
498 # and then check all iovs in the set if they cover it
499 for existing in self.__iovs:
500 if iov - existing is None:
501 return True
502 return False
503

◆ copy()

def copy (   self)
Return a copy of this set

Definition at line 542 of file iov.py.

542 def copy(self):
543 """Return a copy of this set"""
544 copy = IoVSet(allow_overlaps=self.__allow_overlaps, allow_startone=self.__allow_startone)
545 copy.__iovs = set(self.__iovs)
546 return copy
547

◆ final()

def final (   self)
Return the final run covered by this iov set

>>> a = IoVSet([(3,0,3,10), (10,11,10,23), (0,0,2,-1), (5,0,5,-1)])
>>> a.final
(10, 23)

Definition at line 570 of file iov.py.

570 def final(self):
571 """Return the final run covered by this iov set
572
573 >>> a = IoVSet([(3,0,3,10), (10,11,10,23), (0,0,2,-1), (5,0,5,-1)])
574 >>> a.final
575 (10, 23)
576 """
577 if not self.__iovs:
578 return None
579 return max(self.iovs).final
580

◆ first()

def first (   self)
Return the first run covered by this iov set

>>> a = IoVSet([(3,0,3,10), (10,11,10,23), (0,0,2,-1), (5,0,5,-1)])
>>> a.first
(0, 0)

Definition at line 558 of file iov.py.

558 def first(self):
559 """Return the first run covered by this iov set
560
561 >>> a = IoVSet([(3,0,3,10), (10,11,10,23), (0,0,2,-1), (5,0,5,-1)])
562 >>> a.first
563 (0, 0)
564 """
565 if not self.__iovs:
566 return None
567 return min(self.iovs).first
568

◆ gaps()

def gaps (   self)
Return the gaps in the set. Any area not covered between the first
point of validity and the last

>>> a = IoVSet([(0,0,2,-1)])
>>> a.gaps
{}
>>> b = IoVSet([(0,0,2,-1), (5,0,5,-1)])
>>> b.gaps
{(3, 0, 4, inf)}
>>> c = IoVSet([(0,0,2,-1), (5,0,5,-1), (10,3,10,6)])
>>> c.gaps
{(3, 0, 4, inf), (6, 0, 10, 2)}

Definition at line 582 of file iov.py.

582 def gaps(self):
583 """Return the gaps in the set. Any area not covered between the first
584 point of validity and the last
585
586 >>> a = IoVSet([(0,0,2,-1)])
587 >>> a.gaps
588 {}
589 >>> b = IoVSet([(0,0,2,-1), (5,0,5,-1)])
590 >>> b.gaps
591 {(3, 0, 4, inf)}
592 >>> c = IoVSet([(0,0,2,-1), (5,0,5,-1), (10,3,10,6)])
593 >>> c.gaps
594 {(3, 0, 4, inf), (6, 0, 10, 2)}
595 """
596 if len(self.__iovs) < 2:
597 return IoVSet()
598
599 full_range = IoVSet([self.first + self.final])
600 return full_range - self
601

◆ intersect()

def intersect (   self,
  iov 
)
Intersect this set with another set and return a new set
which is valid exactly where both sets have been valid before

    >>> a = IoVSet()
    >>> a.add((0,0,10,-1))
    >>> a.intersect((5,0,20,-1))
    {(5, 0, 10, inf)}
    >>> a.intersect(IoVSet([(0,0,3,-1), (9,0,20,-1)]))
    {(0, 0, 3, inf), (9, 0, 10, inf)}

Parameters:
    iov (Union[IoVSet, IntervalOfValidity, tuple(int)]): IoV or
        set of IoVs to intersect with this set

Definition at line 439 of file iov.py.

439 def intersect(self, iov):
440 """Intersect this set with another set and return a new set
441 which is valid exactly where both sets have been valid before
442
443 >>> a = IoVSet()
444 >>> a.add((0,0,10,-1))
445 >>> a.intersect((5,0,20,-1))
446 {(5, 0, 10, inf)}
447 >>> a.intersect(IoVSet([(0,0,3,-1), (9,0,20,-1)]))
448 {(0, 0, 3, inf), (9, 0, 10, inf)}
449
450 Parameters:
451 iov (Union[IoVSet, IntervalOfValidity, tuple(int)]): IoV or
452 set of IoVs to intersect with this set
453 """
454 if not isinstance(iov, (IoVSet, IntervalOfValidity)):
455 iov = IntervalOfValidity(iov)
456 if isinstance(iov, IntervalOfValidity):
457 iov = IoVSet([iov])
458
459 # ok for all combinations a,b from set1 and set2 check the intersection
460 # and if not empty add to the result
461 result = IoVSet()
462 for a, b in product(self.iovs, iov.iovs):
463 c = a & b
464 if c:
465 result.add(c)
466 return result
467

◆ iovs()

def iovs (   self)
Return the set of valid iovs

Definition at line 553 of file iov.py.

553 def iovs(self):
554 """Return the set of valid iovs"""
555 return self.__iovs
556

◆ overlaps()

def overlaps (   self,
  iov 
)
Check if the given iov overlaps with this set.

In contrast to `contains` this doesn't require the given iov to be fully
covered. It's enough if the any run covered by the iov is also covered
by this set.

    >>> a = IoVSet([(0,0,2,-1), (5,0,5,-1)])
    >>> a.overlaps((0,0,1,-1))
    True
    >>> a.overlaps(IntervalOfValidity(0,0,3,2))
    True
    >>> a.overlaps(IoVSet([(0,1,1,23), (5,0,5,23)]))
    True
    >>> a.overlaps(IoVSet([(0,1,1,23), (5,0,6,23)]))
    True
    >>> a.overlaps((3,0,4,-1))
    False

Parameters:
    iov (Union[IoVSet, IntervalOfValidity, tuple(int)]): IoV or
        set of IoVs to be checked

Returns:
    True if the iov or any of the iovs in the given set overlap with any
    iov in this set

Definition at line 504 of file iov.py.

504 def overlaps(self, iov):
505 """Check if the given iov overlaps with this set.
506
507 In contrast to `contains` this doesn't require the given iov to be fully
508 covered. It's enough if the any run covered by the iov is also covered
509 by this set.
510
511 >>> a = IoVSet([(0,0,2,-1), (5,0,5,-1)])
512 >>> a.overlaps((0,0,1,-1))
513 True
514 >>> a.overlaps(IntervalOfValidity(0,0,3,2))
515 True
516 >>> a.overlaps(IoVSet([(0,1,1,23), (5,0,5,23)]))
517 True
518 >>> a.overlaps(IoVSet([(0,1,1,23), (5,0,6,23)]))
519 True
520 >>> a.overlaps((3,0,4,-1))
521 False
522
523 Parameters:
524 iov (Union[IoVSet, IntervalOfValidity, tuple(int)]): IoV or
525 set of IoVs to be checked
526
527 Returns:
528 True if the iov or any of the iovs in the given set overlap with any
529 iov in this set
530 """
531 if not isinstance(iov, (IoVSet, IntervalOfValidity)):
532 iov = IntervalOfValidity(iov)
533 if isinstance(iov, IntervalOfValidity):
534 iov = IoVSet([iov])
535
536 for a, b in product(self.iovs, iov.iovs):
537 c = a & b
538 if c:
539 return True
540 return False
541

◆ remove()

def remove (   self,
  iov 
)
Remove an iov or a set of iovs from this set

After this operation the set will not be valid for the given iov or set
of iovs:

    >>> a = IoVSet()
    >>> a.add((0,0,10,-1))
    >>> a.remove((1,0,1,-1))
    >>> a.remove((5,0,8,5))
    >>> a
    {(0, 0, 0, inf), (2, 0, 4, inf), (8, 6, 10, inf)}
    >>> a.remove(IoVSet([(3,0,3,10), (3,11,3,-1)]))
    >>> a
    {(0, 0, 0, inf), (2, 0, 2, inf), (4, 0, 4, inf), (8, 6, 10, inf)}

Parameters:
    iov (Union[IoVSet, IntervalOfValidity, tuple(int)]): IoV or
        set of IoVs to remove from this set

Warning:
    This method modifies the set in place

Definition at line 396 of file iov.py.

396 def remove(self, iov):
397 """Remove an iov or a set of iovs from this set
398
399 After this operation the set will not be valid for the given iov or set
400 of iovs:
401
402 >>> a = IoVSet()
403 >>> a.add((0,0,10,-1))
404 >>> a.remove((1,0,1,-1))
405 >>> a.remove((5,0,8,5))
406 >>> a
407 {(0, 0, 0, inf), (2, 0, 4, inf), (8, 6, 10, inf)}
408 >>> a.remove(IoVSet([(3,0,3,10), (3,11,3,-1)]))
409 >>> a
410 {(0, 0, 0, inf), (2, 0, 2, inf), (4, 0, 4, inf), (8, 6, 10, inf)}
411
412 Parameters:
413 iov (Union[IoVSet, IntervalOfValidity, tuple(int)]): IoV or
414 set of IoVs to remove from this set
415
416 Warning:
417 This method modifies the set in place
418 """
419 # we can remove a set from a set :D
420 if isinstance(iov, IoVSet):
421 for element in iov:
422 self.remove(element)
423 return
424 # make sure it's actually an IoV, this will raise an error on failure
425 if not isinstance(iov, IntervalOfValidity):
426 iov = IntervalOfValidity(iov)
427 # and subtract the iov from all existing iovs
428 for existing in list(self.__iovs):
429 delta = existing - iov
430 if delta != existing:
431 self.__iovs.remove(existing)
432 if isinstance(delta, tuple):
433 # got two new iovs, apparently we split the old one
434 for new in delta:
435 self.__iovs.add(new)
436 elif delta is not None:
437 self.__iovs.add(delta)
438

Member Data Documentation

◆ __allow_overlaps

__allow_overlaps
private

Whether or not we raise an error on overlaps.

Definition at line 315 of file iov.py.

◆ __allow_startone

__allow_startone
private

Whether or not run 1 will be also considered the first run when combining iovs between experiments.

Definition at line 318 of file iov.py.

◆ __iovs

__iovs
private

The set of iovs.

Definition at line 313 of file iov.py.


The documentation for this class was generated from the following file: