"
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "a"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "id": "c347edb1-78b3-4963-a503-b877597c2ee5",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "[[{px: 0.73, py: 0.862, pz: -0.129}, {px: 0.746, py: 0.614, pz: ..., ...}],\n",
+ " [],\n",
+ " [{px: 0.493, py: -0.633, pz: -0.413}, {px: 0.836, py: -1.77, ...}],\n",
+ " [{px: -0.58, py: -0.586, pz: -0.513}, {...}, ..., {px: -0.201, py: 1.52, ...}],\n",
+ " [{px: -0.474, py: 1.6, pz: -0.1}, {px: 0.218, py: 0.155, pz: 0.834}],\n",
+ " [{px: -0.881, py: -0.183, pz: -0.725}, {px: -0.108, py: -0.889, ...}],\n",
+ " [{px: -1.77, py: 2.04, pz: 0.896}],\n",
+ " [{px: -1.08, py: -0.591, pz: -0.0674}, {px: -0.183, py: -0.289, ...}],\n",
+ " [{px: -1.08, py: -1.15, pz: 2.6}],\n",
+ " [{px: -0.419, py: -0.363, pz: -0.563}, {px: -2.48, py: -0.228, ...}]]\n",
+ "--------------------------------------------------------------------------------\n",
+ "backend: cpu\n",
+ "nbytes: 544 B\n",
+ "type: 10 * var * Momentum3D[\n",
+ " px: float64,\n",
+ " py: float64,\n",
+ " pz: float64\n",
+ "]
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 8,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "b"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7a6e73c4-cc2c-4cb5-9807-13c1bc970f78",
+ "metadata": {},
+ "source": [
+ "Awkward Array uses array-at-a-time functions like NumPy, so if we want to compute dot products of each vector in `a` with every vector of each list in `b`, we'd say:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "id": "144ee86e-2b47-4526-9d6b-3d490be69ba8",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "[[0.347, -1.32],\n",
+ " [],\n",
+ " [-0.035, -0.385],\n",
+ " [-0.0551, 0.194, 2.28, -2.86, -2.39],\n",
+ " [-0.173, -0.782],\n",
+ " [-0.807, 0.704],\n",
+ " [-0.128],\n",
+ " [-1.35, -0.446],\n",
+ " [0.945],\n",
+ " [-1.11, -5.58]]\n",
+ "--------------------------------------\n",
+ "backend: cpu\n",
+ "nbytes: 240 B\n",
+ "type: 10 * var * float64
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 9,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "a.dot(b)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1088c2a6-e744-4308-bd74-4ed9471d3bd1",
+ "metadata": {},
+ "source": [
+ "Note that `a` and `b` have different numbers of vectors, but the same array lengths. The operation above [broadcasts](https://awkward-array.org/doc/main/user-guide/how-to-math-broadcasting.html) array `a` into `b`, like the following code:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "id": "9edab13c-5b8e-47f2-afac-c0dd7241a8ca",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "[0.3470024410105361 -1.32262374856204 ]\n",
+ "[]\n",
+ "[-0.0350058354646221 -0.3845727581312185 ]\n",
+ "[-0.05513156034267678 0.1939866533163302 2.2806023784977056 -2.861051860111839 -2.3860250251022475 ]\n",
+ "[-0.17338156209593328 -0.7816799910864897 ]\n",
+ "[-0.8071770038569903 0.7044860439866077 ]\n",
+ "[-0.1279745100114199 ]\n",
+ "[-1.3483450919978617 -0.44626327125953613 ]\n",
+ "[0.9449043237160631 ]\n",
+ "[-1.1124522691465186 -5.579496184145224 ]\n"
+ ]
+ }
+ ],
+ "source": [
+ "for i in range(len(a)):\n",
+ " print(\"[\", end=\"\")\n",
+ "\n",
+ " for j in range(len(b[i])):\n",
+ " out = a[i].dot(b[i, j])\n",
+ "\n",
+ " print(out, end=\" \")\n",
+ "\n",
+ " print(\"]\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0e17784d-a838-4c87-a708-f530bd0fbe59",
+ "metadata": {},
+ "source": [
+ "Like NumPy, the array-at-a-time expression is more concise and faster:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "id": "1e3ffd74-469d-4ccd-984d-706413442700",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "a = array_of_momentum3d(10000)\n",
+ "b = array_of_lists_of_momentum3d(1.5, 10000)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "id": "135e44f1-7e25-49ef-8805-8638b3d0e9be",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "9.08 s ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)\n"
+ ]
+ }
+ ],
+ "source": [
+ "%%timeit -n1 -r1\n",
+ "\n",
+ "out = np.zeros(10000)\n",
+ "\n",
+ "for i in range(len(a)):\n",
+ " for j in range(len(b[i])):\n",
+ " out[i] += a[i].dot(b[i, j])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "id": "6b4d2c04-9034-4558-905a-af4539be1d40",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "2.44 ms ± 20.2 μs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n"
+ ]
+ }
+ ],
+ "source": [
+ "%%timeit\n",
+ "\n",
+ "out = np.sum(a.dot(b), axis=1)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cd509b13-8e87-40b0-b478-bb40154dd5c1",
+ "metadata": {},
+ "source": [
+ "(Note the units.)\n",
+ "\n",
+ "Just as with NumPy, all of the coordinate transformations and vector operations are implemented for Awkward Arrays of vectors."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "716cd51c-88ec-42e7-89ae-719cef7e4368",
+ "metadata": {},
+ "source": [
+ "## Some troubleshooting hints"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "904561c9-b998-4e4a-8ce1-e799931d9285",
+ "metadata": {},
+ "source": [
+ "Make sure that the Vector behaviors are actually installed and applied to your data. In the data type, the record type should appear as `\"Vector2D\"`, `\"Momentum2D\"`, `\"Vector3D\"`, `\"Momentum3D\"`, `\"Vector4D\"`, or `\"Momentum4D\"`, rather than the generic curly brackets `{` and `}`, and if you extract one record from the array, can you perform a vector operation on it?\n",
+ "\n",
+ "Make sure that your arrays broadcast the way that you want them to. If the vector behaviors are clouding the picture, make simpler arrays with numbers in place of records. Can you add them with `+`? (Addition uses the same broadcasting rules as all other operations.)\n",
+ "\n",
+ "If your code runs but doesn't give the results you expect, try slicing the arrays to just the first two items with `arr[:2]`. Step through the calculation on just two elements, observing the results of each operation. Are they what you expect?"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "60db1ccb-8d0a-4bc8-9050-6f68b03e2ee4",
+ "metadata": {},
+ "source": [
+ "## Advanced: subclassing Awkward-Vector behaviors"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "00d4f231-46f3-41a0-8573-9564aad8b29b",
+ "metadata": {},
+ "source": [
+ "It is possible to write subclasses for Awkward-Vector behaviors as mixins to extend the vector functionalities. For instance, the `MomentumAwkward` classes can be extended in the following way:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "id": "967444cc-a4f1-4e2b-8289-3224333218f1",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "behavior = vector.backends.awkward.behavior\n",
+ "\n",
+ "\n",
+ "@ak.mixin_class(behavior)\n",
+ "class TwoVector(vector.backends.awkward.MomentumAwkward2D):\n",
+ " pass\n",
+ "\n",
+ "\n",
+ "@ak.mixin_class(behavior)\n",
+ "class ThreeVector(vector.backends.awkward.MomentumAwkward3D):\n",
+ " pass\n",
+ "\n",
+ "\n",
+ "# required for transforming vectors\n",
+ "# the class names must always end with \"Array\"\n",
+ "TwoVectorArray.ProjectionClass2D = TwoVectorArray # noqa: F821\n",
+ "TwoVectorArray.ProjectionClass3D = ThreeVectorArray # noqa: F821\n",
+ "TwoVectorArray.MomentumClass = TwoVectorArray # noqa: F821\n",
+ "\n",
+ "ThreeVectorArray.ProjectionClass2D = TwoVectorArray # noqa: F821\n",
+ "ThreeVectorArray.ProjectionClass3D = ThreeVectorArray # noqa: F821\n",
+ "ThreeVectorArray.MomentumClass = ThreeVectorArray # noqa: F821"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "id": "42ea1b53-6003-4294-ac52-3e014eab92b7",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "[[{pt: 1, phi: 1.2}, {pt: 2, phi: 1.4}],\n",
+ " [],\n",
+ " [{pt: 3, phi: 1.6}],\n",
+ " [{pt: 4, phi: 3.4}]]\n",
+ "------------------------------------------------------------\n",
+ "backend: cpu\n",
+ "nbytes: 104 B\n",
+ "type: 4 * var * TwoVector[\n",
+ " pt: int64,\n",
+ " phi: float64\n",
+ "]
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 15,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "vec = ak.zip(\n",
+ " {\n",
+ " \"pt\": [[1, 2], [], [3], [4]],\n",
+ " \"phi\": [[1.2, 1.4], [], [1.6], [3.4]],\n",
+ " },\n",
+ " with_name=\"TwoVector\",\n",
+ " behavior=behavior,\n",
+ ")\n",
+ "vec"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c2889f3f-5fb3-42ea-bd5d-8c0135aa7c81",
+ "metadata": {},
+ "source": [
+ "The binary operators are not automatically registered by Awkward, but Vector methods can be used to perform operations on subclassed vectors."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "id": "b4ecc08c-253b-46b7-a78a-1aca4558d863",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "[[{rho: 2, phi: 1.2}, {rho: 4, phi: 1.4}],\n",
+ " [],\n",
+ " [{rho: 6, phi: 1.6}],\n",
+ " [{rho: 8, phi: -2.88}]]\n",
+ "---------------------------------------------------------------\n",
+ "backend: cpu\n",
+ "nbytes: 104 B\n",
+ "type: 4 * var * TwoVector[\n",
+ " rho: float64,\n",
+ " phi: float64\n",
+ "]
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 16,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "vec.add(vec)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "41426373-4492-4ff6-9496-3e5d88ef630e",
+ "metadata": {},
+ "source": [
+ "Similarly, other vector methods can be used by the new methods internally."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 17,
+ "id": "2c05135c-ba70-4b24-9d9f-2b04f72bf1ce",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import numbers"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "id": "8e24d10e-a1ab-4614-9e8e-62a6378c0864",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "@ak.mixin_class(behavior)\n",
+ "class LorentzVector(vector.backends.awkward.MomentumAwkward4D):\n",
+ " @ak.mixin_class_method(np.divide, {numbers.Number})\n",
+ " def divide(self, factor):\n",
+ " return self.scale(1 / factor)\n",
+ "\n",
+ "\n",
+ "# required for transforming vectors\n",
+ "# the class names must always end with \"Array\"\n",
+ "LorentzVectorArray.ProjectionClass2D = TwoVectorArray # noqa: F821\n",
+ "LorentzVectorArray.ProjectionClass3D = ThreeVectorArray # noqa: F821\n",
+ "LorentzVectorArray.ProjectionClass4D = LorentzVectorArray # noqa: F821\n",
+ "LorentzVectorArray.MomentumClass = LorentzVectorArray # noqa: F821"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "id": "203112e0-217e-4dc5-8145-881d48c9cf08",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "[[{pt: 1, eta: 1.2, phi: 0.3, energy: 50}, {pt: 2, eta: 1.4, ...}],\n",
+ " [],\n",
+ " [{pt: 3, eta: 1.6, phi: 0.5, energy: 52}],\n",
+ " [{pt: 4, eta: 3.4, phi: 0.6, energy: 60}]]\n",
+ "-----------------------------------------------------------------------------------------------------\n",
+ "backend: cpu\n",
+ "nbytes: 168 B\n",
+ "type: 4 * var * LorentzVector[\n",
+ " pt: int64,\n",
+ " eta: float64,\n",
+ " phi: float64,\n",
+ " energy: int64\n",
+ "]
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 19,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "vec = ak.zip(\n",
+ " {\n",
+ " \"pt\": [[1, 2], [], [3], [4]],\n",
+ " \"eta\": [[1.2, 1.4], [], [1.6], [3.4]],\n",
+ " \"phi\": [[0.3, 0.4], [], [0.5], [0.6]],\n",
+ " \"energy\": [[50, 51], [], [52], [60]],\n",
+ " },\n",
+ " with_name=\"LorentzVector\",\n",
+ " behavior=behavior,\n",
+ ")\n",
+ "vec"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "id": "6bf279a8-fca7-4c16-aca8-90565818a646",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "[[{rho: 0.5, phi: 0.3, eta: 1.2, t: 25}, {rho: 1, phi: 0.4, ...}],\n",
+ " [],\n",
+ " [{rho: 1.5, phi: 0.5, eta: 1.6, t: 26}],\n",
+ " [{rho: 2, phi: 0.6, eta: 3.4, t: 30}]]\n",
+ "-----------------------------------------------------------------------------------------------------\n",
+ "backend: cpu\n",
+ "nbytes: 168 B\n",
+ "type: 4 * var * LorentzVector[\n",
+ " rho: float64,\n",
+ " phi: float64,\n",
+ " eta: float64,\n",
+ " t: float64\n",
+ "]
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 20,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "vec / 2"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 21,
+ "id": "6648d398-60e4-4a7d-bd88-a7dd4a35e8d0",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "[[{rho: 1, phi: 0.3}, {rho: 2, phi: 0.4}],\n",
+ " [],\n",
+ " [{rho: 3, phi: 0.5}],\n",
+ " [{rho: 4, phi: 0.6}]]\n",
+ "-------------------------------------------------------------\n",
+ "backend: cpu\n",
+ "nbytes: 104 B\n",
+ "type: 4 * var * TwoVector[\n",
+ " rho: int64,\n",
+ " phi: float64\n",
+ "]
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 21,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "vec.like(vector.obj(x=1, y=2))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 22,
+ "id": "09854ba6-f571-42f8-95a9-b0ac52553cda",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "[[{rho: 1, phi: 0.3, eta: 1.2}, {rho: 2, phi: 0.4, eta: 1.4}],\n",
+ " [],\n",
+ " [{rho: 3, phi: 0.5, eta: 1.6}],\n",
+ " [{rho: 4, phi: 0.6, eta: 3.4}]]\n",
+ "---------------------------------------------------------------------------------\n",
+ "backend: cpu\n",
+ "nbytes: 136 B\n",
+ "type: 4 * var * ThreeVector[\n",
+ " rho: int64,\n",
+ " phi: float64,\n",
+ " eta: float64\n",
+ "]
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 22,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "vec.like(vector.obj(x=1, y=2, z=3))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "59cf3641-e227-4f0b-a1fa-99b0d196f02f",
+ "metadata": {},
+ "source": [
+ "It is also possible to manually add binary operations in vector's behavior dict to enable binary operations."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 23,
+ "id": "11778dd0-4726-43cc-817b-3326528dd144",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "_binary_dispatch_cls = {\n",
+ " \"TwoVector\": TwoVector,\n",
+ " \"ThreeVector\": ThreeVector,\n",
+ " \"LorentzVector\": LorentzVector,\n",
+ "}\n",
+ "_rank = [TwoVector, ThreeVector, LorentzVector]\n",
+ "\n",
+ "for lhs, lhs_to in _binary_dispatch_cls.items():\n",
+ " for rhs, rhs_to in _binary_dispatch_cls.items():\n",
+ " out_to = min(lhs_to, rhs_to, key=_rank.index)\n",
+ " behavior[(np.add, lhs, rhs)] = out_to.add\n",
+ " behavior[(np.subtract, lhs, rhs)] = out_to.subtract"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 24,
+ "id": "3088485c-70e4-461d-86b3-5db81148389f",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "[[{rho: 2, phi: 0.3, eta: 1.2, t: 100}, {rho: 4, phi: 0.4, eta: 1.4, ...}],\n",
+ " [],\n",
+ " [{rho: 6, phi: 0.5, eta: 1.6, t: 104}],\n",
+ " [{rho: 8, phi: 0.6, eta: 3.4, t: 120}]]\n",
+ "---------------------------------------------------------------------------------------------------\n",
+ "backend: cpu\n",
+ "nbytes: 168 B\n",
+ "type: 4 * var * LorentzVector[\n",
+ " rho: float64,\n",
+ " phi: float64,\n",
+ " eta: float64,\n",
+ " t: int64\n",
+ "]
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 24,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "vec + vec"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 25,
+ "id": "040e47cc-013d-423e-b5df-b0982a2279aa",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "[[{rho: 2, phi: 0.3}, {rho: 4, phi: 0.4}],\n",
+ " [],\n",
+ " [{rho: 6, phi: 0.5}],\n",
+ " [{rho: 8, phi: 0.6}]]\n",
+ "---------------------------------------------------------------\n",
+ "backend: cpu\n",
+ "nbytes: 104 B\n",
+ "type: 4 * var * TwoVector[\n",
+ " rho: float64,\n",
+ " phi: float64\n",
+ "]
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 25,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "vec.to_2D() + vec.to_2D()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e2259fbe-3eea-4fde-bedb-b5631f639ca3",
+ "metadata": {},
+ "source": [
+ "Finally, instead of manually registering the superclass ufuncs, one can use the utility `copy_behaviors` function to copy behavior items for a new subclass -"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 26,
+ "id": "4af071da-8612-49a2-9a56-7e49487cf866",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "behavior.update(ak._util.copy_behaviors(\"Vector2D\", \"TwoVector\", behavior))\n",
+ "behavior.update(ak._util.copy_behaviors(\"Vector3D\", \"ThreeVector\", behavior))\n",
+ "behavior.update(ak._util.copy_behaviors(\"Momentum4D\", \"LorentzVector\", behavior))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 27,
+ "id": "1c434751-a932-4694-92fc-9e48b51905b0",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "[[{rho: 2, phi: 0.3, eta: 1.2, t: 100}, {rho: 4, phi: 0.4, eta: 1.4, ...}],\n",
+ " [],\n",
+ " [{rho: 6, phi: 0.5, eta: 1.6, t: 104}],\n",
+ " [{rho: 8, phi: 0.6, eta: 3.4, t: 120}]]\n",
+ "------------------------------------------------------------------------------------------------\n",
+ "backend: cpu\n",
+ "nbytes: 168 B\n",
+ "type: 4 * var * Momentum4D[\n",
+ " rho: float64,\n",
+ " phi: float64,\n",
+ " eta: float64,\n",
+ " t: int64\n",
+ "]
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 27,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "vec + vec"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 28,
+ "id": "09e2bc41-340d-4ad6-82d8-f08cf869644a",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "[[{rho: 2, phi: 0.3}, {rho: 4, phi: 0.4}],\n",
+ " [],\n",
+ " [{rho: 6, phi: 0.5}],\n",
+ " [{rho: 8, phi: 0.6}]]\n",
+ "--------------------------------------------------------------\n",
+ "backend: cpu\n",
+ "nbytes: 104 B\n",
+ "type: 4 * var * Vector2D[\n",
+ " rho: float64,\n",
+ " phi: float64\n",
+ "]
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 28,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "vec.to_2D() + vec.to_2D()"
+ ]
}
],
"metadata": {
diff --git a/docs/src/make_awkward.md b/docs/src/make_awkward.md
index 44b10a2b..fae35119 100644
--- a/docs/src/make_awkward.md
+++ b/docs/src/make_awkward.md
@@ -1,6 +1,6 @@
# Making Awkward Arrays of vectors
-An Awkward Array of vectors is an Awkward Array containing appropriately named records, appropriately named fields, and the Vector behaviors registered in the array. Here's a complete example for illustration:
+An Awkward Array of vectors is an Awkward Array containing appropriately named records, appropriately named fields, and the Vector [behaviors](https://awkward-array.org/doc/main/reference/ak.behavior.html) registered in the array. Here's a complete example for illustration:
```python
>>> import awkward as ak
diff --git a/docs/src/numpy.ipynb b/docs/src/numpy.ipynb
index 2694368e..d830eb60 100644
--- a/docs/src/numpy.ipynb
+++ b/docs/src/numpy.ipynb
@@ -13,7 +13,7 @@
"id": "1144533f-0290-43f2-a9f2-adc9d042ed1a",
"metadata": {},
"source": [
- "First, [install](../index.md#installation) and import Vector and NumPy. (Vector requires NumPy, so if you can use Vector, you've already installed NumPy.)"
+ "First, [install](../index.md#installation) and import Vector and [NumPy](https://numpy.org/). (Vector requires NumPy, so if you can use Vector, you've already installed NumPy.)"
]
},
{
diff --git a/docs/src/sympy.ipynb b/docs/src/sympy.ipynb
index afc0b10d..df5e10ac 100644
--- a/docs/src/sympy.ipynb
+++ b/docs/src/sympy.ipynb
@@ -40,7 +40,7 @@
"id": "07e49af1-a2e4-43e9-b265-38d917456ce0",
"metadata": {},
"source": [
- "[SymPy](https://www.sympy.org/) is a computer algebra system like Mathematica and Maple. It primarily deals with algebraic expressions, rather than concrete numbers. However, all of the coordinate transformations and vector manipulations can be applied symbolically through Vector's SymPy backend.\n",
+ "SymPy is a computer algebra system like Mathematica and Maple. It primarily deals with algebraic expressions, rather than concrete numbers. However, all of the coordinate transformations and vector manipulations can be applied symbolically through Vector's SymPy backend.\n",
"\n",
"When comparing SymPy to the other backends, note that SymPy vector expressions have a different sign convention for operations on space-like and negative time-like 4D vectors. For all other backends, Vector's conventions were chosen to agree with popular HEP libraries, particularly [ROOT](https://root.cern), but for the SymPy backend, those conventions would insert piecewise if-then branches, which would complicate symbolic expressions.\n",
"\n",