[PEAK] Computed sets

Adam Atlas adam at atlas.st
Fri Mar 13 22:22:36 EDT 2009


I'm writing a module based on Trellis which provides several Set-like  
objects, which can generally be used like Set or FrozenSet (plus the  
Trellis .added and .removed attributes) but are generated dynamically  
from some source sets, either by filtering one source set or by  
applying some standard set operation (union, intersect, difference,  
symmetric difference) to two source sets. The idea is to do this more  
efficiently by watching for changes in the source sets and changing  
the computed set appropriately, rather than having, say, a  
trellis.compute(lambda self: self.set1.union(self.set2)), which would  
require the whole set to be rebuilt any time set1 or set2 change at  
all, and also wouldn't expose the .added and .removed attributes.

So here's how I'm doing it right now. Before I go further I just  
thought I'd post it here to see if I'm on the right track, or if  
there's anything wrong with this general approach.


class FilteredSubset(sets.BaseSet, trellis.Component):
     source = trellis.make(trellis.Set, writable=True)
     condition = trellis.attr(lambda self, val: True)
     _data = trellis.Set._data

     def __init__(self, source=None, condition=None, **kw):
         trellis.Component.__init__(self, **kw)
         if condition is not None:
             self.condition = condition
         if source is not None:
             self.source = source
             self._data.update((k, True) for k in source._data if  
self.condition(k))

     @trellis.compute
     def added(self):
         return set(k for k in self.source.added if self.condition(k))

     @trellis.compute
     def removed(self):
         return set(k for k in self.source.removed if k in self)



class UnionSet(sets.BaseSet, trellis.Component):
     source1 = trellis.make(trellis.Set, writable=True)
     source2 = trellis.make(trellis.Set, writable=True)
     _data = trellis.Set._data

     def __init__(self, source1=None, source2=None, **kw):
         trellis.Component.__init__(self, **kw)
         if source1 is not None:
             self.source1 = source1
             self._data.update(dict.fromkeys(source1, True))
         if source2 is not None:
             self.source2 = source2
             self._data.update(dict.fromkeys(source2, True))

     @trellis.compute
     def added(self):
         '''
         something is added to UnionSet if it is added to at least one  
source
         set and it was not already in either source set
         '''
         return self.source1.added.difference(self.source2).union(
             self.source2.added.difference(self.source1))

     @trellis.compute
     def removed(self):
         '''
         something is removed from UnionSet if it is removed from both  
source
         sets, or if it is removed from one source set and it is not  
in the
         other source set
         '''
         return self.source1.removed.difference(self.source2).union(
             self.source2.removed.difference(self.source1))


More information about the PEAK mailing list