Belle II Software development
IoVSet Class Reference

Public Member Functions

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

Private Attributes

dict __iovs = set()
 The set of iovs.
 
 __allow_overlaps = allow_overlaps
 Whether or not we raise an error on overlaps.
 
 __allow_startone = 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 283 of file iov.py.

Constructor & Destructor Documentation

◆ __init__()

__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 299 of file iov.py.

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

Member Function Documentation

◆ __and__()

__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 632 of file iov.py.

632 def __and__(self, other):
633 """Return a new set that is the intersection between two sets
634
635 >>> a = IoVSet([(0,0,1,-1)])
636 >>> a & (1,0,2,-1)
637 {(1, 0, 1, inf)}
638 """
639 return self.intersect(other)
640

◆ __bool__()

__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 612 of file iov.py.

612 def __bool__(self):
613 """Return True if the set is not empty
614
615
616 >>> a = IoVSet()
617 >>> a.add((0,0,1,-1))
618 >>> bool(a)
619 True
620 >>> a.clear()
621 >>> a
622 {}
623 >>> bool(a)
624 False
625 """
626 return len(self.__iovs) > 0
627

◆ __contains__()

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

Definition at line 628 of file iov.py.

628 def __contains__(self, iov):
629 """Check if an iov is fully covered by the set"""
630 return self.contains(iov)
631

◆ __iter__()

__iter__ ( self)
Loop over the set of iovs

Definition at line 677 of file iov.py.

677 def __iter__(self):
678 """Loop over the set of iovs"""
679 return iter(self.__iovs)
680

◆ __len__()

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

Definition at line 681 of file iov.py.

681 def __len__(self):
682 """Return the number of validity intervals in this set"""
683 return len(self.__iovs)
684

◆ __or__()

__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 641 of file iov.py.

641 def __or__(self, other):
642 """
643 Return a new set that is the combination of two sets: The new set will
644 be valid everywhere any of the two sets were valid.
645
646 No check for overlaps will be performed but the result will inherit the
647 settings for further additions from the first set
648
649 >>> a = IoVSet([(0,0,1,-1)])
650 >>> a | (1,0,2,-1)
651 {(0, 0, 2, inf)}
652 >>> a | (3,0,3,-1)
653 {(0, 0, 1, inf), (3, 0, 3, inf)}
654 """
655 copy = self.copy()
656 copy.add(other, allow_overlaps=True)
657 return copy
658

◆ __repr__()

__repr__ ( self)
Return a printable representation

Definition at line 685 of file iov.py.

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

◆ __sub__()

__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 659 of file iov.py.

659 def __sub__(self, other):
660 """
661 Return a new set which is only valid for where a is valid but not b.
662
663 See `remove` but this will not modify the set in place
664
665 >>> a = IoVSet([(0,0,-1,-1)])
666 >>> a - (1,0,2,-1)
667 {(0, 0, 0, inf), (3, 0, inf, inf)}
668 >>> a - (0,0,3,-1) - (10,0,-1,-1)
669 {(4, 0, 9, inf)}
670 >>> IoVSet([(0,0,1,-1)]) - (2,0,2,-1)
671 {(0, 0, 1, inf)}
672 """
673 copy = self.copy()
674 copy.remove(other)
675 return copy
676

◆ add()

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 327 of file iov.py.

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

◆ clear()

clear ( self)
Clear all iovs from this set

Definition at line 556 of file iov.py.

556 def clear(self):
557 """Clear all iovs from this set"""
558 self.__iovs = {}
559

◆ contains()

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 474 of file iov.py.

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

◆ copy()

copy ( self)
Return a copy of this set

Definition at line 550 of file iov.py.

550 def copy(self):
551 """Return a copy of this set"""
552 copy = IoVSet(allow_overlaps=self.__allow_overlaps, allow_startone=self.__allow_startone)
553 copy.__iovs = set(self.__iovs)
554 return copy
555

◆ gaps()

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 592 of file iov.py.

592 def gaps(self):
593 """Return the gaps in the set. Any area not covered between the first
594 point of validity and the last
595
596 >>> a = IoVSet([(0,0,2,-1)])
597 >>> a.gaps
598 {}
599 >>> b = IoVSet([(0,0,2,-1), (5,0,5,-1)])
600 >>> b.gaps
601 {(3, 0, 4, inf)}
602 >>> c = IoVSet([(0,0,2,-1), (5,0,5,-1), (10,3,10,6)])
603 >>> c.gaps
604 {(3, 0, 4, inf), (6, 0, 10, 2)}
605 """
606 if len(self.__iovs) < 2:
607 return IoVSet()
608
609 full_range = IoVSet([self.first + self.final])
610 return full_range - self
611

◆ intersect()

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 443 of file iov.py.

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

◆ iovs()

iovs ( self)
Return the set of valid iovs

Definition at line 561 of file iov.py.

561 def iovs(self):
562 """Return the set of valid iovs"""
563 return self.__iovs
564

◆ overlaps()

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 510 of file iov.py.

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

◆ remove()

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 400 of file iov.py.

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

Member Data Documentation

◆ __allow_overlaps

__allow_overlaps = allow_overlaps
private

Whether or not we raise an error on overlaps.

Definition at line 319 of file iov.py.

◆ __allow_startone

__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 322 of file iov.py.

◆ __iovs

__iovs = set()
private

The set of iovs.

Definition at line 317 of file iov.py.


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