| 48 | | |
|---|
| 49 | | # Compatibility with Python 2.2 and 2.3 |
|---|
| 50 | | |
|---|
| 51 | | # The AIMA code is designed to run in Python 2.2 and up (at some point, |
|---|
| 52 | | # support for 2.2 may go away; 2.2 was released in 2001, and so is over |
|---|
| 53 | | # 3 years old). The first part of this file brings you up to 2.4 |
|---|
| 54 | | # compatibility if you are running in Python 2.2 or 2.3: |
|---|
| 55 | | |
|---|
| 56 | | try: bool ## Introduced in 2.3 |
|---|
| 57 | | except NameError: |
|---|
| 58 | | class bool(int): |
|---|
| 59 | | "Simple implementation of Booleans, as in PEP 285" |
|---|
| 60 | | def __init__(self, val): self.val = val |
|---|
| 61 | | def __int__(self): return self.val |
|---|
| 62 | | def __repr__(self): return ('False', 'True')[self.val] |
|---|
| 63 | | |
|---|
| 64 | | True, False = bool(1), bool(0) |
|---|
| 65 | | |
|---|
| 66 | | try: sum ## Introduced in 2.3 |
|---|
| 67 | | except NameError: |
|---|
| 68 | | def sum(seq, start=0): |
|---|
| 69 | | """Sum the elements of seq. |
|---|
| 70 | | >>> sum([1, 2, 3]) |
|---|
| 71 | | 6 |
|---|
| 72 | | """ |
|---|
| 73 | | return reduce(operator.add, seq, start) |
|---|
| 74 | | |
|---|
| 75 | | try: enumerate ## Introduced in 2.3 |
|---|
| 76 | | except NameError: |
|---|
| 77 | | def enumerate(collection): |
|---|
| 78 | | """Return an iterator that enumerates pairs of (i, c[i]). PEP 279. |
|---|
| 79 | | >>> list(enumerate('abc')) |
|---|
| 80 | | [(0, 'a'), (1, 'b'), (2, 'c')] |
|---|
| 81 | | """ |
|---|
| 82 | | i = 0 |
|---|
| 83 | | it = iter(collection) |
|---|
| 84 | | while 1: |
|---|
| 85 | | yield (i, it.next()) |
|---|
| 86 | | i += 1 |
|---|
| 87 | | |
|---|
| 88 | | |
|---|
| 89 | | try: reversed ## Introduced in 2.4 |
|---|
| 90 | | except NameError: |
|---|
| 91 | | def reversed(seq): |
|---|
| 92 | | """Iterate over x in reverse order. |
|---|
| 93 | | >>> list(reversed([1,2,3])) |
|---|
| 94 | | [3, 2, 1] |
|---|
| 95 | | """ |
|---|
| 96 | | if hasattr(seq, 'keys'): |
|---|
| 97 | | raise ValueError("mappings do not support reverse iteration") |
|---|
| 98 | | i = len(seq) |
|---|
| 99 | | while i > 0: |
|---|
| 100 | | i -= 1 |
|---|
| 101 | | yield seq[i] |
|---|
| 102 | | |
|---|
| 103 | | |
|---|
| 104 | | try: sorted ## Introduced in 2.4 |
|---|
| 105 | | except NameError: |
|---|
| 106 | | def sorted(seq, cmp=None, key=None, reverse=False): |
|---|
| 107 | | """Copy seq and sort and return it. |
|---|
| 108 | | >>> sorted([3, 1, 2]) |
|---|
| 109 | | [1, 2, 3] |
|---|
| 110 | | """ |
|---|
| 111 | | seq2 = copy.copy(seq) |
|---|
| 112 | | seq2.sort(_make_cmp(cmp, key)) |
|---|
| 113 | | if reverse: |
|---|
| 114 | | seq2.reverse() |
|---|
| 115 | | return seq2 |
|---|
| 116 | | |
|---|
| 117 | | def _make_cmp(cmpfn=None, key=None): |
|---|
| 118 | | if not cmpfn and not key: return None |
|---|
| 119 | | elif cmpfn and not key: return cmpfn |
|---|
| 120 | | elif not cmpfn and key: return lambda x,y: cmp(key(x), key(y)) |
|---|
| 121 | | else: return lambda x,y: cmpfn(key(x), key(y)) |
|---|
| 122 | | |
|---|
| 123 | | try: |
|---|
| 124 | | set, frozenset ## set builtin introduced in 2.4 |
|---|
| 125 | | except NameError: |
|---|
| 126 | | try: |
|---|
| 127 | | import sets ## sets module introduced in 2.3 |
|---|
| 128 | | set, frozenset = sets.Set, sets.ImmutableSet |
|---|
| 129 | | except (NameError, ImportError): |
|---|
| 130 | | class BaseSet: |
|---|
| 131 | | "set type (see http://docs.python.org/lib/types-set.html)" |
|---|
| 132 | | |
|---|
| 133 | | |
|---|
| 134 | | def __init__(self, elements=[]): |
|---|
| 135 | | self.dict = {} |
|---|
| 136 | | for e in elements: |
|---|
| 137 | | self.dict[e] = 1 |
|---|
| 138 | | |
|---|
| 139 | | def __len__(self): |
|---|
| 140 | | return len(self.dict) |
|---|
| 141 | | |
|---|
| 142 | | def __iter__(self): |
|---|
| 143 | | for e in self.dict: |
|---|
| 144 | | yield e |
|---|
| 145 | | |
|---|
| 146 | | def __contains__(self, element): |
|---|
| 147 | | return element in self.dict |
|---|
| 148 | | |
|---|
| 149 | | def issubset(self, other): |
|---|
| 150 | | for e in self.dict.keys(): |
|---|
| 151 | | if e not in other: |
|---|
| 152 | | return False |
|---|
| 153 | | return True |
|---|
| 154 | | |
|---|
| 155 | | def issuperset(self, other): |
|---|
| 156 | | for e in other: |
|---|
| 157 | | if e not in self: |
|---|
| 158 | | return False |
|---|
| 159 | | return True |
|---|
| 160 | | |
|---|
| 161 | | |
|---|
| 162 | | def union(self, other): |
|---|
| 163 | | return type(self)(list(self) + list(other)) |
|---|
| 164 | | |
|---|
| 165 | | def intersection(self, other): |
|---|
| 166 | | return type(self)([e for e in self.dict if e in other]) |
|---|
| 167 | | |
|---|
| 168 | | def difference(self, other): |
|---|
| 169 | | return type(self)([e for e in self.dict if e not in other]) |
|---|
| 170 | | |
|---|
| 171 | | def symmetric_difference(self, other): |
|---|
| 172 | | return type(self)([e for e in self.dict if e not in other] + |
|---|
| 173 | | [e for e in other if e not in self.dict]) |
|---|
| 174 | | |
|---|
| 175 | | def copy(self): |
|---|
| 176 | | return type(self)(self.dict) |
|---|
| 177 | | |
|---|
| 178 | | def __repr__(self): |
|---|
| 179 | | elements = ", ".join(map(str, self.dict)) |
|---|
| 180 | | return "%s([%s])" % (type(self).__name__, elements) |
|---|
| 181 | | |
|---|
| 182 | | __le__ = issubset |
|---|
| 183 | | __ge__ = issuperset |
|---|
| 184 | | __or__ = union |
|---|
| 185 | | __and__ = intersection |
|---|
| 186 | | __sub__ = difference |
|---|
| 187 | | __xor__ = symmetric_difference |
|---|
| 188 | | |
|---|
| 189 | | class frozenset(BaseSet): |
|---|
| 190 | | "A frozenset is a BaseSet that has a hash value and is immutable." |
|---|
| 191 | | |
|---|
| 192 | | def __init__(self, elements=[]): |
|---|
| 193 | | BaseSet.__init__(elements) |
|---|
| 194 | | self.hash = 0 |
|---|
| 195 | | for e in self: |
|---|
| 196 | | self.hash |= hash(e) |
|---|
| 197 | | |
|---|
| 198 | | def __hash__(self): |
|---|
| 199 | | return self.hash |
|---|
| 200 | | |
|---|
| 201 | | class set(BaseSet): |
|---|
| 202 | | "A set is a BaseSet that does not have a hash, but is mutable." |
|---|
| 203 | | |
|---|
| 204 | | def update(self, other): |
|---|
| 205 | | for e in other: |
|---|
| 206 | | self.add(e) |
|---|
| 207 | | return self |
|---|
| 208 | | |
|---|
| 209 | | def intersection_update(self, other): |
|---|
| 210 | | for e in self.dict.keys(): |
|---|
| 211 | | if e not in other: |
|---|
| 212 | | self.remove(e) |
|---|
| 213 | | return self |
|---|
| 214 | | |
|---|
| 215 | | def difference_update(self, other): |
|---|
| 216 | | for e in self.dict.keys(): |
|---|
| 217 | | if e in other: |
|---|
| 218 | | self.remove(e) |
|---|
| 219 | | return self |
|---|
| 220 | | |
|---|
| 221 | | def symmetric_difference_update(self, other): |
|---|
| 222 | | to_remove1 = [e for e in self.dict if e in other] |
|---|
| 223 | | to_remove2 = [e for e in other if e in self.dict] |
|---|
| 224 | | self.difference_update(to_remove1) |
|---|
| 225 | | self.difference_update(to_remove2) |
|---|
| 226 | | return self |
|---|
| 227 | | |
|---|
| 228 | | def add(self, element): |
|---|
| 229 | | self.dict[element] = 1 |
|---|
| 230 | | |
|---|
| 231 | | def remove(self, element): |
|---|
| 232 | | del self.dict[element] |
|---|
| 233 | | |
|---|
| 234 | | def discard(self, element): |
|---|
| 235 | | if element in self.dict: |
|---|
| 236 | | del self.dict[element] |
|---|
| 237 | | |
|---|
| 238 | | def pop(self): |
|---|
| 239 | | key, val = self.dict.popitem() |
|---|
| 240 | | return key |
|---|
| 241 | | |
|---|
| 242 | | def clear(self): |
|---|
| 243 | | self.dict.clear() |
|---|
| 244 | | |
|---|
| 245 | | __ior__ = update |
|---|
| 246 | | __iand__ = intersection_update |
|---|
| 247 | | __isub__ = difference_update |
|---|
| 248 | | __ixor__ = symmetric_difference_update |
|---|
| 249 | | |
|---|
| 250 | | |
|---|
| 251 | | |
|---|