Exemple #1
0
    def test_get(self):
        ordered_list = [(10, 100), (5, 20), (7, 70), (2, 50)]
        om = OrderedMap(ordered_list)

        a = om.get(5)
        assert a == 20

        from structure.time_signature import TimeSignature

        from timemodel.time_signature_event import TimeSignatureEvent
        tse = TimeSignatureEvent(TimeSignature(3, Duration(1, 4)), Position(0))

        d = OrderedMap([(tse.time, tse)])
        x = d.get(0)
        assert x == tse
Exemple #2
0
    def test_remove(self):
        ordered_list = [(10, 100), (5, 20), (7, 70), (2, 50)]
        om = OrderedMap(ordered_list)

        assert 5 in om

        assert om.get(5) == 20
        om.remove_key(5)
        assert 5 not in om
Exemple #3
0
    def test_merge(self):
        ordered_list = [(10, 100), (5, 20), (7, 70), (2, 50)]
        om = OrderedMap(ordered_list)
        sup = [(3, 60), (15, 2)]
        om.merge(sup)
        self.assertTrue(3 in om.keys())
        self.assertTrue(om.get(3) == 60)
        self.assertTrue(15 in om.keys())
        self.assertTrue(om.get(15) == 2)
        self.assertTrue(5 in om.keys())

        sup = {3: 60, 15: 2}
        om.merge(sup)
        self.assertTrue(3 in om.keys())
        self.assertTrue(om.get(3) == 60)
        self.assertTrue(15 in om.keys())
        self.assertTrue(om.get(15) == 2)
        self.assertTrue(5 in om.keys())

        sup = OrderedMap({3: 60, 15: 2})
        om.merge(sup)
        self.assertTrue(3 in om.keys())
        self.assertTrue(om.get(3) == 60)
        self.assertTrue(15 in om.keys())
        self.assertTrue(om.get(15) == 2)
        self.assertTrue(5 in om.keys())
Exemple #4
0
class EventSequence(object):
    """
    A class to collect a sequence of Event's ordered (increasing) by the Event's time value.
    The class contains the following event accounting structures:
    1) OrderedMap: ordering the events by time in a map that provides a floor() function.
    2) successor: a dict that maps events to successors.
    3) predecessor: a dict that maps events to predecessors.
    4) first: first event in the event sequence.
    5) last: last event in the event sequence.
    """

    def __init__(self, event_list=None):
        """
        Constructor.
        
        Args:
          event_list:  Any of None, a single Event, or a list of Events.
        """
        self.ordered_map = OrderedMap()
        
        self._successor = {}
        self._predecessor = {}
        self.__first = None
        self.__last = None
        
        if event_list:
            self.add(event_list)
    
    @property       
    def sequence_list(self):
        return list(self.ordered_map.get(x) for x in self.ordered_map.keys())
    
    @property
    def is_empty(self):
        return self.ordered_map.is_empty()
    
    def floor(self, time):
        return self.ordered_map.floor(time)
    
    def event(self, index):
        return self.ordered_map.get(index)
    
    def floor_event(self, time):
        floor_position = self.floor(time)
        return self.event(floor_position) if floor_position else None
    
    @property
    def first(self):
        return self.__first
    
    @property
    def last(self):
        return self.__last
    
    def add(self, new_members):
        """
        Add any of a single Event or a list of Events.
        
        Args:
          new_members: Any of a single Event or a list of events
        """
                
        if isinstance(new_members, list):
            mem_set = new_members
            inputt = [(e.time, e) for e in new_members]

        else:
            mem_set = [new_members]
            inputt = [(new_members.time, new_members)]
           
        for m in mem_set:
            if self.ordered_map.has_reverse(m):
                raise Exception('{0} already a member of sequence.'.format(m))  
            if not isinstance(m, Event):
                raise Exception('{0} is not an event.'.format(m)) 
            
        for i in inputt:
            if i[1].time not in self.ordered_map:
                self._add_successor_predecessor_maps(i[1])
            else:
                self._update_successor_predecessor_maps(i[1])
            self.ordered_map.insert(i[0], i[1])                  
        
    def remove(self, members): 
        """
        Remove any of a single Event or a list of Events already in the sequence.
        
        Args:
          members: Any of a single Event or a list of Events already in the sequence.
        """
        if isinstance(members, list):
            for member in members:
                self.remove(member)
        else:
            if not self.ordered_map.has_reverse(members):
                raise Exception('{0} not a member of sequence'.format(members))            
            self._remove_successor_predecessor_maps(members)
            self.ordered_map.remove_key(self.ordered_map.reverse_get(members))  
            
    def move_event(self, event, new_time):
        """
        Method to move event in sequence to a new time.
        
        Args:
          event: (Event) to move
          new_time: the new time setting for the event
        """
        if self.event(event.time) != event:
            raise Exception('Given event at time {0} not in sequence'.format(event.time))
        self.remove(event)
        event.time = new_time
        self.add(event)
            
    def _add_successor_predecessor_maps(self, event):
        fl_key = self.floor(event.time)
        if fl_key:
            a = self.event(fl_key)
            b = self._successor[a]  # could be None  event is between a and b
            self._successor[a] = event
            self._successor[event] = b
            self._predecessor[event] = a
            if b:
                self._predecessor[b] = event
            else:
                self.__last = event
        else:  # this event has to come first
            if self.__first:
                self._successor[event] = self.__first
                self._predecessor[self.__first] = event
                self._predecessor[event] = None
                self.__first = event
            else:
                self.__first = self.__last = event
                self._successor[event] = None
                self._predecessor[event] = None
            
    def _update_successor_predecessor_maps(self, event):
        e = self.event(event.time)
        self.remove(e)
        self._add_successor_predecessor_maps(event)
        pass
    
    def _remove_successor_predecessor_maps(self, event):
        a = self._predecessor[event]
        b = self._successor[event]
        del self._successor[event]
        del self._predecessor[event]
        if a:
            self._successor[a] = b
        else:
            self.__first = b
        if b:
            self._predecessor[b] = a
        else:
            self.__last = a
        
    def clear(self):
        self.ordered_map.clear()
        self._successor.clear()
        self._predecessor.clear()
        
    def successor(self, event):
        return self._successor[event] if event in self._successor else None
    
    def predecessor(self, event):
        return self._predecessor[event] if event in self._predecessor else None
        
    def __str__(self):
        return ', '.join(str(x) for x in self.sequence_list)
    
    def print_maps(self):
        print('---------')
        if self.__first:
            print('first={0}'.format(self.__first))
        else:
            print('first=None')
        if self.__first:
            print('last={0}'.format(self.__last))
        else:
            print('last=None')
        
        print('Successor:')
        for i in self._successor.items():
            print('   {0} --> {1}'.format(i[0].object if i[0] else 'None', i[1].object if i[1] else 'None'))

        print('Predecessor:')
        for i in self._predecessor.items():
            print('   {0} --> {1}'.format(i[0].object if i[0] else 'None', i[1].object if i[1] else 'None'))
class PiecewiseLinearFunction(UnivariateFunction):
    """
    Piecewise linear function, steps defined by a set of transition points, where values between the ordinates
    of adjacent transitions points, are based on a linear interpolation of the transition points' values.
    
    For example, (3, 5), (7, 10), (10, 14), (12, 2)  has the following steps:
       (-3, 5
       (3-7, 5),
       (7-10, 10),
       (10-12, 14),
       (12-, 2)
       
       if restrict_domain is specified (True), evaluation points must be within domain bounds.
    """

    def __init__(self, transition_points=list(), restrict_domain=False):
        """
        Constructor.
        
        Args:
        transition_points: non-empty list of ordered pairs (x, y), x is the domain, y the range.
        restrict_domain: boolean indicating if evaluation points must be in defined domain of transition points.
                         default is False.
        """
        if transition_points is None or not isinstance(transition_points, list):
            assert Exception('Illegal argument to SetwiseLinearFunction {0}'.format(transition_points))
        self.__restrict_domain = restrict_domain
        self._setup(transition_points)
        
    def _setup(self, transition_points):
        self.__transition_points = sorted(transition_points, key=lambda x: x[0])
        self.__domain_start = self.__transition_points[0][0]
        self.__domain_end = self.__transition_points[len(self.__transition_points) - 1][0]
        
        lin_segs = []
        for i in range(0, len(self.transition_points) - 1):
            lin_segs.append((self.transition_points[i][0],
                             LinearSegment(self.transition_points[i], self.transition_points[i + 1])))
        
        self.ordered_map = OrderedMap(lin_segs)
        
    @property
    def transition_points(self):
        return self.__transition_points
    
    @property
    def restrict_domain(self):
        return self.__restrict_domain
    
    @property
    def domain_start(self):
        return self.__domain_start
    
    @property
    def domain_end(self):
        return self.__domain_end

    def __call__(self, x):
        return self.eval(x)
        
    def eval(self, x):
        if len(self.transition_points) == 0:
            raise Exception("The function is undefined due to lack of transition points.")
        if self.restrict_domain:
            if x < self.domain_start or x > self.domain_end:
                raise Exception('Input {0} out of range [{1}, {2}]'.format(x, self.domain_start, self.domain_end))

        if x <= self.domain_start:
            return self.transition_points[0][1]
        if x >= self.domain_end:
            return self.transition_points[len(self.transition_points) - 1][1]
        key = self.ordered_map.floor(x)
        lin_seg = self.ordered_map.get(key)
        return lin_seg.eval(x)
    
    def add(self, transition_point):
        """
        Add a transition point to the piecewise function.
        
        Args:
          transition_point: Pair (x, y)  x, y are numerics.
        """
        new_points = list(self.transition_points)
        new_points.append(transition_point)
        self._setup(new_points)
        
    def add_and_clear_forward(self, transition_point):
        """
        Add a transition point to the piecewise function AND clear out higher (domain value) transition points.
        
        Args:
          transition_point: Pair (x, y)  x, y are numerics.
        """
        new_points = []
        elimination_value = transition_point[0]
    
        for p in self.transition_points:
            if p[0] < elimination_value:
                new_points.append(p) 
        new_points.append(transition_point)
    
        self._setup(new_points)
class StepwiseFunction(UnivariateFunction):
    """
    Stepwise function, steps defined by a set of transition points
    
    For example, (5, 1), (7, 3), (10, 6), (12, 8)  has the following linear segments:
    (5, 1) to (7, 3)
    (7, 3) to (10, 6)
    (10, 6) to 12, 8)
             
    if restrict_domain is specified (True), evaluation points must be within domain bounds.
    """
    def __init__(self, transition_points=None, restrict_domain=False):
        """
        Constructor.
        
        Args:
        transition_points: non-empty list of ordered pairs (x, y)
        restrict_domain: boolean indicating if evaluation points must be in defined domain of transition points.
                         default is False.
        """
        if transition_points is None:
            transition_points = list()
        if transition_points is None or not isinstance(transition_points,
                                                       list):
            assert Exception(
                'Illegal argument to SetwiseLinearFunction {0}'.format(
                    transition_points))
        self.__restrict_domain = restrict_domain
        self._setup(transition_points)

    def _setup(self, transition_points):
        self.__transition_points = sorted(transition_points,
                                          key=lambda x: x[0])
        self.__domain_start = self.__transition_points[0][0]
        self.__domain_end = self.__transition_points[
            len(self.__transition_points) - 1][0]

        self.ordered_map = OrderedMap(self.transition_points)

    @property
    def transition_points(self):
        return self.__transition_points

    @property
    def domain_start(self):
        return self.__domain_start

    @property
    def domain_end(self):
        return self.__domain_end

    @property
    def restrict_domain(self):
        return self.__restrict_domain

    def eval(self, x):
        if len(self.transition_points) == 0:
            raise Exception(
                "The function is undefined due to lack of transition points.")
        if self.restrict_domain:
            if x < self.domain_start or x > self.domain_end:
                raise Exception('Input {0} out of range [{1}, {2}]'.format(
                    x, self.domain_start, self.domain_end))
        key = self.ordered_map.floor(x)
        if key is None:
            return self.ordered_map.get(self.domain_start)
        if key == self.domain_end:
            return self.ordered_map.get(self.domain_end)
        else:
            return self.ordered_map.get(key)

    def add(self, transition_point):
        """
        Add a transition point to the stepwise function.
        
        Args:
          transition_point: Pair (x, y)  x, y are numerics.
        """
        new_points = list(self.transition_points)
        new_points.append(transition_point)
        self._setup(new_points)

    def add_and_clear_forward(self, transition_point):
        """
        Add a transition point to the stepwise function AND clear out higher (domain value) transition points.
        
        Args:
          transition_point: Pair (x, y)  x, y are numerics.
        """
        new_points = []
        elimination_value = transition_point[0]

        for p in self.transition_points:
            if p[0] < elimination_value:
                new_points.append(p)
        new_points.append(transition_point)

        self._setup(new_points)