def test_not_eq_same_length_sparse(self): for eg in self.examples: s = SparseTuple(eg) t = tuple(range(99, 99 + len(eg))) self.assert_(len(s) == len(t), (s, t)) if len(s) > 0: u = SparseTuple(t[:-1] + (999, )) self.assert_(not s == u, (s, u))
def test_construction(self): for eg in self.examples: sparse = SparseTuple(eg) d = {} for i, e in enumerate(eg): if e != 0: d[i] = e sparse2 = SparseTuple(len(eg), d) self.assertEquals(sparse, sparse2)
def test_set_item_zero(self): """__setitem__ with zero gives zero.""" for eg in self.examples: sparse = SparseTuple(eg) for i, x in enumerate(eg): sparse[i] = 0 self.assertEquals(0, sparse[i])
def test_set_item_same(self): """__setitem__ with same item gives no change.""" for eg in self.examples: sparse = SparseTuple([0 for x in eg]) for i, x in enumerate(eg): sparse[i] = x self.assertEquals(x, sparse[i])
def test_get_slice(self): for eg in self.examples: sparse = SparseTuple(eg) for i in range(len(eg)): for j in range(i, len(eg)): s = sparse[i:j] for k, x in enumerate(eg[i:j]): self.assertEquals(s[k], x)
def test_repr(self): for eg in self.examples: sparse = SparseTuple(eg) d = {} for i, e in enumerate(eg): if e != 0: d[i] = e self.assertEquals(repr(sparse), 'SparseTuple(%d, %s)' % (len(eg), repr(d)))
def test_negative_value(self): """Ensure that a tuple with negative value throws exception.""" for eg in self.examples: try: sparse = SparseTuple(eg) except NegativeIntegerError: pass else: self.assert_(0, 'Should throw exception at negative item.')
def test_negative_set_item(self): """Ensure that we cannot try to set a negative value.""" p = SparseTuple(range(10)) try: p[0] = -1 except NegativeIntegerError: pass else: self.assert_(0, 'Cannot set a negative item.')
def test_not_eq_same_length_tuple(self): for eg in self.examples: s = SparseTuple(eg) t = tuple(range(99, 99 + len(eg))) self.assert_(len(s) == len(t), (s, t)) if len(s) > 0: self.assert_(not s == t, (s, t)) else: self.assert_(s == t, (s, t))
def test_hash(self): """Note that we only insist that sparse tuples can be used in the place of the equivalent tuple in a dictionary. This does not mean that they have to have the same hash, only that the lookup works correctly (which uses eq as well as hash).""" t = (0, 1, 2, 3, 4) p = SparseTuple(t) self.assert_(hash(t) == hash(p))
def test_as_dict_key(self): """ This test depends on has values being the same. We have deprecated this requirement. """ t = (0, 1, 2, 3, 4) p = SparseTuple(t) d = {} d[p] = -99.0 self.assert_(d.has_key(t)) self.assert_(d[t] == d[p]) self.assert_(d[t] == -99.0)
def test_not_eq_other(self): not_in_examples = tuple(range(51)) for eg in self.examples: s = SparseTuple(eg) self.assert_(not (s == not_in_examples), (s, not_in_examples))
def test_eq_self(self): for eg in self.examples: s = SparseTuple(eg) self.assert_(s == s, (s, s))
def test_eq_tuple_self(self): for eg in self.examples: s = SparseTuple(eg) self.assert_(s == eg, (s, eg))
def test_eq_to_tuple_self(self): for eg in self.examples: s = SparseTuple(eg) t = s.to_tuple() self.assert_(s == t, (s, t))
def test_to_tuple(self): for eg in self.examples: sparse = SparseTuple(eg) self.assertEquals(sparse.to_tuple(), tuple(eg))
def test_hash(self): empt = SparseTuple(()) self.assertEquals(hash(empt), hash(()))
class SparsePowers(PowersBase): """ A sparse representation of powers, using the SparseTuple class. We only store the non-zero powers. """ def __init__(self, *args): self._powers = SparseTuple(*args) def copy(self): return SparsePowers(self._powers._len, self._powers._i_to_e) def __repr__(self): return 'SparsePowers(%d, %s)' % (self._powers._len, repr(self._powers._i_to_e)) def __mul__(self, other): """ Efficient multiplication for sparse power objects. """ assert isinstance(other, SparsePowers) if self._powers._len == other._powers._len: temp = dict(self._powers._i_to_e) for i, p in other._powers._i_to_e.iteritems(): temp[i] = temp.get(i, 0) + p return SparsePowers(self._powers._len, temp) else: raise IndexError, "Mismatched Powers lengths" def __pow__(self, other): """ Efficient powers. """ if other < 0: raise ValueError temp = {} for i, p in self._powers.iteritems(): assert p > 0 temp[i] = p * other return SparsePowers(self._powers._len, temp) def __len__(self): return len(self._powers) def degree(self): """ Gives the degree of the Powers. Efficient for sparse powers. """ return sum(self._powers._i_to_e.itervalues()) def diff(self, var): """ Returns a pair of multiplier, differentiated monomial. """ if var < 0 or var >= self._powers._len: raise IndexError(var) if self._powers.has_key(var): d = dict(self._powers._i_to_e) p = self._powers[var] assert p > 0 d[var] = p - 1 return float(p), SparsePowers(self._powers._len, d) else: return 0.0, SparsePowers(self._powers._len, {}) #collapse for economy def diff_pow(self, var, pow): """ Returns a pair of multiplier, differentiated monomial. """ assert isinstance(var, int) assert isinstance(pow, int) if pow <= 0: return 1.0, self assert pow > 0 if var < 0 or var >= self._powers._len: raise IndexError(var) if self._powers.has_key(var): p = self._powers[var] if pow <= p: d = dict(self._powers._i_to_e) c = p for i in xrange(1, pow): c *= (p - i) if pow == p: del d[var] else: d[var] -= pow return float(c), SparsePowers(self._powers._len, d) return 0.0, SparsePowers(self._powers._len, {}) #collapse for economy def to_tuple(self): return self._powers.to_tuple() def __hash__(self): """ This is potentially very inefficient. In C++ we will use Comparators instead of hashes. """ return self._powers.__hash__() def __eq__(self, other): if isinstance(other, tuple): return self._powers == other return self._powers == other._powers def __ne__(self, other): return not self.__eq__(other) def __lt__(self, other): return self._powers < other._powers def __le__(self, other): return self._powers <= other._powers def __gt__(self, other): return self._powers > other._powers def __ge__(self, other): return self._powers >= other._powers def __getitem__(self, i): return self._powers[i] def __getslice__(self, i, j): return self._powers.__getslice__(i, j) def __call__(self, args): """ Call on numerical arguments. """ if len(self._powers) == len(args): result = 1.0 for i, p in self._powers._i_to_e.iteritems(): result *= args[i]**p return result else: raise IndexError, "Wrong number of arguments"
def __init__(self, *args): self._powers = SparseTuple(*args)
def test_len(self): empt = SparseTuple(()) self.assertEquals(len(empt), len(()))
def test_iter(self): for eg in self.examples: sparse = SparseTuple(eg) t = tuple([x for x in sparse]) self.assertEquals(t, eg)
def test_len(self): for eg in self.examples: sparse = SparseTuple(eg) self.assertEquals(len(sparse), len(eg))
def test_eq_copy(self): for eg in self.examples: s = SparseTuple(eg) v = SparseTuple(eg) self.assert_(s == v, (s, v))
def test_get_item(self): """__getitem__ should return relevant values.""" for eg in self.examples: sparse = SparseTuple(eg) for i, x in enumerate(eg): self.assertEquals(x, sparse[i])
def test_both_constructors(self): for eg in self.examples: d = self._tuple_to_nonzero_dict(eg) p0 = SparseTuple(eg) p1 = SparseTuple(len(eg), d) self.assertEquals(p0, p1)
def test_eq_to_tuple(self): t = (0, 1, 2, 3, 4) p = SparseTuple(t) self.assert_(t == p)
def test_no_zeroth_element(self): empt = SparseTuple(()) self.assertRaises(IndexError, empt.__getitem__, 0)
def test_str(self): for eg in self.examples: sparse = SparseTuple(eg) self.assertEquals(str(sparse), str(eg))
class SparsePowers(PowersBase): """ A sparse representation of powers, using the SparseTuple class. We only store the non-zero powers. """ def __init__(self, *args): self._powers = SparseTuple(*args) def copy(self): return SparsePowers(self._powers._len, self._powers._i_to_e) def __repr__(self): return 'SparsePowers(%d, %s)'%(self._powers._len, repr(self._powers._i_to_e)) def __mul__(self, other): """ Efficient multiplication for sparse power objects. """ assert isinstance(other, SparsePowers) if self._powers._len == other._powers._len: temp = dict(self._powers._i_to_e) for i, p in other._powers._i_to_e.iteritems(): temp[i] = temp.get(i, 0) + p return SparsePowers(self._powers._len, temp) else: raise IndexError, "Mismatched Powers lengths" def __pow__(self, other): """ Efficient powers. """ if other<0: raise ValueError temp = {} for i, p in self._powers.iteritems(): assert p > 0 temp[i] = p * other return SparsePowers(self._powers._len, temp) def __len__(self): return len(self._powers) def degree(self): """ Gives the degree of the Powers. Efficient for sparse powers. """ return sum(self._powers._i_to_e.itervalues()) def diff(self, var): """ Returns a pair of multiplier, differentiated monomial. """ if var<0 or var>=self._powers._len: raise IndexError(var) if self._powers.has_key(var): d = dict(self._powers._i_to_e) p = self._powers[var] assert p > 0 d[var] = p-1 return float(p), SparsePowers(self._powers._len, d) else: return 0.0, SparsePowers(self._powers._len, {}) #collapse for economy def diff_pow(self, var, pow): """ Returns a pair of multiplier, differentiated monomial. """ assert isinstance(var, int) assert isinstance(pow, int) if pow <= 0: return 1.0, self assert pow > 0 if var<0 or var>=self._powers._len: raise IndexError(var) if self._powers.has_key(var): p = self._powers[var] if pow <= p: d = dict(self._powers._i_to_e) c = p for i in xrange(1, pow): c *= (p-i) if pow == p: del d[var] else: d[var] -= pow return float(c), SparsePowers(self._powers._len, d) return 0.0, SparsePowers(self._powers._len, {}) #collapse for economy def to_tuple(self): return self._powers.to_tuple() def __hash__(self): """ This is potentially very inefficient. In C++ we will use Comparators instead of hashes. """ return self._powers.__hash__() def __eq__(self, other): if isinstance(other, tuple): return self._powers == other return self._powers == other._powers def __ne__(self, other): return not self.__eq__(other) def __lt__(self, other): return self._powers < other._powers def __le__(self, other): return self._powers <= other._powers def __gt__(self, other): return self._powers > other._powers def __ge__(self, other): return self._powers >= other._powers def __getitem__(self, i): return self._powers[i] def __getslice__(self, i, j): return self._powers.__getslice__(i, j) def __call__(self, args): """ Call on numerical arguments. """ if len(self._powers) == len(args): result = 1.0 for i, p in self._powers._i_to_e.iteritems(): result *= args[i] ** p return result else: raise IndexError, "Wrong number of arguments"