Source code for pybs.utils.linearCombination

from numbers import Number


[docs]class LinearCombination(dict): """Class to represent linear combinations of arbitrary elements. """ __slots__ = ('_fast_setitem',) def __init__(self, iterable=None, *args, **kwds): self._fast_setitem = super(LinearCombination, self).__setitem__ super(LinearCombination, self).__init__() self.__iadd__(iterable) def __str__(self): return ' + '.join([str(self[element]) + '*' + str(element) for element in self])
[docs] def __missing__(self, key): """Called if an element is not in the :class:`LinearCombination`. If an element is not in the :class:`LinearCombination`, its coefficient is 0. """ return 0
[docs] def __setitem__(self, key, value): """Called when coefficients are set as e.g. ``linComb[elem]=4``. Ensures the coefficient is a ``Number``, and that the key is deleted if the coefficient is 0. """ if isinstance(value, Number): if value == 0: if key in self: del self[key] else: self._fast_setitem(key, value) else: raise TypeError( 'bad operand type. Values must be of type Number, not: ' + str(type(value)))
[docs] def __delitem__(self, elem): """Like dict.__delitem__() \ but does not raise KeyError for missing values. """ if elem in self: super(LinearCombination, self).__delitem__(elem)
[docs] def __iadd__(self, other): """Overload inplace addition (``self += other``). If `other` is a :class:`LinearCombination`, they are added as vectors, if not other is assumed to be an element and is bumped by 1.""" self_get = self.get if isinstance(other, LinearCombination): if self: for elem, count in other.iteritems(): self._fast_setitem(elem, self_get(elem, 0) + count) else: super(LinearCombination, self).update(other) elif other is not None: # WHY condition? self._fast_setitem(other, self_get(other, 0) + 1) return self
[docs] def __add__(self, other): """Overload addition (``self + other``). Same rule as above if `other` is not :class:`LinearCombination`. """ result = self.copy() result += other return result
[docs] def __isub__(self, other): """Overload inplace subtraction (``self -= other``). Same rule as above if `other` is not :class:`LinearCombination`. """ self_get = self.get if isinstance(other, LinearCombination): for elem, count in other.items(): self[elem] = self_get(elem, 0) - count else: self._fast_setitem(other, self_get(other, 0) - 1) return self
[docs] def __sub__(self, other): """Overload subtraction (``self - other``). Same rule as above if `other` is not :class:`LinearCombination`. """ result = self.copy() result -= other return result
[docs] def __mul__(self, other): """Overload multiplication, used for scalar multiplication (``self * num``). """ if isinstance(other, Number): result = LinearCombination() for key, value in self.iteritems(): result[key] = value * other return result else: return NotImplemented
[docs] def __rmul__(self, other): """Overload multiplication to deal with scalar multiplication \ from the right (``num * self``). """ return self * other
[docs] def dimensions(self): """Number of different elements in the multiset.""" return dict.__len__(self)
[docs] def copy(self): """Return an identical :class:`LinearCombination`.""" result = LinearCombination() result += self return result # def __reduce__(self): # Good for pickling. # return self.__class__, (dict(self),)
def __repr__(self): if not self: return '%s()' % self.__class__.__name__ items = ', '.join(map('%r: %r'.__mod__, self.most_common())) return '%s({%s})' % (self.__class__.__name__, items)