Skip to content
This repository has been archived by the owner on May 2, 2022. It is now read-only.

Commit

Permalink
minor change to Binning class documentation. significant updates to R…
Browse files Browse the repository at this point in the history
…ound and RoundLog classes for better performance were incorporated from Tai Sakuma main working branch
  • Loading branch information
Sean Kalafut committed Apr 8, 2017
1 parent 13a77de commit d2d45c4
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 51 deletions.
2 changes: 1 addition & 1 deletion AlphaTwirl/Binning/Binning.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ def __init__(self, boundaries = None, lows = None, ups = None,

if boundaries is None:
if lows is None or ups is None:
raise ValueError("Only a list of bin boundaries, or pairs of (bin lower bound, bin upper bound) need to be given!")
raise ValueError("Only either boundaries or pairs of lows and ups need to be given!")
if not tuple(lows[1:]) == tuple(ups[:-1]):
raise ValueError("Boundaries cannot be determined from lows = " + str(lows) + " and ups = " + str(ups))
self.boundaries = tuple(lows) + (ups[-1], )
Expand Down
92 changes: 48 additions & 44 deletions AlphaTwirl/Binning/Round.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Tai Sakuma <tai.sakuma@cern.ch>

import math
import collections
import logging

##__________________________________________________________________||
Expand Down Expand Up @@ -61,7 +62,6 @@ def test_call(self):
obj = Round(2, 0) #width is 2, aboundary is 0
self.assertEqual( -2, obj( -1.9))
self.assertEqual( -2, obj( -1 )) #equivalent to calling obj.__call__(-1)
self.assertEqual( -2, obj( -0.1))
self.assertEqual( 0, obj( 0.1))
Expand All @@ -80,19 +80,17 @@ def test_next(self):
self.assertEqual( -0.015, obj.next( -0.035))
self.assertEqual( 0.005, obj.next( -0.015))
self.assertEqual( 0.025, obj.next( 0.005))
self.assertEqual( 0.045, obj.next( 0.025))
"""
def __init__(self, width = 1, aboundary = None,
min = None, underflow_bin = None,
max = None, overflow_bin = None,
valid = returnTrue, retvalue = 'lowedge'
valid = returnTrue
):
"""__init__ creates an instance of the Round class.
By default:
retvalue is set to lowedge. It can also be set to center.
every value added to the Round class object has the parameter
valid set to True. Thus, __call__ will never return None.
specific max and min values are not set.
Expand All @@ -106,16 +104,12 @@ def __init__(self, width = 1, aboundary = None,
"""

supportedRetvalues = ('center', 'lowedge')
if retvalue not in supportedRetvalues:
raise ValueError("The retvalue '%s' is not supported! " % (retvalue, ) + "Supported values are '" + "', '".join(supportedRetvalues) + "'")

self.width = width
self.aboundary = aboundary
self.halfWidth = self.width/2 if self.width % 2 == 0 else float(self.width)/2
if aboundary is None: aboundary = self.halfWidth
self.boundaries = [aboundary - width, aboundary, aboundary + width]
self.lowedge = (retvalue == 'lowedge')
self.boundaries = collections.deque([aboundary - width, aboundary, aboundary + width])
#self.lowedge = (retvalue == 'lowedge')
self.min = min
self.underflow_bin = underflow_bin
self.max = max
Expand All @@ -136,21 +130,32 @@ def __repr__(self):

def __call__(self, val):
"""main function of this class. returns the bin to which val belongs.
For improved performance the work done by this function has been moved
to the function _lower_boundary, which is called automatically by
__call__
"""
return self._lower_boundary(val)

def _lower_boundary(self, val):
"""returns the bin to which val belongs.
This function is executed automatically by __call__, and should not be
called explicitly by users.
first check if the value val added using __init__ is valid.
first check if the value val is valid.
then, if min and max set in __init__ are not None, check if val belongs to the
underflow (below min) or overflow bin (below max)
then, check if 'val' is plus or minus infinity. this is only necessary if 'max'
and/or 'min' are not defined.
then, check if val is plus or minus infinity. this is only necessary if max
and/or min are not defined.
This class keeps an internal list of bin boundaries named 'boundaries' which is updated
This class keeps an internal list of bin boundaries named boundaries which is updated
if a new value val is added which does not fall in an existing bin.
"""

if not self.valid(val):
if not self.valid(val):
return None

if self.min is not None:
Expand All @@ -166,17 +171,16 @@ def __call__(self, val):
logger.warning('val = {}. will return {}'.format(val, None))
return None

self._updateBoundaries(val)
bin = self.boundaries[0]

for b in self.boundaries[1:]:
if b <= val: bin = b
else: break
self._update_boundaries(val)

if not self.lowedge:
bin += self.halfWidth
bin = self.boundaries[0]
for b in self.boundaries:
if b <= val:
bin = b
else:
break

return bin
return bin

def _updateBoundaries(self, val):
"""when a new value val is added that does not fit in an existing bin, this
Expand All @@ -187,16 +191,28 @@ def _updateBoundaries(self, val):
this function explicitly.
"""
while val < self.boundaries[0]:
self.boundaries.insert(0, self.boundaries[0] - self.width)

while val < self.boundaries[0]:
self.boundaries.appendleft(self.boundaries[0] - self.width)

while val > self.boundaries[-1]:
while val > self.boundaries[-1]:
self.boundaries.append(self.boundaries[-1] + self.width)

def next(self, bin):
"""given the input bin, this function returns the next bin.
For improved performance the work done by this function has been moved
to the function _next_lower_boundary, which is called automatically by
next
first check that the bin given in the argument 'bin' exists in the set of bins already
"""
return self._next_lower_boundary(bin)

def _next_lower_boundary(self, bin):
"""given the input bin, this function returns the next bin.
This function is automatically called by next, and should not be called
explicitly by users.
first check that the bin given in the argument bin exists in the set of bins already
defined. Return None if bin is not valid.
if bin corresponds to underflow_bin, return the first bin (just above underflow_bin)
Expand All @@ -210,31 +226,19 @@ def next(self, bin):
"""

bin = self.__call__(bin)
bin = self._lower_boundary(bin)

if bin is None:
return None

if bin == self.underflow_bin:
return self.__call__(self.min)
return self._lower_boundary(self.min)

if bin == self.overflow_bin:
return self.overflow_bin

self._updateBoundaries(bin)
self._updateBoundaries(bin + self.width)

nbin = self.boundaries[0]

for b in self.boundaries[1:]:
if b <= bin: nbin = b
else: break

ret = self.boundaries[self.boundaries.index(nbin) + 1]

if not self.lowedge:
ret += self.halfWidth
self._update_boundaries(bin)

return ret
return self._lower_boundary(bin + self.width*1.001)

##__________________________________________________________________||
10 changes: 4 additions & 6 deletions AlphaTwirl/Binning/RoundLog.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def test_call(self):
A functor example of next is::
def test_next(self):
obj = RoundLog(retvalue = 'center') #the default bin width defined in __init__ is used
obj = RoundLog() #the default bin width defined in __init__ is used
self.assertAlmostEqual( 2.818382931264, obj.next(2.23872113856834))
self.assertAlmostEqual( 28.18382931264, obj.next(22.3872113856834))
Expand All @@ -66,15 +66,13 @@ def test_next(self):
def __init__(self, width = 0.1, aboundary = 1,
min = None, underflow_bin = None,
max = None, overflow_bin = None,
valid = returnTrue,
retvalue = 'lowedge',
valid = returnTrue
):
"""valid can be any user defined function which returns True or False.
retvalue can be lowedge or center. See Round.py class for information
about other __init__ input parameters.
See Round class for information about other __init__ input parameters.
"""
self._round = Round(width = width, aboundary = math.log10(aboundary), retvalue = retvalue)
self._round = Round(width = width, aboundary = math.log10(aboundary))
self.width = width
self.aboundary = aboundary
self.min = min
Expand Down

0 comments on commit d2d45c4

Please sign in to comment.