Add files via upload

This commit is contained in:
Peter Norvig 2024-12-28 00:20:07 -08:00 committed by GitHub
parent 9360ec80ea
commit d74e7cbcec
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 2997 additions and 4108 deletions

File diff suppressed because one or more lines are too long

View File

@ -420,11 +420,12 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 20, "execution_count": 154,
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"Point = Tuple[int, ...] # Type for points\n", "Point = Tuple[int, ...] # Type for points\n",
"Point2D = Tuple[int, int] # Type for 2-dimensional point\n",
"Vector = Point # E.g., (1, 0) can be a point, or can be a direction, a Vector\n", "Vector = Point # E.g., (1, 0) can be a point, or can be a direction, a Vector\n",
"Zero = (0, 0)\n", "Zero = (0, 0)\n",
"\n", "\n",
@ -444,43 +445,40 @@
"def Ys(points) -> Tuple[int]: \"Y coordinates of a collection of points\"; return mapt(Y_, points)\n", "def Ys(points) -> Tuple[int]: \"Y coordinates of a collection of points\"; return mapt(Y_, points)\n",
"def Zs(points) -> Tuple[int]: \"X coordinates of a collection of points\"; return mapt(Z_, points)\n", "def Zs(points) -> Tuple[int]: \"X coordinates of a collection of points\"; return mapt(Z_, points)\n",
"\n", "\n",
"def add(p: Point, q: Point) -> Point: \"Add points\"; return mapt(operator.add, p, q)\n", "## I define point arithmetic for general points and separate versions for 2D points,\n",
"def sub(p: Point, q: Point) -> Point: \"Subtract points\"; return mapt(operator.sub, p, q)\n", "## because profiling showed the 2D versions are significantly faster\n",
"def neg(p: Point) -> Vector: \"Negate a point\"; return mapt(operator.neg, p)\n",
"def mul(p: Point, k: float) -> Vector: \"Scalar multiply\"; return tuple(k * c for c in p)\n",
"\n", "\n",
"def distance(p: Point, q: Point) -> float:\n", "def add3(p: Point, q: Point) -> Point: \"Add points\"; return mapt(operator.add, p, q)\n",
" \"\"\"Euclidean (L2) distance between two points.\"\"\"\n", "def sub3(p: Point, q: Point) -> Point: \"Subtract points\"; return mapt(operator.sub, p, q)\n",
" d = sum((pi - qi) ** 2 for pi, qi in zip(p, q)) ** 0.5\n", "def mul3(p: Point, k: float) -> Vector: \"Scalar multiply\"; return tuple(k * c for c in p)\n",
" return int(d) if d.is_integer() else d\n", "def neg(p: Point2D) -> Vector: \"Negate a 2D Point\"; return mapt(operator.neg, p)\n",
"\n",
"def add(p: Point2D, q: Point2D) -> Point2D: \"Add 2D Points\"; return (p[0] + q[0], p[1] + q[1])\n",
"def sub(p: Point2D, q: Point2D) -> Point2D: \"Subtract 2D Points\"; return (p[0] - q[0], p[1] - q[1])\n",
"def mul(p: Point2D, k: float) -> Point2D: \"Scalar multiply\"; return (p[0] * k, p[1] * k)\n",
"def neg(p: Point2D) -> Vector: \"Negate a 2D Point\"; return (-p[0], -p[1])\n",
"\n", "\n",
"def slide(points: Set[Point], delta: Vector) -> Set[Point]: \n", "def slide(points: Set[Point], delta: Vector) -> Set[Point]: \n",
" \"\"\"Slide all the points in the set of points by the amount delta.\"\"\"\n", " \"\"\"Slide all the points in the set of points by the amount delta.\"\"\"\n",
" return {add(p, delta) for p in points}\n", " return {add(p, delta) for p in points}\n",
"\n", "\n",
"def make_turn(facing:Vector, turn:str) -> Vector:\n", "def make_turn(facing: Vector, turn: str) -> Vector:\n",
" \"\"\"Turn 90 degrees left or right. `turn` can be 'L' or 'Left' or 'R' or 'Right' or lowercase.\"\"\"\n", " \"\"\"Turn 90 degrees left or right. `turn` can be 'L' or 'Left' or 'R' or 'Right' or lowercase.\"\"\"\n",
" (x, y) = facing\n", " (x, y) = facing\n",
" return (y, -x) if turn[0] in ('L', 'l') else (-y, x)\n", " return (y, -x) if turn[0] in ('L', 'l') else (-y, x)\n",
"\n", "\n",
"# Profiling found that `add` and `taxi_distance` were speed bottlenecks; \n", "def distance(p: Point2D, q: Point2D) -> float:\n",
"# I define below versions that are specialized for 2D points only.\n", " \"\"\"Euclidean (L2) distance between two points.\"\"\"\n",
"\n", " d = sum((pi - qi) ** 2 for pi, qi in zip(p, q)) ** 0.5\n",
"def add2(p: Point, q: Point) -> Point: \n", " return int(d) if d.is_integer() else d\n",
" \"\"\"Specialized version of point addition for 2D Points only. Faster.\"\"\"\n", " \n",
" return (p[0] + q[0], p[1] + q[1])\n", "def distance_squared(p: Point2D, q: Point2D) -> float:\n",
"\n",
"def sub2(p: Point, q: Point) -> Point: \n",
" \"\"\"Specialized version of point subtraction for 2D Points only. Faster.\"\"\"\n",
" return (p[0] - q[0], p[1] - q[1])\n",
"\n",
"def taxi_distance(p: Point, q: Point) -> int:\n",
" \"\"\"Manhattan (L1) distance between two 2D Points.\"\"\"\n",
" return abs(p[0] - q[0]) + abs(p[1] - q[1])\n",
"\n",
"def distance_squared(p: Point, q: Point) -> float:\n",
" \"\"\"Square of the Euclidean (L2) distance between two 2D points.\"\"\"\n", " \"\"\"Square of the Euclidean (L2) distance between two 2D points.\"\"\"\n",
" return (p[0] - q[0]) ** 2 + (p[1] - q[1]) ** 2" " return (p[0] - q[0]) ** 2 + (p[1] - q[1]) ** 2\n",
" \n",
"def taxi_distance(p: Point2D, q: Point2D) -> int:\n",
" \"\"\"Manhattan (L1) distance between two 2D Points.\"\"\"\n",
" return abs(p[0] - q[0]) + abs(p[1] - q[1])"
] ]
}, },
{ {
@ -545,15 +543,15 @@
" def follow_line(self, start: Point, direction: Vector) -> Iterable[Point]:\n", " def follow_line(self, start: Point, direction: Vector) -> Iterable[Point]:\n",
" while self.in_range(start):\n", " while self.in_range(start):\n",
" yield start\n", " yield start\n",
" start = add2(start, direction)\n", " start = add(start, direction)\n",
"\n", "\n",
" def copy(self): \n", " def copy(self): \n",
" return Grid(self, directions=self.directions, skip=self.skip, default=self.default)\n", " return Grid(self, directions=self.directions, skip=self.skip, default=self.default)\n",
" \n", " \n",
" def neighbors(self, point) -> List[Point]:\n", " def neighbors(self, point) -> List[Point]:\n",
" \"\"\"Points on the grid that neighbor `point`.\"\"\"\n", " \"\"\"Points on the grid that neighbor `point`.\"\"\"\n",
" return [add2(point, Δ) for Δ in self.directions \n", " return [add(point, Δ) for Δ in self.directions \n",
" if (add2(point, Δ) in self) \n", " if (add(point, Δ) in self) \n",
" or (self.default not in (KeyError, None))]\n", " or (self.default not in (KeyError, None))]\n",
" \n", " \n",
" def neighbor_contents(self, point) -> Iterable:\n", " def neighbor_contents(self, point) -> Iterable:\n",
@ -790,6 +788,33 @@
" self[attr] = value" " self[attr] = value"
] ]
}, },
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def get_size(obj, seen: Optional[Set[int]] = None) -> int:\n",
" \"\"\"Recursively finds size of objects.\"\"\"\n",
" seen = set() if seen is None else seen\n",
"\n",
" if id(obj) in seen: return 0 # to handle self-referential objects\n",
" seen.add(id(obj))\n",
"\n",
" size = sys.getsizeof(obj, 0) # pypy3 always returns default (necessary)\n",
" if isinstance(obj, dict):\n",
" size += sum(getSize(v, seen) + getSize(k, seen) for k, v in obj.items())\n",
" elif hasattr(obj, '__dict__'):\n",
" size += getSize(obj.__dict__, seen)\n",
" elif hasattr(obj, '__slots__'): # in case slots are in use\n",
" slotList = [getattr(C, \"__slots__\", []) for C in obj.__class__.__mro__]\n",
" slotList = [[slot] if isinstance(slot, str) else slot for slot in slotList]\n",
" size += sum(getSize(getattr(obj, a, None), seen) for slot in slotList for a in slot)\n",
" elif hasattr(obj, '__iter__') and not isinstance(obj, (str, bytes, bytearray)):\n",
" size += sum(getSize(i, seen) for i in obj)\n",
" return size"
]
},
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": {}, "metadata": {},