diff --git a/notebooks/v1sim.ipynb b/notebooks/v1sim.ipynb new file mode 100644 index 0000000..3a95e5c --- /dev/null +++ b/notebooks/v1sim.ipynb @@ -0,0 +1,215 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Version 1 Simulation\n", + "\n", + "The first version of this series is a basic control model. Given an elevation profile $H(x)$ and a time target, minimize energy usage.\n", + "We assume the time target is constant, since we are racing at a given overall pace. In other words, we already know the average speed $E(V) = dist/time$" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import jax.numpy as jnp\n", + "from jax import jit, vmap, lax\n", + "from jax import random\n", + "import matplotlib.pyplot as plt\n", + "\n", + "@jit\n", + "def _cov_math(t, s, H):\n", + " return 0.5 * (jnp.abs(t) ** 2 * H + jnp.abs(s) ** 2 * H - jnp.abs(t - s) ** 2 * H)\n", + "\n", + "\n", + "def _fbm_covariance(n, H) -> jnp.ndarray:\n", + " tidx = jnp.arange(1, n + 1)\n", + " t, s = jnp.meshgrid(tidx, tidx)\n", + "\n", + " # fBm covariance equation from wikipedia\n", + " cov = 0.5 * (jnp.abs(t) ** 2 * H + jnp.abs(s) ** 2 * H - jnp.abs(t - s) ** 2 * H)\n", + " return cov\n", + "\n", + "# generate terrain using fractional brownian motion\n", + "def gen_elevation_profile(rngkey: random.PRNGKey, n_steps: int, H: float):\n", + " t = jnp.linspace(0,1,n_steps)\n", + " cov = _fbm_covariance(n_steps, H)\n", + " # using the \"method 1\" (cholesky decomposition)\n", + " sigma = jnp.linalg.cholesky(cov)\n", + " # create a vector of n_steps gaussian normal values\n", + " v = random.normal(rngkey, shape=(n_steps))\n", + " # convert these to fbm lines\n", + "\n", + " fbm_samples = sigma * v\n", + "\n", + " return t, fbm_samples\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "An NVIDIA GPU may be present on this machine, but a CUDA-enabled jaxlib is not installed. Falling back to cpu.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[nan -0. -0. ... -0. -0. -0.]\n", + " [nan nan -0. ... -0. -0. -0.]\n", + " [nan nan nan ... -0. -0. -0.]\n", + " ...\n", + " [nan nan nan ... nan -0. -0.]\n", + " [nan nan nan ... nan nan -0.]\n", + " [nan nan nan ... nan nan nan]]\n" + ] + }, + { + "data": { + "image/png": "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zOmnn56PfvSjSZLOzs5MmDAhl112Wd7znvc865y6uroyduzYdHZ2prm5+Tm60udWVVV5ors3VffGPNH7RPoffzzdG59M1VOlp7c3/dWmPFFVebKnP709Xak2daevt0p/T2+qvv709Xfnyaou3X1V6vs3pafqSbWpJ/3d/anrr0tVVanqerMp9enur5L+x1PX05uqvy7p6099lVT1vemua0hPVZeG9KS36k19d2/SW5/6qiFJldT3pTv1SfrSm9409PYl/fVJf5X61D/1eN2o9KYuo9KT3qovDb1Jqir1eeocdQ196a5rSNKfvvSlobc/qepTVVVGZVTqGvrSUz8qvanPqPSkr+pLQ29dUlVpyKin/oc19OfJ+sanHh84R8N/O0f/c3OOhv93jqo76etNqoZnnqPhmedoqBqS5FnPUSXpa6z/wzzTl1FbOEdP6lKfTQOPb/UcPX1PneP/zbP252hIXUP1h2vd6jn+8LV/1nNUfRn1R1+3rZ/jj75uNTzHH3/tt3qOqjt127B+tvS139I5arZ+hn0NlrJ+hm8NlrB+il6DJayfgl/Darl+XhCvYTVbP6W/htVg/RT8GubvwB3531B1edrXl/5z2u/pTKm2tUNreie9u7s7K1euzOzZs//whPX1mT17dtra2jZ7TFtb26DxSTJnzpyB8b/5zW/S3t4+aMzYsWMzY8aMLZ5z06ZN6erqGrSV7omevkxb+N3UfXnvvO3at2TtW4/Iteefl97//Ugu/z/XZM2jJ+YtjzTm+Ovuz2l3fTTNp348//btMVn9vy9P683NebL5M5n/kkk557YxecvdC/K5rr/Pfn/3D/ndD3+U1987JWs6OrLzn/1DznzF/8yX72/J/xr9zznof30nm+6ZkY23/VvevH5m9vgf38knp7wrix+ekr987KJcPvb7+Z9XLE//Xb/O4U+8LY/Wjcor3rA0F77+XflA/zdydcvyzLnmZ2lad3ga/vO3eWcOyyv//KZ85U3H5/LuN+a0hsvzvT1vzksenZsx93XkqByVJ1/00rx61s/yjTcem4+MvirffXlb3vXd2zJ2/ZF58YO/T/dLds3+b/l5LnzzSVnSd2gWNF6d/7vX6ozrPCovefDRvKdhXnp2Hp9XHXpLru4/NKc3XZ0bXnFz/r8bVuWlXUdl54fWp7d5fF475+e5+NCTck11aD465ur8YO/V2WXDUWl+6NH8xeh56Rs7PpNn35Jrc2jO2OnqLN335hyxdFV2feyojP3d+vSPG5+pb/95Fs86Kd/Ooflo47U5cumqjH/sqIxb+2je2zgv1bjxec1bbsl3cmjO3OnqLNv35hy1dFVaHjsqxzXOS8aNz+ve/vNcMuukXJdD87HGa3P00lXZ/bGjssvaR3N847z07TIhl846Kdfn0Jy909X5l31vztFLV2WPx47K8Y3zUjdufKa9/ee5dNZJ+T91bxp4/NnO8e5ltw88PhzneO9ORww8/mznuOLNxw261q2d46ZXrB40z62d46W/Wz9onrU+x5S33PKMr9uWznHmZr72WzrH5r72WzpHrdbPcK/BEtbPcK/BEtZPyWuwhPVT8mtYrdbPC+U1rFbrp+TXsFqtn5Jfw/wduOP+G6pqbhnY/vqweSOdcc+Jmkb6I488kr6+vkyYMGHQ/gkTJqS9vX2zx7S3t291/NP/Hco5Fy1alLFjxw5sra2t23U9AAAAUEs1fbv72rVrs+eee2bFihWZOXPmwP6Pfexj+clPfpKbb775Gcc0Njbmm9/8ZubN+8N3QS6++OJ84hOfSEdHR1asWJE3vOENWbt2bfbYY4+BMUcffXTq6uqyZMmSZ5xz06ZN2bRp08Cfu7q60tra6u3u3u4+9HN4u7u3anmr3w60fgp9u6m3u3u7u7e7F7J+Sn8N83Z3fwfuKP+GeuG93X1ULScxfvz4NDQ0pKOjY9D+jo6OtLS0bPaYlpaWrY5/+r8dHR2DIr2joyNTp07d7DmbmprS1NS0vZcxIurq6vKiptFJ07i8OOOSl470jAAAAMq18MuLR3oKz4mavt29sbEx06ZNy/Llywf29ff3Z/ny5YPurP93M2fOHDQ+SW688caB8a94xSvS0tIyaExXV1duvvnmLZ4TAAAAng9qeic9SRYsWJATTjghBx54YKZPn54LLrggGzduzIknnpgkOf7447Pnnntm0aJFSZIPfehDOeSQQ/KlL30phx9+eK666qrcdtttueSSS5I8dYf5wx/+cD796U9nv/32yyte8Yp8/OMfz8SJEzN37txaXw4AAADUTM0j/ZhjjsnDDz+c888/P+3t7Zk6dWqWLVs28MFvDzzwQOrr/3BD/+CDD86VV16Z8847L+ecc07222+/XH/99dl///0HxnzsYx/Lxo0bc/LJJ2f9+vV54xvfmGXLlmXMmDG1vhwAAAComZr/nvQSPR9+TzoAAAAvHEX8nnQAAABg24l0AAAAKIRIBwAAgEKIdAAAACiESAcAAIBCiHQAAAAohEgHAACAQoh0AAAAKIRIBwAAgEKIdAAAACiESAcAAIBCiHQAAAAohEgHAACAQoh0AAAAKIRIBwAAgEKIdAAAACiESAcAAIBCiHQAAAAohEgHAACAQoh0AAAAKIRIBwAAgEKIdAAAACiESAcAAIBCiHQAAAAohEgHAACAQoh0AAAAKIRIBwAAgEKIdAAAACiESAcAAIBCiHQAAAAohEgHAACAQoh0AAAAKIRIBwAAgEKIdAAAACiESAcAAIBCiHQAAAAohEgHAACAQoh0AAAAKIRIBwAAgEKIdAAAACiESAcAAIBCiHQAAAAohEgHAACAQoh0AAAAKIRIBwAAgEKIdAAAACiESAcAAIBCiHQAAAAohEgHAACAQoh0AAAAKIRIBwAAgEKIdAAAACiESAcAAIBCiHQAAAAohEgHAACAQoh0AAAAKIRIBwAAgEKIdAAAACiESAcAAIBCiHQAAAAohEgHAACAQoh0AAAAKIRIBwAAgEKIdAAAACiESAcAAIBCiHQAAAAohEgHAACAQoh0AAAAKIRIBwAAgEKIdAAAACiESAcAAIBCiHQAAAAohEgHAACAQtQs0h999NEce+yxaW5uzrhx4zJ//vw89thjWz3mySefzCmnnJJdd901L3nJS3LEEUeko6Nj4PF/+7d/y7x589La2pqddtopkydPzle/+tVaXQIAAAAMq5pF+rHHHps777wzN954Y2644Yb89Kc/zcknn7zVYz7ykY/ke9/7Xq655pr85Cc/ydq1a/Pud7974PGVK1dm9913z+WXX54777wz5557bs4+++xceOGFtboMAAAAGDZ1VVVVz/VJ77777rz61a/OrbfemgMPPDBJsmzZshx22GH57W9/m4kTJz7jmM7Ozuy222658sorc+SRRyZJ7rnnnkyePDltbW056KCDNvtcp5xySu6+++7cdNNN2zy/rq6ujB07Np2dnWlubt6OKwQAAIBtt60dWpM76W1tbRk3btxAoCfJ7NmzU19fn5tvvnmzx6xcuTI9PT2ZPXv2wL5JkyZlr732Sltb2xafq7OzM7vssstW57Np06Z0dXUN2gAAAKA0NYn09vb27L777oP2jRo1Krvsskva29u3eExjY2PGjRs3aP+ECRO2eMyKFSuyZMmSZ30b/aJFizJ27NiBrbW1ddsvBgAAAIbJkCL9rLPOSl1d3Va3e+65p1ZzHeSOO+7Iu971rixcuDBvfetbtzr27LPPTmdn58D24IMPDsscAQAAYChGDWXw6aefnve9731bHbPPPvukpaUl69atG7S/t7c3jz76aFpaWjZ7XEtLS7q7u7N+/fpBd9M7Ojqeccxdd92VWbNm5eSTT8555533rPNuampKU1PTs44DAACAkTSkSN9tt92y2267Peu4mTNnZv369Vm5cmWmTZuWJLnpppvS39+fGTNmbPaYadOmZfTo0Vm+fHmOOOKIJMmaNWvywAMPZObMmQPj7rzzzhx66KE54YQT8pnPfGYo0wcAAICi1eTT3ZPk7W9/ezo6OrJ48eL09PTkxBNPzIEHHpgrr7wySfLQQw9l1qxZ+da3vpXp06cnSf76r/86S5cuzWWXXZbm5uacdtppSZ762fPkqbe4H3rooZkzZ06+8IUvDDxXQ0PDNn3z4Gk+3R0AAIDhtK0dOqQ76UNxxRVX5NRTT82sWbNSX1+fI444Il/72tcGHu/p6cmaNWvy+OOPD+z7yle+MjB206ZNmTNnTi6++OKBx6+99to8/PDDufzyy3P55ZcP7H/5y1+e++67r1aXAgAAAMOiZnfSS+ZOOgAAAMNpRH9POgAAADB0Ih0AAAAKIdIBAACgECIdAAAACiHSAQAAoBAiHQAAAAoh0gEAAKAQIh0AAAAKIdIBAACgECIdAAAACiHSAQAAoBAiHQAAAAoh0gEAAKAQIh0AAAAKIdIBAACgECIdAAAACiHSAQAAoBAiHQAAAAoh0gEAAKAQIh0AAAAKIdIBAACgECIdAAAACiHSAQAAoBAiHQAAAAoh0gEAAKAQIh0AAAAKIdIBAACgECIdAAAACiHSAQAAoBAiHQAAAAoh0gEAAKAQIh0AAAAKIdIBAACgECIdAAAACiHSAQAAoBAiHQAAAAoh0gEAAKAQIh0AAAAKIdIBAACgECIdAAAACiHSAQAAoBAiHQAAAAoh0gEAAKAQIh0AAAAKIdIBAACgECIdAAAACiHSAQAAoBAiHQAAAAoh0gEAAKAQIh0AAAAKIdIBAACgECIdAAAACiHSAQAAoBAiHQAAAAoh0gEAAKAQIh0AAAAKIdIBAACgECIdAAAACiHSAQAAoBAiHQAAAAoh0gEAAKAQIh0AAAAKIdIBAACgECIdAAAACiHSAQAAoBAiHQAAAAoh0gEAAKAQIh0AAAAKIdIBAACgECIdAAAACiHSAQAAoBAiHQAAAAoh0gEAAKAQNYv0Rx99NMcee2yam5szbty4zJ8/P4899thWj3nyySdzyimnZNddd81LXvKSHHHEEeno6Njs2P/6r//Ky172stTV1WX9+vU1uAIAAAAYXjWL9GOPPTZ33nlnbrzxxtxwww356U9/mpNPPnmrx3zkIx/J9773vVxzzTX5yU9+krVr1+bd7373ZsfOnz8/r33ta2sxdQAAABgRdVVVVc/1Se++++68+tWvzq233poDDzwwSbJs2bIcdthh+e1vf5uJEyc+45jOzs7stttuufLKK3PkkUcmSe65555Mnjw5bW1tOeiggwbGfv3rX8+SJUty/vnnZ9asWfn973+fcePGbfP8urq6Mnbs2HR2dqa5uflPu1gAAAB4FtvaoTW5k97W1pZx48YNBHqSzJ49O/X19bn55ps3e8zKlSvT09OT2bNnD+ybNGlS9tprr7S1tQ3su+uuu/LJT34y3/rWt1Jfv23T37RpU7q6ugZtAAAAUJqaRHp7e3t23333QftGjRqVXXbZJe3t7Vs8prGx8Rl3xCdMmDBwzKZNmzJv3rx84QtfyF577bXN81m0aFHGjh07sLW2tg7tggAAAGAYDCnSzzrrrNTV1W11u+eee2o115x99tmZPHly3vve9w75uM7OzoHtwQcfrNEMAQAAYPuNGsrg008/Pe973/u2OmafffZJS0tL1q1bN2h/b29vHn300bS0tGz2uJaWlnR3d2f9+vWD7qZ3dHQMHHPTTTfll7/8Za699tokydM/Tj9+/Pice+65+cQnPrHZczc1NaWpqWlbLhEAAABGzJAifbfddstuu+32rONmzpyZ9evXZ+XKlZk2bVqSpwK7v78/M2bM2Owx06ZNy+jRo7N8+fIcccQRSZI1a9bkgQceyMyZM5Mk3/72t/PEE08MHHPrrbfmL//yL/Ozn/0s++6771AuBQAAAIozpEjfVpMnT87b3va2nHTSSVm8eHF6enpy6qmn5j3vec/AJ7s/9NBDmTVrVr71rW9l+vTpGTt2bObPn58FCxZkl112SXNzc0477bTMnDlz4JPd/zjEH3nkkYHnG8qnuwMAAECJahLpSXLFFVfk1FNPzaxZs1JfX58jjjgiX/va1wYe7+npyZo1a/L4448P7PvKV74yMHbTpk2ZM2dOLr744lpNEQAAAIpSk9+TXjq/Jx0AAIDhNKK/Jx0AAAAYOpEOAAAAhRDpAAAAUAiRDgAAAIUQ6QAAAFAIkQ4AAACFEOkAAABQCJEOAAAAhRDpAAAAUAiRDgAAAIUQ6QAAAFAIkQ4AAACFEOkAAABQCJEOAAAAhRDpAAAAUAiRDgAAAIUQ6QAAAFAIkQ4AAACFEOkAAABQCJEOAAAAhRDpAAAAUAiRDgAAAIUQ6QAAAFAIkQ4AAACFEOkAAABQCJEOAAAAhRDpAAAAUAiRDgAAAIUQ6QAAAFAIkQ4AAACFEOkAAABQCJEOAAAAhRDpAAAAUAiRDgAAAIUQ6QAAAFAIkQ4AAACFEOkAAABQCJEOAAAAhRDpAAAAUAiRDgAAAIUQ6QAAAFAIkQ4AAACFEOkAAABQCJEOAAAAhRDpAAAAUAiRDgAAAIUQ6QAAAFAIkQ4AAACFEOkAAABQCJEOAAAAhRDpAAAAUAiRDgAAAIUQ6QAAAFAIkQ4AAACFEOkAAABQiFEjPYGRUFVVkqSrq2uEZwIAAMCO4On+fLpHt2SHjPQNGzYkSVpbW0d4JgAAAOxINmzYkLFjx27x8brq2TL+Bai/vz9r167NzjvvnLq6upGezmZ1dXWltbU1Dz74YJqbm0d6OrBZ1imls0YpnTVK6axRng+eL+u0qqps2LAhEydOTH39ln/yfIe8k15fX5+XvexlIz2NbdLc3Fz0QoPEOqV81iils0YpnTXK88HzYZ1u7Q7603xwHAAAABRCpAMAAEAhRHqhmpqasnDhwjQ1NY30VGCLrFNKZ41SOmuU0lmjPB+80NbpDvnBcQAAAFAid9IBAACgECIdAAAACiHSAQAAoBAiHQAAAAoh0gEAAKAQIn0EXXTRRdl7770zZsyYzJgxI7fccstWx19zzTWZNGlSxowZkylTpmTp0qXDNFN2ZENZp5deemne9KY35aUvfWle+tKXZvbs2c+6ruFPNdTX0qddddVVqaury9y5c2s7QXZ4Q12j69evzymnnJI99tgjTU1NeeUrX+nvfGpqqGv0ggsuyKte9arstNNOaW1tzUc+8pE8+eSTwzRbdjQ//elP8453vCMTJ05MXV1drr/++mc95sc//nFe97rXpampKX/2Z3+Wyy67rObzfC6J9BGyZMmSLFiwIAsXLsyqVatywAEHZM6cOVm3bt1mx69YsSLz5s3L/Pnzs3r16sydOzdz587NHXfcMcwzZ0cy1HX64x//OPPmzcuPfvSjtLW1pbW1NW9961vz0EMPDfPM2VEMdY0+7b777stHP/rRvOlNbxqmmbKjGuoa7e7uzlve8pbcd999ufbaa7NmzZpceuml2XPPPYd55uwohrpGr7zyypx11llZuHBh7r777nzjG9/IkiVLcs455wzzzNlRbNy4MQcccEAuuuiibRr/m9/8Jocffnj+/M//PLfffns+/OEP5/3vf39+8IMf1Himz6GKETF9+vTqlFNOGfhzX19fNXHixGrRokWbHX/00UdXhx9++KB9M2bMqP7qr/6qpvNkxzbUdfrHent7q5133rn65je/WaspsoPbnjXa29tbHXzwwdU//MM/VCeccEL1rne9axhmyo5qqGv061//erXPPvtU3d3dwzVFdnBDXaOnnHJKdeihhw7at2DBguoNb3hDTecJVVVVSarrrrtuq2M+9rGPVa95zWsG7TvmmGOqOXPm1HBmzy130kdAd3d3Vq5cmdmzZw/sq6+vz+zZs9PW1rbZY9ra2gaNT5I5c+ZscTz8qbZnnf6xxx9/PD09Pdlll11qNU12YNu7Rj/5yU9m9913z/z584djmuzAtmeNfve7383MmTNzyimnZMKECdl///3z2c9+Nn19fcM1bXYg27NGDz744KxcuXLgLfH33ntvli5dmsMOO2xY5gzP5oXQTaNGegI7okceeSR9fX2ZMGHCoP0TJkzIPffcs9lj2tvbNzu+vb29ZvNkx7Y96/SPnXnmmZk4ceIzXijhubA9a/Rf//Vf841vfCO33377MMyQHd32rNF77703N910U4499tgsXbo0v/71r/PBD34wPT09Wbhw4XBMmx3I9qzRv/iLv8gjjzySN77xjamqKr29vfnABz7g7e4UY0vd1NXVlSeeeCI77bTTCM1s27mTDtTE5z73uVx11VW57rrrMmbMmJGeDmTDhg057rjjcumll2b8+PEjPR3YrP7+/uy+++655JJLMm3atBxzzDE599xzs3jx4pGeGiR56vNnPvvZz+biiy/OqlWr8p3vfCff//7386lPfWqkpwYvGO6kj4Dx48enoaEhHR0dg/Z3dHSkpaVls8e0tLQMaTz8qbZnnT7ti1/8Yj73uc/lhz/8YV772tfWcprswIa6Rv/zP/8z9913X97xjncM7Ovv70+SjBo1KmvWrMm+++5b20mzQ9me19E99tgjo0ePTkNDw8C+yZMnp729Pd3d3WlsbKzpnNmxbM8a/fjHP57jjjsu73//+5MkU6ZMycaNG3PyySfn3HPPTX29e4CMrC11U3Nz8/PiLnriTvqIaGxszLRp07J8+fKBff39/Vm+fHlmzpy52WNmzpw5aHyS3HjjjVscD3+q7VmnSfL5z38+n/rUp7Js2bIceOCBwzFVdlBDXaOTJk3KL3/5y9x+++0D2zvf+c6BT39tbW0dzumzA9ie19E3vOEN+fWvfz3wDaQk+Y//+I/sscceAp3n3Pas0ccff/wZIf70N5WqqqrdZGEbvSC6aaQ/uW5HddVVV1VNTU3VZZddVt11113VySefXI0bN65qb2+vqqqqjjvuuOqss84aGP/zn/+8GjVqVPXFL36xuvvuu6uFCxdWo0ePrn75y1+O1CWwAxjqOv3c5z5XNTY2Vtdee231u9/9bmDbsGHDSF0CL3BDXaN/zKe7U2tDXaMPPPBAtfPOO1ennnpqtWbNmuqGG26odt999+rTn/70SF0CL3BDXaMLFy6sdt555+qf//mfq3vvvbf6l3/5l2rfffetjj766JG6BF7gNmzYUK1evbpavXp1laT68pe/XK1evbq6//77q6qqqrPOOqs67rjjBsbfe++91Yte9KLqjDPOqO6+++7qoosuqhoaGqply5aN1CUMmUgfQX//939f7bXXXlVjY2M1ffr06he/+MXAY4ccckh1wgknDBp/9dVXV6985SurxsbG6jWveU31/e9/f5hnzI5oKOv05S9/eZXkGdvChQuHf+LsMIb6WvrfiXSGw1DX6IoVK6oZM2ZUTU1N1T777FN95jOfqXp7e4d51uxIhrJGe3p6qr/927+t9t1332rMmDFVa2tr9cEPfrD6/e9/P/wTZ4fwox/9aLP/vnx6XZ5wwgnVIYcc8oxjpk6dWjU2Nlb77LNP9U//9E/DPu8/RV1VeV8KAAAAlMDPpAMAAEAhRDoAAAAUQqQDAABAIUQ6AAAAFEKkAwAAQCFEOgAAABRCpAMAAEAhRDoAAAAUQqQDAABAIUQ6AAAAFEKkAwAAQCH+f8wrPxOJhqH9AAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "key = random.PRNGKey(0)\n", + "steps = 1000\n", + "samples = 5\n", + "\n", + "H = 0.6\n", + "\n", + "t, fbm = gen_elevation_profile(key, steps, H)\n", + "plt.figure(figsize=(12,6))\n", + "print(fbm)\n", + "for i in range(fbm.shape[0]):\n", + " plt.plot(t, fbm[i], label=f\"Sample {i}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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SUlJ+PDDDzu83x49ekAikRh9rVixwgq/ASGEOA9/T3c8MjaeghviMqyWwWlubsY999yDlJQUfPnll61uP3nyJMLDw7Fu3TrExsbi8OHDePzxxyGTyfDkk0+2e99vvPEGFixYoPvez89P8PETQgghxHFZLcBZtmwZAGDt2rUmb3/00UeNvk9ISEBqaio2bdrUYYDj5+eHyEj7brhFCCGEEPHY1TLx6upqBAcHd3jeihUrEBISguTkZLz77rtQqdrfWE6hUKCmpsboixBCCCHOy26KjA8fPowffvgBv//+e7vnPf300xg6dCiCg4Nx+PBhLF26FIWFhXj//ffb/Jnly5frMkqEEEIIcX4WZXBefPHFVgW+Lb8uXrxo8SDS09Nxxx134LXXXsOUKVPaPXfJkiWYMGECBg0ahIULF+K9997DypUroVAo2vyZpUuXorq6WveVm5tr8RgJIYQQ4jgsyuA899xzePjhh9s9JyEhwaIBnD9/HpMmTcLjjz+Ol19+2aKfBYBRo0ZBpVLh2rVr6NvXdEdZuVwOuZw6dRJCCCGuwqIAJywsDGFhYYI9eEZGBm666SbMmzcPb731VqfuIy0tDVKpFOHh4YKNixBCCCGOzWo1ODk5OaioqEBOTg7UajXS0tIAAL169YKvry/S09Nx0003YerUqViyZAmKilgrcZlMpguijh07hrlz52LXrl3o1q0bUlNTcfToUUycOBF+fn5ITU3F4sWL8eCDDyIoKMhavwohhBBCHIzVApxXX30VX3/9te775ORkAMCePXswYcIE/PTTTygtLcW6deuwbt063XlxcXG4du0aAKChoQGZmZlQKpUA2FTThg0b8Prrr0OhUCA+Ph6LFy/GkiVLrPVrEEIIIcQB0V5UtBcVIYQQ4hAsef+2qz44hBBCCCFCoACHEEIIIU6HAhxCCCGEOB276WRsS3zZEW3ZQAghhDgO/n3bnPJhlwxwamtrAQCxsbEij4QQQgghlqqtrUVAQEC757jkKiqNRoOCggL4+flBIpEIet81NTWIjY1Fbm4urdCyMnqubYeea9uh59p26Lm2HaGea47jUFtbi+joaEil7VfZuGQGRyqVIiYmxqqP4e/vT/9hbISea9uh59p26Lm2HXqubUeI57qjzA2PiowJIYQQ4nQowCGEEEKI06EAR2ByuRyvvfYa7V5uA/Rc2w49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nnjiCS4gIIDbu3cvV1hYqPtqaGjQnbNw4UKue/fu3O7du7kTJ05wKSkpXEpKiu52fvnylClTuLS0NG7btm1cWFgYLV/ugOEqKo6j51lIx44d49zc3Li33nqLu3z5Mvfdd99x3t7e3Lp163TnrFixggsMDOS2bNnCnT17lrvjjjtMLrFNTk7mjh49yh08eJDr3bu3yy9dbmnevHlct27ddMvEN23axIWGhnL//Oc/defQc905tbW13OnTp7nTp09zALj333+fO336NHf9+nWO44R5XquqqriIiAjuoYce4tLT07kNGzZw3t7etExcbCtXruS6d+/OeXh4cCNHjuSOHDki9pAcDgCTX2vWrNGd09jYyP3973/ngoKCOG9vb+7OO+/kCgsLje7n2rVr3PTp0zkvLy8uNDSUe+655zilUmnj38axtAxw6HkW1m+//cYNGDCAk8vlXGJiIrd69Wqj2zUaDffKK69wERERnFwu5yZNmsRlZmYanVNeXs7Nnj2b8/X15fz9/blHHnmEq62tteWvYfdqamq4Z555huvevTvn6enJJSQkcP/617+Mlh3Tc905e/bsMfn6PG/ePI7jhHtez5w5w40bN46Ty+Vct27duBUrVnRqvBKOM2jvSAghhBDiBKgGhxBCCCFOhwIcQgghhDgdCnAIIYQQ4nQowCGEEEKI06EAhxBCCCFOhwIcQgghhDgdCnAIIYQQ4nQowCGEEEKI06EAhxBCCCFOhwIcQgghhDgdCnAIIYQQ4nQowCGEEEKI0/l/hE3Y6oATQVEAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "steps = 100\n", + "key = random.key(25)\n", + "\n", + "def uniform_window(n):\n", + " return jnp.ones(n)/n\n", + "\n", + "def generate_basic_terrain(key, steps=100, yscale=1.0, xscale=10.0, window=uniform_window, window_size=5):\n", + " key, split = random.split(key)\n", + " v = random.normal(split, shape=(steps))\n", + " y = jnp.cumsum(v) * yscale\n", + " # smooth with a windowing function\n", + " y_smooth = jnp.convolve(y, window(window_size), mode='same')\n", + " # compute the x-values\n", + " x = jnp.arange(steps) * xscale\n", + " return x,y_smooth\n", + "\n", + "\n", + "x,y = generate_basic_terrain(key)\n", + " \n", + "slope = jnp.atan(jnp.diff(y, prepend=0) / 10.0) * 180 / jnp.pi\n", + "plt.plot(x,y)\n", + "plt.plot(x, slope)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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fft2NDQ04IUXXsA111yDc845B4sWLUr2qRMREaUlSZL8+1GptFU85UXGf/jDH7BixYqgmhzB6XSivr5e6ZKyWCx47bXX8LOf/QyDg4Oorq7G5Zdfju9+97vJPm0iIqK0ZjYa4HS74XSpM4OT8gDnqaeeCvtYTU0NAmugq6ursWnTpmScFhEREUWg9mF/KV+iIiIiIu3xD/tjgENEREQ6YTKoez8qBjhEREQUM9Eq7mAGh4iIiPTCovIdxRngEBERUcxEBsfFDA4RERHphdmXweESFREREemGiUtUREREpDcW3xIV28SJiIhIN0SbuNPDDA4RERHphCgydrqYwSEiIiKdUNrEuVUDERER6YWSwWGRMREREemFaBNnkTERERHphplt4kRERKQ3Zu5FRURERHrDQX9ERESkO2YDB/0RERGRzihFxmwTJyIiIr3gEhURERHpDveiIiIiIt0xKXNwmMEhIiIineCgPyIiItIdMQfHxQCHiIiI9MJk4F5UREREpDNmE5eoiIiISGfMBl+buIcZHCIiItIJs4lt4kRERKQzJgOXqIiIiEhnzJyDQ0RERHrDNnEiIiLSHTHJ2MEMDhEREekFMzhERESkO6IGh23iREREpBsiwHG40iyD88ADD2DFihXIyspCQUFByGMaGxtx6aWXIisrC2VlZbjzzjvhcrkift3u7m5cddVVyMvLQ0FBAa6//noMDAwk4CcgIiKicMRWDS5PmgU4DocDV1xxBW6++eaQj7vdblx66aVwOBzYvHkzHn/8cTz22GO45557In7dq666Cnv37sX69evx0ksv4c0338SNN96YiB+BiIiIwrCY1N0mLsmynNAze+yxx3Drrbeit7c36POvvPIKPvrRj+LEiRMoLy8HADzyyCO466670NHRAYvFMuZr7du3D/Pnz8d7772HpUuXAgBeffVVXHLJJTh+/DiqqqqiOiebzYb8/Hz09fUhLy9vcj8gERFRGjrSMYDzH9qE3AwTPrh3dVK+ZyzX75TV4GzZsgULFy5UghsAWL16NWw2G/bu3Rv2OQUFBUpwAwCrVq2CwWDAu+++G/Z72e122Gy2oA8iIiKaOP+gvzRbohpPa2trUHADQPl3a2tr2OeUlZUFfc5kMqGoqCjscwBg3bp1yM/PVz6qq6snefZERETpTemiUukSVUwBzt133w1JkiJ+7N+/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dXWKz4SIiIhi1d/fj/z8/IjHSHI0YZDOeDwenDhxArm5uZAkKa5f22azobq6Gk1NTcjLy4vr16ZgfK2Th6918vC1Th6+1skTr9dalmX09/ejqqoKBkPkKpu0zOAYDAZMnTo1od8jLy+PfzBJwtc6efhaJw9f6+Tha5088Xitx8vcCCwyJiIiIt1hgENERES6wwAnzqxWK77//e/DarWm+lR0j6918vC1Th6+1snD1zp5UvFap2WRMREREekbMzhERESkOwxwiIiISHcY4BAREZHuMMAhIiIi3WGAE0cPP/wwampqkJGRgWXLlmHr1q2pPiXNWbduHU477TTk5uairKwMl112Gerr64OOGRkZwS233ILi4mLk5OTg8ssvR1tbW9AxjY2NuPTSS5GVlYWysjLceeedcLlcyfxRNOXBBx+EJEm49dZblc/xdY6v5uZmXH311SguLkZmZiYWLlyIbdu2KY/Lsox77rkHlZWVyMzMxKpVq3Dw4MGgr9Hd3Y2rrroKeXl5KCgowPXXX4+BgYFk/yiq5na78b3vfQ+1tbXIzMzEjBkzcP/99wftXcTXemLefPNNfOxjH0NVVRUkScI///nPoMfj9bru3r0bZ599NjIyMlBdXY0f/ehHEzthmeLi6aefli0Wi/zHP/5R3rt3r3zDDTfIBQUFcltbW6pPTVNWr14tP/roo/KePXvknTt3ypdccok8bdo0eWBgQDnmpptukqurq+UNGzbI27Ztk8844wx5xYoVyuMul0tesGCBvGrVKvn999+XX375ZbmkpEReu3ZtKn4k1du6datcU1MjL1q0SP7GN76hfJ6vc/x0d3fL06dPl6+77jr53XfflY8cOSL/+9//lg8dOqQc8+CDD8r5+fnyP//5T3nXrl3yxz/+cbm2tlYeHh5Wjrnooovkk08+WX7nnXfk//73v/LMmTPlK6+8MhU/kmo98MADcnFxsfzSSy/JR48elZ955hk5JydH/vnPf64cw9d6Yl5++WX5O9/5jvzss8/KAOTnnnsu6PF4vK59fX1yeXm5fNVVV8l79uyR//KXv8iZmZnyb3/725jPlwFOnJx++unyLbfcovzb7XbLVVVV8rp161J4VtrX3t4uA5A3bdoky7Is9/b2ymazWX7mmWeUY/bt2ycDkLds2SLLsveP0GAwyK2trcoxv/nNb+S8vDzZbrcn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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# we can compute the slope at any point along the terrain\n", + "plt.plot(x, slope)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.7" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/pdm.lock b/pdm.lock index 6626b9e..4ceabbe 100644 --- a/pdm.lock +++ b/pdm.lock @@ -2,43 +2,353 @@ # It is not intended for manual editing. [metadata] -groups = ["default"] +groups = ["default", "dev"] strategy = ["inherit_metadata"] lock_version = "4.5.0" -content_hash = "sha256:3d98f83a67ac634a9925dfc4463ac69294c03a44459353cb609fc20015b468aa" +content_hash = "sha256:6ec3d68699b6437757cd200a2efed5a5a3b5f372f1629b5177c0399297cc5f12" [[metadata.targets]] -requires_python = ">=3.12" +requires_python = ">=3.12,<3.13" + +[[package]] +name = "appnope" +version = "0.1.4" +requires_python = ">=3.6" +summary = "Disable App Nap on macOS >= 10.9" +groups = ["dev"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\" and platform_system == \"Darwin\"" +files = [ + {file = "appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c"}, + {file = "appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee"}, +] + +[[package]] +name = "asttokens" +version = "2.4.1" +summary = "Annotate AST trees with source code positions" +groups = ["dev"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +dependencies = [ + "six>=1.12.0", + "typing; python_version < \"3.5\"", +] +files = [ + {file = "asttokens-2.4.1-py2.py3-none-any.whl", hash = "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24"}, + {file = "asttokens-2.4.1.tar.gz", hash = "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0"}, +] + +[[package]] +name = "certifi" +version = "2024.8.30" +requires_python = ">=3.6" +summary = "Python package for providing Mozilla's CA Bundle." +groups = ["default"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +files = [ + {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, + {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, +] + +[[package]] +name = "cffi" +version = "1.17.1" +requires_python = ">=3.8" +summary = "Foreign Function Interface for Python calling C code." +groups = ["dev"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\" and implementation_name == \"pypy\"" +dependencies = [ + "pycparser", +] +files = [ + {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"}, + {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"}, + {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"}, + {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"}, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.0" +requires_python = ">=3.7.0" +summary = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +groups = ["default"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +files = [ + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9"}, + {file = "charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079"}, + {file = "charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e"}, +] + +[[package]] +name = "cloudpickle" +version = "3.1.0" +requires_python = ">=3.8" +summary = "Pickler class to extend the standard pickle.Pickler functionality" +groups = ["default"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +files = [ + {file = "cloudpickle-3.1.0-py3-none-any.whl", hash = "sha256:fe11acda67f61aaaec473e3afe030feb131d78a43461b718185363384f1ba12e"}, + {file = "cloudpickle-3.1.0.tar.gz", hash = "sha256:81a929b6e3c7335c863c771d673d105f02efdb89dfaba0c90495d1c64796601b"}, +] [[package]] name = "colorama" version = "0.4.6" requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" summary = "Cross-platform colored terminal text." -groups = ["default"] -marker = "sys_platform == \"win32\"" +groups = ["default", "dev"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\" and sys_platform == \"win32\"" files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +[[package]] +name = "comm" +version = "0.2.2" +requires_python = ">=3.8" +summary = "Jupyter Python Comm implementation, for usage in ipykernel, xeus-python etc." +groups = ["dev"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +dependencies = [ + "traitlets>=4", +] +files = [ + {file = "comm-0.2.2-py3-none-any.whl", hash = "sha256:e6fb86cb70ff661ee8c9c14e7d36d6de3b4066f1441be4063df9c5009f0a64d3"}, + {file = "comm-0.2.2.tar.gz", hash = "sha256:3fd7a84065306e07bea1773df6eb8282de51ba82f77c72f9c85716ab11fe980e"}, +] + +[[package]] +name = "contourpy" +version = "1.3.1" +requires_python = ">=3.10" +summary = "Python library for calculating contours of 2D quadrilateral grids" +groups = ["default"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +dependencies = [ + "numpy>=1.23", +] +files = [ + {file = "contourpy-1.3.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0ffa84be8e0bd33410b17189f7164c3589c229ce5db85798076a3fa136d0e509"}, + {file = "contourpy-1.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:805617228ba7e2cbbfb6c503858e626ab528ac2a32a04a2fe88ffaf6b02c32bc"}, + {file = "contourpy-1.3.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ade08d343436a94e633db932e7e8407fe7de8083967962b46bdfc1b0ced39454"}, + {file = "contourpy-1.3.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:47734d7073fb4590b4a40122b35917cd77be5722d80683b249dac1de266aac80"}, + {file = "contourpy-1.3.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2ba94a401342fc0f8b948e57d977557fbf4d515f03c67682dd5c6191cb2d16ec"}, + {file = "contourpy-1.3.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efa874e87e4a647fd2e4f514d5e91c7d493697127beb95e77d2f7561f6905bd9"}, + {file = "contourpy-1.3.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1bf98051f1045b15c87868dbaea84f92408337d4f81d0e449ee41920ea121d3b"}, + {file = "contourpy-1.3.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:61332c87493b00091423e747ea78200659dc09bdf7fd69edd5e98cef5d3e9a8d"}, + {file = "contourpy-1.3.1-cp312-cp312-win32.whl", hash = "sha256:e914a8cb05ce5c809dd0fe350cfbb4e881bde5e2a38dc04e3afe1b3e58bd158e"}, + {file = "contourpy-1.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:08d9d449a61cf53033612cb368f3a1b26cd7835d9b8cd326647efe43bca7568d"}, + {file = "contourpy-1.3.1.tar.gz", hash = "sha256:dfd97abd83335045a913e3bcc4a09c0ceadbe66580cf573fe961f4a825efa699"}, +] + +[[package]] +name = "cycler" +version = "0.12.1" +requires_python = ">=3.8" +summary = "Composable style cycles" +groups = ["default"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +files = [ + {file = "cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30"}, + {file = "cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c"}, +] + +[[package]] +name = "debugpy" +version = "1.8.9" +requires_python = ">=3.8" +summary = "An implementation of the Debug Adapter Protocol for Python" +groups = ["dev"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +files = [ + {file = "debugpy-1.8.9-cp312-cp312-macosx_14_0_universal2.whl", hash = "sha256:957363d9a7a6612a37458d9a15e72d03a635047f946e5fceee74b50d52a9c8e2"}, + {file = "debugpy-1.8.9-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e565fc54b680292b418bb809f1386f17081d1346dca9a871bf69a8ac4071afe"}, + {file = "debugpy-1.8.9-cp312-cp312-win32.whl", hash = "sha256:3e59842d6c4569c65ceb3751075ff8d7e6a6ada209ceca6308c9bde932bcef11"}, + {file = "debugpy-1.8.9-cp312-cp312-win_amd64.whl", hash = "sha256:66eeae42f3137eb428ea3a86d4a55f28da9bd5a4a3d369ba95ecc3a92c1bba53"}, + {file = "debugpy-1.8.9-py2.py3-none-any.whl", hash = "sha256:cc37a6c9987ad743d9c3a14fa1b1a14b7e4e6041f9dd0c8abf8895fe7a97b899"}, + {file = "debugpy-1.8.9.zip", hash = "sha256:1339e14c7d980407248f09824d1b25ff5c5616651689f1e0f0e51bdead3ea13e"}, +] + +[[package]] +name = "decorator" +version = "5.1.1" +requires_python = ">=3.5" +summary = "Decorators for Humans" +groups = ["dev"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +files = [ + {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"}, + {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, +] + +[[package]] +name = "executing" +version = "2.1.0" +requires_python = ">=3.8" +summary = "Get the currently executing AST node of a frame, and other information" +groups = ["dev"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +files = [ + {file = "executing-2.1.0-py2.py3-none-any.whl", hash = "sha256:8d63781349375b5ebccc3142f4b30350c0cd9c79f921cde38be2be4637e98eaf"}, + {file = "executing-2.1.0.tar.gz", hash = "sha256:8ea27ddd260da8150fa5a708269c4a10e76161e2496ec3e587da9e3c0fe4b9ab"}, +] + +[[package]] +name = "farama-notifications" +version = "0.0.4" +summary = "Notifications for all Farama Foundation maintained libraries." +groups = ["default"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +files = [ + {file = "Farama-Notifications-0.0.4.tar.gz", hash = "sha256:13fceff2d14314cf80703c8266462ebf3733c7d165336eee998fc58e545efd18"}, + {file = "Farama_Notifications-0.0.4-py3-none-any.whl", hash = "sha256:14de931035a41961f7c056361dc7f980762a143d05791ef5794a751a2caf05ae"}, +] + +[[package]] +name = "fonttools" +version = "4.55.0" +requires_python = ">=3.8" +summary = "Tools to manipulate font files" +groups = ["default"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +files = [ + {file = "fonttools-4.55.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:838d2d8870f84fc785528a692e724f2379d5abd3fc9dad4d32f91cf99b41e4a7"}, + {file = "fonttools-4.55.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f46b863d74bab7bb0d395f3b68d3f52a03444964e67ce5c43ce43a75efce9246"}, + {file = "fonttools-4.55.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:33b52a9cfe4e658e21b1f669f7309b4067910321757fec53802ca8f6eae96a5a"}, + {file = "fonttools-4.55.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:732a9a63d6ea4a81b1b25a1f2e5e143761b40c2e1b79bb2b68e4893f45139a40"}, + {file = "fonttools-4.55.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7dd91ac3fcb4c491bb4763b820bcab6c41c784111c24172616f02f4bc227c17d"}, + {file = "fonttools-4.55.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1f0e115281a32ff532118aa851ef497a1b7cda617f4621c1cdf81ace3e36fb0c"}, + {file = "fonttools-4.55.0-cp312-cp312-win32.whl", hash = "sha256:6c99b5205844f48a05cb58d4a8110a44d3038c67ed1d79eb733c4953c628b0f6"}, + {file = "fonttools-4.55.0-cp312-cp312-win_amd64.whl", hash = "sha256:f8c8c76037d05652510ae45be1cd8fb5dd2fd9afec92a25374ac82255993d57c"}, + {file = "fonttools-4.55.0-py3-none-any.whl", hash = "sha256:12db5888cd4dd3fcc9f0ee60c6edd3c7e1fd44b7dd0f31381ea03df68f8a153f"}, + {file = "fonttools-4.55.0.tar.gz", hash = "sha256:7636acc6ab733572d5e7eec922b254ead611f1cdad17be3f0be7418e8bfaca71"}, +] + +[[package]] +name = "gymnasium" +version = "1.0.0" +requires_python = ">=3.8" +summary = "A standard API for reinforcement learning and a diverse set of reference environments (formerly Gym)." +groups = ["default"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +dependencies = [ + "cloudpickle>=1.2.0", + "farama-notifications>=0.0.1", + "importlib-metadata>=4.8.0; python_version < \"3.10\"", + "numpy>=1.21.0", + "typing-extensions>=4.3.0", +] +files = [ + {file = "gymnasium-1.0.0-py3-none-any.whl", hash = "sha256:b6f40e1e24c5bd419361e1a5b86a9117d2499baecc3a660d44dfff4c465393ad"}, + {file = "gymnasium-1.0.0.tar.gz", hash = "sha256:9d2b66f30c1b34fe3c2ce7fae65ecf365d0e9982d2b3d860235e773328a3b403"}, +] + +[[package]] +name = "idna" +version = "3.10" +requires_python = ">=3.6" +summary = "Internationalized Domain Names in Applications (IDNA)" +groups = ["default"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +files = [ + {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, + {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, +] + [[package]] name = "iniconfig" version = "2.0.0" requires_python = ">=3.7" summary = "brain-dead simple config-ini parsing" groups = ["default"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" files = [ {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] +[[package]] +name = "ipykernel" +version = "6.29.5" +requires_python = ">=3.8" +summary = "IPython Kernel for Jupyter" +groups = ["dev"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +dependencies = [ + "appnope; platform_system == \"Darwin\"", + "comm>=0.1.1", + "debugpy>=1.6.5", + "ipython>=7.23.1", + "jupyter-client>=6.1.12", + "jupyter-core!=5.0.*,>=4.12", + "matplotlib-inline>=0.1", + "nest-asyncio", + "packaging", + "psutil", + "pyzmq>=24", + "tornado>=6.1", + "traitlets>=5.4.0", +] +files = [ + {file = "ipykernel-6.29.5-py3-none-any.whl", hash = "sha256:afdb66ba5aa354b09b91379bac28ae4afebbb30e8b39510c9690afb7a10421b5"}, + {file = "ipykernel-6.29.5.tar.gz", hash = "sha256:f093a22c4a40f8828f8e330a9c297cb93dcab13bd9678ded6de8e5cf81c56215"}, +] + +[[package]] +name = "ipython" +version = "8.29.0" +requires_python = ">=3.10" +summary = "IPython: Productive Interactive Computing" +groups = ["dev"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +dependencies = [ + "colorama; sys_platform == \"win32\"", + "decorator", + "exceptiongroup; python_version < \"3.11\"", + "jedi>=0.16", + "matplotlib-inline", + "pexpect>4.3; sys_platform != \"win32\" and sys_platform != \"emscripten\"", + "prompt-toolkit<3.1.0,>=3.0.41", + "pygments>=2.4.0", + "stack-data", + "traitlets>=5.13.0", + "typing-extensions>=4.6; python_version < \"3.12\"", +] +files = [ + {file = "ipython-8.29.0-py3-none-any.whl", hash = "sha256:0188a1bd83267192123ccea7f4a8ed0a78910535dbaa3f37671dca76ebd429c8"}, + {file = "ipython-8.29.0.tar.gz", hash = "sha256:40b60e15b22591450eef73e40a027cf77bd652e757523eebc5bd7c7c498290eb"}, +] + [[package]] name = "jax" version = "0.4.35" requires_python = ">=3.10" summary = "Differentiate, compile, and transform Numpy code." groups = ["default"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" dependencies = [ "jaxlib<=0.4.35,>=0.4.34", "ml-dtypes>=0.4.0", @@ -59,6 +369,7 @@ version = "0.4.35" requires_python = ">=3.10" summary = "XLA library for JAX" groups = ["default"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" dependencies = [ "ml-dtypes>=0.2.0", "numpy>=1.24", @@ -78,12 +389,136 @@ files = [ {file = "jaxlib-0.4.35-cp313-cp313-win_amd64.whl", hash = "sha256:330c090bb9af413f552d8a92d097e50baec6b75823430fb2966a49f5298d4c43"}, ] +[[package]] +name = "jedi" +version = "0.19.2" +requires_python = ">=3.6" +summary = "An autocompletion tool for Python that can be used for text editors." +groups = ["dev"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +dependencies = [ + "parso<0.9.0,>=0.8.4", +] +files = [ + {file = "jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9"}, + {file = "jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0"}, +] + +[[package]] +name = "jupyter-client" +version = "8.6.3" +requires_python = ">=3.8" +summary = "Jupyter protocol implementation and client libraries" +groups = ["dev"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +dependencies = [ + "importlib-metadata>=4.8.3; python_version < \"3.10\"", + "jupyter-core!=5.0.*,>=4.12", + "python-dateutil>=2.8.2", + "pyzmq>=23.0", + "tornado>=6.2", + "traitlets>=5.3", +] +files = [ + {file = "jupyter_client-8.6.3-py3-none-any.whl", hash = "sha256:e8a19cc986cc45905ac3362915f410f3af85424b4c0905e94fa5f2cb08e8f23f"}, + {file = "jupyter_client-8.6.3.tar.gz", hash = "sha256:35b3a0947c4a6e9d589eb97d7d4cd5e90f910ee73101611f01283732bd6d9419"}, +] + +[[package]] +name = "jupyter-core" +version = "5.7.2" +requires_python = ">=3.8" +summary = "Jupyter core package. A base package on which Jupyter projects rely." +groups = ["dev"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +dependencies = [ + "platformdirs>=2.5", + "pywin32>=300; sys_platform == \"win32\" and platform_python_implementation != \"PyPy\"", + "traitlets>=5.3", +] +files = [ + {file = "jupyter_core-5.7.2-py3-none-any.whl", hash = "sha256:4f7315d2f6b4bcf2e3e7cb6e46772eba760ae459cd1f59d29eb57b0a01bd7409"}, + {file = "jupyter_core-5.7.2.tar.gz", hash = "sha256:aa5f8d32bbf6b431ac830496da7392035d6f61b4f54872f15c4bd2a9c3f536d9"}, +] + +[[package]] +name = "kiwisolver" +version = "1.4.7" +requires_python = ">=3.8" +summary = "A fast implementation of the Cassowary constraint solver" +groups = ["default"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +files = [ + {file = "kiwisolver-1.4.7-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:5360cc32706dab3931f738d3079652d20982511f7c0ac5711483e6eab08efff2"}, + {file = "kiwisolver-1.4.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:942216596dc64ddb25adb215c3c783215b23626f8d84e8eff8d6d45c3f29f75a"}, + {file = "kiwisolver-1.4.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:48b571ecd8bae15702e4f22d3ff6a0f13e54d3d00cd25216d5e7f658242065ee"}, + {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ad42ba922c67c5f219097b28fae965e10045ddf145d2928bfac2eb2e17673640"}, + {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:612a10bdae23404a72941a0fc8fa2660c6ea1217c4ce0dbcab8a8f6543ea9e7f"}, + {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9e838bba3a3bac0fe06d849d29772eb1afb9745a59710762e4ba3f4cb8424483"}, + {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:22f499f6157236c19f4bbbd472fa55b063db77a16cd74d49afe28992dff8c258"}, + {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:693902d433cf585133699972b6d7c42a8b9f8f826ebcaf0132ff55200afc599e"}, + {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4e77f2126c3e0b0d055f44513ed349038ac180371ed9b52fe96a32aa071a5107"}, + {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:657a05857bda581c3656bfc3b20e353c232e9193eb167766ad2dc58b56504948"}, + {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4bfa75a048c056a411f9705856abfc872558e33c055d80af6a380e3658766038"}, + {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:34ea1de54beef1c104422d210c47c7d2a4999bdecf42c7b5718fbe59a4cac383"}, + {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:90da3b5f694b85231cf93586dad5e90e2d71b9428f9aad96952c99055582f520"}, + {file = "kiwisolver-1.4.7-cp312-cp312-win32.whl", hash = "sha256:18e0cca3e008e17fe9b164b55735a325140a5a35faad8de92dd80265cd5eb80b"}, + {file = "kiwisolver-1.4.7-cp312-cp312-win_amd64.whl", hash = "sha256:58cb20602b18f86f83a5c87d3ee1c766a79c0d452f8def86d925e6c60fbf7bfb"}, + {file = "kiwisolver-1.4.7-cp312-cp312-win_arm64.whl", hash = "sha256:f5a8b53bdc0b3961f8b6125e198617c40aeed638b387913bf1ce78afb1b0be2a"}, + {file = "kiwisolver-1.4.7.tar.gz", hash = "sha256:9893ff81bd7107f7b685d3017cc6583daadb4fc26e4a888350df530e41980a60"}, +] + +[[package]] +name = "matplotlib" +version = "3.9.2" +requires_python = ">=3.9" +summary = "Python plotting package" +groups = ["default"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +dependencies = [ + "contourpy>=1.0.1", + "cycler>=0.10", + "fonttools>=4.22.0", + "importlib-resources>=3.2.0; python_version < \"3.10\"", + "kiwisolver>=1.3.1", + "numpy>=1.23", + "packaging>=20.0", + "pillow>=8", + "pyparsing>=2.3.1", + "python-dateutil>=2.7", +] +files = [ + {file = "matplotlib-3.9.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:ac43031375a65c3196bee99f6001e7fa5bdfb00ddf43379d3c0609bdca042df9"}, + {file = "matplotlib-3.9.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:be0fc24a5e4531ae4d8e858a1a548c1fe33b176bb13eff7f9d0d38ce5112a27d"}, + {file = "matplotlib-3.9.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf81de2926c2db243c9b2cbc3917619a0fc85796c6ba4e58f541df814bbf83c7"}, + {file = "matplotlib-3.9.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6ee45bc4245533111ced13f1f2cace1e7f89d1c793390392a80c139d6cf0e6c"}, + {file = "matplotlib-3.9.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:306c8dfc73239f0e72ac50e5a9cf19cc4e8e331dd0c54f5e69ca8758550f1e1e"}, + {file = "matplotlib-3.9.2-cp312-cp312-win_amd64.whl", hash = "sha256:5413401594cfaff0052f9d8b1aafc6d305b4bd7c4331dccd18f561ff7e1d3bd3"}, + {file = "matplotlib-3.9.2.tar.gz", hash = "sha256:96ab43906269ca64a6366934106fa01534454a69e471b7bf3d79083981aaab92"}, +] + +[[package]] +name = "matplotlib-inline" +version = "0.1.7" +requires_python = ">=3.8" +summary = "Inline Matplotlib backend for Jupyter" +groups = ["dev"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +dependencies = [ + "traitlets", +] +files = [ + {file = "matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca"}, + {file = "matplotlib_inline-0.1.7.tar.gz", hash = "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90"}, +] + [[package]] name = "ml-dtypes" version = "0.5.0" requires_python = ">=3.9" summary = "" groups = ["default"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" dependencies = [ "numpy>=1.21", "numpy>=1.21.2; python_version >= \"3.10\"", @@ -103,12 +538,25 @@ files = [ {file = "ml_dtypes-0.5.0.tar.gz", hash = "sha256:3e7d3a380fe73a63c884f06136f8baa7a5249cc8e9fdec677997dd78549f8128"}, ] +[[package]] +name = "nest-asyncio" +version = "1.6.0" +requires_python = ">=3.5" +summary = "Patch asyncio to allow nested event loops" +groups = ["dev"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +files = [ + {file = "nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c"}, + {file = "nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe"}, +] + [[package]] name = "numpy" version = "2.1.3" requires_python = ">=3.10" summary = "Fundamental package for array computing in Python" groups = ["default"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" files = [ {file = "numpy-2.1.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f55ba01150f52b1027829b50d70ef1dafd9821ea82905b63936668403c3b471e"}, {file = "numpy-2.1.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:13138eadd4f4da03074851a698ffa7e405f41a0845a6b1ad135b81596e4e9958"}, @@ -149,6 +597,7 @@ version = "3.4.0" requires_python = ">=3.8" summary = "Path optimization of einsum functions." groups = ["default"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" files = [ {file = "opt_einsum-3.4.0-py3-none-any.whl", hash = "sha256:69bb92469f86a1565195ece4ac0323943e83477171b91d24c35afe028a90d7cd"}, {file = "opt_einsum-3.4.0.tar.gz", hash = "sha256:96ca72f1b886d148241348783498194c577fa30a8faac108586b14f1ba4473ac"}, @@ -159,29 +608,200 @@ name = "packaging" version = "24.2" requires_python = ">=3.8" summary = "Core utilities for Python packages" -groups = ["default"] +groups = ["default", "dev"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" files = [ {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, ] +[[package]] +name = "parso" +version = "0.8.4" +requires_python = ">=3.6" +summary = "A Python Parser" +groups = ["dev"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +files = [ + {file = "parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18"}, + {file = "parso-0.8.4.tar.gz", hash = "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d"}, +] + +[[package]] +name = "pexpect" +version = "4.9.0" +summary = "Pexpect allows easy control of interactive console applications." +groups = ["dev"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\" and (sys_platform != \"win32\" and sys_platform != \"emscripten\")" +dependencies = [ + "ptyprocess>=0.5", +] +files = [ + {file = "pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"}, + {file = "pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"}, +] + +[[package]] +name = "pillow" +version = "11.0.0" +requires_python = ">=3.9" +summary = "Python Imaging Library (Fork)" +groups = ["default"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +files = [ + {file = "pillow-11.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d2c0a187a92a1cb5ef2c8ed5412dd8d4334272617f532d4ad4de31e0495bd923"}, + {file = "pillow-11.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:084a07ef0821cfe4858fe86652fffac8e187b6ae677e9906e192aafcc1b69903"}, + {file = "pillow-11.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8069c5179902dcdce0be9bfc8235347fdbac249d23bd90514b7a47a72d9fecf4"}, + {file = "pillow-11.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f02541ef64077f22bf4924f225c0fd1248c168f86e4b7abdedd87d6ebaceab0f"}, + {file = "pillow-11.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:fcb4621042ac4b7865c179bb972ed0da0218a076dc1820ffc48b1d74c1e37fe9"}, + {file = "pillow-11.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:00177a63030d612148e659b55ba99527803288cea7c75fb05766ab7981a8c1b7"}, + {file = "pillow-11.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8853a3bf12afddfdf15f57c4b02d7ded92c7a75a5d7331d19f4f9572a89c17e6"}, + {file = "pillow-11.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3107c66e43bda25359d5ef446f59c497de2b5ed4c7fdba0894f8d6cf3822dafc"}, + {file = "pillow-11.0.0-cp312-cp312-win32.whl", hash = "sha256:86510e3f5eca0ab87429dd77fafc04693195eec7fd6a137c389c3eeb4cfb77c6"}, + {file = "pillow-11.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:8ec4a89295cd6cd4d1058a5e6aec6bf51e0eaaf9714774e1bfac7cfc9051db47"}, + {file = "pillow-11.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:27a7860107500d813fcd203b4ea19b04babe79448268403172782754870dac25"}, + {file = "pillow-11.0.0.tar.gz", hash = "sha256:72bacbaf24ac003fea9bff9837d1eedb6088758d41e100c1552930151f677739"}, +] + +[[package]] +name = "platformdirs" +version = "4.3.6" +requires_python = ">=3.8" +summary = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." +groups = ["default", "dev"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +files = [ + {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, + {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, +] + [[package]] name = "pluggy" version = "1.5.0" requires_python = ">=3.8" summary = "plugin and hook calling mechanisms for python" groups = ["default"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" files = [ {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, ] +[[package]] +name = "pooch" +version = "1.8.2" +requires_python = ">=3.7" +summary = "A friend to fetch your data files" +groups = ["default"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +dependencies = [ + "packaging>=20.0", + "platformdirs>=2.5.0", + "requests>=2.19.0", +] +files = [ + {file = "pooch-1.8.2-py3-none-any.whl", hash = "sha256:3529a57096f7198778a5ceefd5ac3ef0e4d06a6ddaf9fc2d609b806f25302c47"}, + {file = "pooch-1.8.2.tar.gz", hash = "sha256:76561f0de68a01da4df6af38e9955c4c9d1a5c90da73f7e40276a5728ec83d10"}, +] + +[[package]] +name = "prompt-toolkit" +version = "3.0.48" +requires_python = ">=3.7.0" +summary = "Library for building powerful interactive command lines in Python" +groups = ["dev"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +dependencies = [ + "wcwidth", +] +files = [ + {file = "prompt_toolkit-3.0.48-py3-none-any.whl", hash = "sha256:f49a827f90062e411f1ce1f854f2aedb3c23353244f8108b89283587397ac10e"}, + {file = "prompt_toolkit-3.0.48.tar.gz", hash = "sha256:d6623ab0477a80df74e646bdbc93621143f5caf104206aa29294d53de1a03d90"}, +] + +[[package]] +name = "psutil" +version = "6.1.0" +requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +summary = "Cross-platform lib for process and system monitoring in Python." +groups = ["dev"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +files = [ + {file = "psutil-6.1.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6e2dcd475ce8b80522e51d923d10c7871e45f20918e027ab682f94f1c6351688"}, + {file = "psutil-6.1.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:0895b8414afafc526712c498bd9de2b063deaac4021a3b3c34566283464aff8e"}, + {file = "psutil-6.1.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9dcbfce5d89f1d1f2546a2090f4fcf87c7f669d1d90aacb7d7582addece9fb38"}, + {file = "psutil-6.1.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:498c6979f9c6637ebc3a73b3f87f9eb1ec24e1ce53a7c5173b8508981614a90b"}, + {file = "psutil-6.1.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d905186d647b16755a800e7263d43df08b790d709d575105d419f8b6ef65423a"}, + {file = "psutil-6.1.0-cp37-abi3-win32.whl", hash = "sha256:1ad45a1f5d0b608253b11508f80940985d1d0c8f6111b5cb637533a0e6ddc13e"}, + {file = "psutil-6.1.0-cp37-abi3-win_amd64.whl", hash = "sha256:a8fb3752b491d246034fa4d279ff076501588ce8cbcdbb62c32fd7a377d996be"}, + {file = "psutil-6.1.0.tar.gz", hash = "sha256:353815f59a7f64cdaca1c0307ee13558a0512f6db064e92fe833784f08539c7a"}, +] + +[[package]] +name = "ptyprocess" +version = "0.7.0" +summary = "Run a subprocess in a pseudo terminal" +groups = ["dev"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\" and (sys_platform != \"win32\" and sys_platform != \"emscripten\")" +files = [ + {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, + {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, +] + +[[package]] +name = "pure-eval" +version = "0.2.3" +summary = "Safely evaluate AST nodes without side effects" +groups = ["dev"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +files = [ + {file = "pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0"}, + {file = "pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42"}, +] + +[[package]] +name = "pycparser" +version = "2.22" +requires_python = ">=3.8" +summary = "C parser in Python" +groups = ["dev"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\" and implementation_name == \"pypy\"" +files = [ + {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, + {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, +] + +[[package]] +name = "pygments" +version = "2.18.0" +requires_python = ">=3.8" +summary = "Pygments is a syntax highlighting package written in Python." +groups = ["dev"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +files = [ + {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, + {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, +] + +[[package]] +name = "pyparsing" +version = "3.2.0" +requires_python = ">=3.9" +summary = "pyparsing module - Classes and methods to define and execute parsing grammars" +groups = ["default"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +files = [ + {file = "pyparsing-3.2.0-py3-none-any.whl", hash = "sha256:93d9577b88da0bbea8cc8334ee8b918ed014968fd2ec383e868fb8afb1ccef84"}, + {file = "pyparsing-3.2.0.tar.gz", hash = "sha256:cbf74e27246d595d9a74b186b810f6fbb86726dbf3b9532efb343f6d7294fe9c"}, +] + [[package]] name = "pyqtgraph" version = "0.13.7" requires_python = ">=3.9" summary = "Scientific Graphics and GUI Library for Python" groups = ["default"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" dependencies = [ "numpy>=1.22.0", ] @@ -190,12 +810,67 @@ files = [ {file = "pyqtgraph-0.13.7.tar.gz", hash = "sha256:64f84f1935c6996d0e09b1ee66fe478a7771e3ca6f3aaa05f00f6e068321d9e3"}, ] +[[package]] +name = "pyside6" +version = "6.8.0.2" +requires_python = "<3.14,>=3.9" +summary = "Python bindings for the Qt cross-platform application and UI framework" +groups = ["default"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +dependencies = [ + "PySide6-Addons==6.8.0.2", + "PySide6-Essentials==6.8.0.2", + "shiboken6==6.8.0.2", +] +files = [ + {file = "PySide6-6.8.0.2-cp39-abi3-macosx_12_0_universal2.whl", hash = "sha256:cecc6ce1da6cb04542ff5a0887734f63e6ecf54258d1786285b9c7904abd9b01"}, + {file = "PySide6-6.8.0.2-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3258f3c63dc5053b8d5b8d2588caca8bb3a36e2f74413511e4676df0e73b6f1e"}, + {file = "PySide6-6.8.0.2-cp39-abi3-manylinux_2_31_aarch64.whl", hash = "sha256:6a25cf784f978fa2a23b4d089970b27ebe14d26adcaf38b2819cb04483de4ce9"}, + {file = "PySide6-6.8.0.2-cp39-abi3-win_amd64.whl", hash = "sha256:3e8fffca9a934e30c07c3f34bb572f84bfcf02385acbc715e65fbdd9746ecc2b"}, +] + +[[package]] +name = "pyside6-addons" +version = "6.8.0.2" +requires_python = "<3.14,>=3.9" +summary = "Python bindings for the Qt cross-platform application and UI framework (Addons)" +groups = ["default"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +dependencies = [ + "PySide6-Essentials==6.8.0.2", + "shiboken6==6.8.0.2", +] +files = [ + {file = "PySide6_Addons-6.8.0.2-cp39-abi3-macosx_12_0_universal2.whl", hash = "sha256:30c9ca570dd18ffbfd34ee95e0a319c34313a80425c4011d6ccc9f4cca0dc4c8"}, + {file = "PySide6_Addons-6.8.0.2-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:754a9822ab2dc313f9998edef69d8a12bc9fd61727543f8d30806ed272ae1e52"}, + {file = "PySide6_Addons-6.8.0.2-cp39-abi3-manylinux_2_31_aarch64.whl", hash = "sha256:553f3fa412f423929b5cd8b7d43fd5f02161851f10a438174a198b0f1a044df7"}, + {file = "PySide6_Addons-6.8.0.2-cp39-abi3-win_amd64.whl", hash = "sha256:ae4377a3e10fe720a9119677b31d8de13e2a5221c06b332df045af002f5f4c3d"}, +] + +[[package]] +name = "pyside6-essentials" +version = "6.8.0.2" +requires_python = "<3.14,>=3.9" +summary = "Python bindings for the Qt cross-platform application and UI framework (Essentials)" +groups = ["default"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +dependencies = [ + "shiboken6==6.8.0.2", +] +files = [ + {file = "PySide6_Essentials-6.8.0.2-cp39-abi3-macosx_12_0_universal2.whl", hash = "sha256:3df4ed75bbb74d74ac338b330819b1a272e7f5cec206765c7176a197c8bc9c79"}, + {file = "PySide6_Essentials-6.8.0.2-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:7df6d6c1da4858dbdea77c74d7270d9c68e8d1bbe3362892abd1a5ade3815a50"}, + {file = "PySide6_Essentials-6.8.0.2-cp39-abi3-manylinux_2_31_aarch64.whl", hash = "sha256:cf490145d18812a6cff48b0b0afb0bfaf7066744bfbd09eb071c3323f1d6d00d"}, + {file = "PySide6_Essentials-6.8.0.2-cp39-abi3-win_amd64.whl", hash = "sha256:d2f029b8c9f0106f57b26aa8c435435d7f509c80525075343e07177b283f862e"}, +] + [[package]] name = "pytest" version = "8.3.3" requires_python = ">=3.8" summary = "pytest: simple powerful testing with Python" groups = ["default"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" dependencies = [ "colorama; sys_platform == \"win32\"", "exceptiongroup>=1.0.0rc8; python_version < \"3.11\"", @@ -209,12 +884,136 @@ files = [ {file = "pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181"}, ] +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +summary = "Extensions to the standard Python datetime module" +groups = ["default", "dev"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +dependencies = [ + "six>=1.5", +] +files = [ + {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, + {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, +] + +[[package]] +name = "pyvista" +version = "0.44.2" +requires_python = ">=3.8" +summary = "Easier Pythonic interface to VTK" +groups = ["default"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +dependencies = [ + "matplotlib>=3.0.1", + "numpy>=1.21.0", + "pillow", + "pooch", + "scooby>=0.5.1", + "typing-extensions", + "vtk<9.4.0", +] +files = [ + {file = "pyvista-0.44.2-py3-none-any.whl", hash = "sha256:8530d35f57cdaa33507ac9aec19e3292be0bc9026b28e4f12df7e8054438d028"}, + {file = "pyvista-0.44.2.tar.gz", hash = "sha256:db65943c3c1c9ba49fe16f5a25a5bc23b74bf1ea7a38aae4ef9c4dc5838ccf5e"}, +] + +[[package]] +name = "pyvistaqt" +version = "0.11.1" +requires_python = ">=3.7" +summary = "pyvista qt plotter" +groups = ["default"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +dependencies = [ + "QtPy>=1.9.0", + "pyvista>=0.32.0", +] +files = [ + {file = "pyvistaqt-0.11.1-py3-none-any.whl", hash = "sha256:3ddc05418fcb297d471e7f7c0fdc89dbd5b6050653b4a86e66e5c1ce7e3563cc"}, + {file = "pyvistaqt-0.11.1.tar.gz", hash = "sha256:5403bfeb82cf063288107a9be9780ca3ca70948e73d33d16a65a83a711d51a36"}, +] + +[[package]] +name = "pywin32" +version = "308" +summary = "Python for Window Extensions" +groups = ["dev"] +marker = "sys_platform == \"win32\" and platform_python_implementation != \"PyPy\" and python_version >= \"3.12\" and python_version < \"3.13\"" +files = [ + {file = "pywin32-308-cp312-cp312-win32.whl", hash = "sha256:587f3e19696f4bf96fde9d8a57cec74a57021ad5f204c9e627e15c33ff568897"}, + {file = "pywin32-308-cp312-cp312-win_amd64.whl", hash = "sha256:00b3e11ef09ede56c6a43c71f2d31857cf7c54b0ab6e78ac659497abd2834f47"}, + {file = "pywin32-308-cp312-cp312-win_arm64.whl", hash = "sha256:9b4de86c8d909aed15b7011182c8cab38c8850de36e6afb1f0db22b8959e3091"}, +] + +[[package]] +name = "pyzmq" +version = "26.2.0" +requires_python = ">=3.7" +summary = "Python bindings for 0MQ" +groups = ["dev"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +dependencies = [ + "cffi; implementation_name == \"pypy\"", +] +files = [ + {file = "pyzmq-26.2.0-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:ded0fc7d90fe93ae0b18059930086c51e640cdd3baebdc783a695c77f123dcd9"}, + {file = "pyzmq-26.2.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:17bf5a931c7f6618023cdacc7081f3f266aecb68ca692adac015c383a134ca52"}, + {file = "pyzmq-26.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55cf66647e49d4621a7e20c8d13511ef1fe1efbbccf670811864452487007e08"}, + {file = "pyzmq-26.2.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4661c88db4a9e0f958c8abc2b97472e23061f0bc737f6f6179d7a27024e1faa5"}, + {file = "pyzmq-26.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea7f69de383cb47522c9c208aec6dd17697db7875a4674c4af3f8cfdac0bdeae"}, + {file = "pyzmq-26.2.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:7f98f6dfa8b8ccaf39163ce872bddacca38f6a67289116c8937a02e30bbe9711"}, + {file = "pyzmq-26.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:e3e0210287329272539eea617830a6a28161fbbd8a3271bf4150ae3e58c5d0e6"}, + {file = "pyzmq-26.2.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:6b274e0762c33c7471f1a7471d1a2085b1a35eba5cdc48d2ae319f28b6fc4de3"}, + {file = "pyzmq-26.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:29c6a4635eef69d68a00321e12a7d2559fe2dfccfa8efae3ffb8e91cd0b36a8b"}, + {file = "pyzmq-26.2.0-cp312-cp312-win32.whl", hash = "sha256:989d842dc06dc59feea09e58c74ca3e1678c812a4a8a2a419046d711031f69c7"}, + {file = "pyzmq-26.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:2a50625acdc7801bc6f74698c5c583a491c61d73c6b7ea4dee3901bb99adb27a"}, + {file = "pyzmq-26.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:4d29ab8592b6ad12ebbf92ac2ed2bedcfd1cec192d8e559e2e099f648570e19b"}, + {file = "pyzmq-26.2.0.tar.gz", hash = "sha256:070672c258581c8e4f640b5159297580a9974b026043bd4ab0470be9ed324f1f"}, +] + +[[package]] +name = "qtpy" +version = "2.4.2" +requires_python = ">=3.7" +summary = "Provides an abstraction layer on top of the various Qt bindings (PyQt5/6 and PySide2/6)." +groups = ["default"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +dependencies = [ + "packaging", +] +files = [ + {file = "QtPy-2.4.2-py3-none-any.whl", hash = "sha256:5a696b1dd7a354cb330657da1d17c20c2190c72d4888ba923f8461da67aa1a1c"}, + {file = "qtpy-2.4.2.tar.gz", hash = "sha256:9d6ec91a587cc1495eaebd23130f7619afa5cdd34a277acb87735b4ad7c65156"}, +] + +[[package]] +name = "requests" +version = "2.32.3" +requires_python = ">=3.8" +summary = "Python HTTP for Humans." +groups = ["default"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +dependencies = [ + "certifi>=2017.4.17", + "charset-normalizer<4,>=2", + "idna<4,>=2.5", + "urllib3<3,>=1.21.1", +] +files = [ + {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, + {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, +] + [[package]] name = "scipy" version = "1.14.1" requires_python = ">=3.10" summary = "Fundamental algorithms for scientific computing in Python" groups = ["default"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" dependencies = [ "numpy<2.3,>=1.23.5", ] @@ -237,3 +1036,144 @@ files = [ {file = "scipy-1.14.1-cp313-cp313-win_amd64.whl", hash = "sha256:baff393942b550823bfce952bb62270ee17504d02a1801d7fd0719534dfb9c84"}, {file = "scipy-1.14.1.tar.gz", hash = "sha256:5a275584e726026a5699459aa72f828a610821006228e841b94275c4a7c08417"}, ] + +[[package]] +name = "scooby" +version = "0.10.0" +requires_python = ">=3.8" +summary = "A Great Dane turned Python environment detective" +groups = ["default"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +files = [ + {file = "scooby-0.10.0-py3-none-any.whl", hash = "sha256:0a3d7e304f8ebb16f69ff7f6360c345d7f50b45f2ddbf7c3d18a6a0dc2cb03a6"}, + {file = "scooby-0.10.0.tar.gz", hash = "sha256:7ea33c262c0cc6a33c6eeeb5648df787be4f22660e53c114e5fff1b811a8854f"}, +] + +[[package]] +name = "shiboken6" +version = "6.8.0.2" +requires_python = "<3.14,>=3.9" +summary = "Python/C++ bindings helper module" +groups = ["default"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +files = [ + {file = "shiboken6-6.8.0.2-cp39-abi3-macosx_12_0_universal2.whl", hash = "sha256:9019e1fcfeed8bb350222e981748ef05a2fec11e31ddf616657be702f0b7a468"}, + {file = "shiboken6-6.8.0.2-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:fa7d411c3c67b4296847b3f5f572268e219d947d029ff9d8bce72fe6982d92bc"}, + {file = "shiboken6-6.8.0.2-cp39-abi3-manylinux_2_31_aarch64.whl", hash = "sha256:1aaa8b7f9138818322ef029b2c487d1c6e00dc3f53084e62e1d11bdea47e47c2"}, + {file = "shiboken6-6.8.0.2-cp39-abi3-win_amd64.whl", hash = "sha256:b11e750e696bb565d897e0f5836710edfb86bd355f87b09988bd31b2aad404d3"}, +] + +[[package]] +name = "six" +version = "1.16.0" +requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +summary = "Python 2 and 3 compatibility utilities" +groups = ["default", "dev"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +files = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] + +[[package]] +name = "stack-data" +version = "0.6.3" +summary = "Extract data from python stack frames and tracebacks for informative displays" +groups = ["dev"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +dependencies = [ + "asttokens>=2.1.0", + "executing>=1.2.0", + "pure-eval", +] +files = [ + {file = "stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695"}, + {file = "stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9"}, +] + +[[package]] +name = "tornado" +version = "6.4.2" +requires_python = ">=3.8" +summary = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." +groups = ["dev"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +files = [ + {file = "tornado-6.4.2-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e828cce1123e9e44ae2a50a9de3055497ab1d0aeb440c5ac23064d9e44880da1"}, + {file = "tornado-6.4.2-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:072ce12ada169c5b00b7d92a99ba089447ccc993ea2143c9ede887e0937aa803"}, + {file = "tornado-6.4.2-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a017d239bd1bb0919f72af256a970624241f070496635784d9bf0db640d3fec"}, + {file = "tornado-6.4.2-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c36e62ce8f63409301537222faffcef7dfc5284f27eec227389f2ad11b09d946"}, + {file = "tornado-6.4.2-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bca9eb02196e789c9cb5c3c7c0f04fb447dc2adffd95265b2c7223a8a615ccbf"}, + {file = "tornado-6.4.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:304463bd0772442ff4d0f5149c6f1c2135a1fae045adf070821c6cdc76980634"}, + {file = "tornado-6.4.2-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:c82c46813ba483a385ab2a99caeaedf92585a1f90defb5693351fa7e4ea0bf73"}, + {file = "tornado-6.4.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:932d195ca9015956fa502c6b56af9eb06106140d844a335590c1ec7f5277d10c"}, + {file = "tornado-6.4.2-cp38-abi3-win32.whl", hash = "sha256:2876cef82e6c5978fde1e0d5b1f919d756968d5b4282418f3146b79b58556482"}, + {file = "tornado-6.4.2-cp38-abi3-win_amd64.whl", hash = "sha256:908b71bf3ff37d81073356a5fadcc660eb10c1476ee6e2725588626ce7e5ca38"}, + {file = "tornado-6.4.2.tar.gz", hash = "sha256:92bad5b4746e9879fd7bf1eb21dce4e3fc5128d71601f80005afa39237ad620b"}, +] + +[[package]] +name = "traitlets" +version = "5.14.3" +requires_python = ">=3.8" +summary = "Traitlets Python configuration system" +groups = ["dev"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +files = [ + {file = "traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f"}, + {file = "traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7"}, +] + +[[package]] +name = "typing-extensions" +version = "4.12.2" +requires_python = ">=3.8" +summary = "Backported and Experimental Type Hints for Python 3.8+" +groups = ["default"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +files = [ + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, +] + +[[package]] +name = "urllib3" +version = "2.2.3" +requires_python = ">=3.8" +summary = "HTTP library with thread-safe connection pooling, file post, and more." +groups = ["default"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +files = [ + {file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"}, + {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"}, +] + +[[package]] +name = "vtk" +version = "9.3.1" +summary = "VTK is an open-source toolkit for 3D computer graphics, image processing, and visualization" +groups = ["default"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +dependencies = [ + "matplotlib>=2.0.0", +] +files = [ + {file = "vtk-9.3.1-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:05a4b6e387a906e8c8d6844441f9200116e937069fcf81f43e2600f26eb046de"}, + {file = "vtk-9.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bdbefb1aef9599a0a0b8222c9582f26946732a93534e6ec37d4b8e2c524c627e"}, + {file = "vtk-9.3.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f728bb61f43fce850d622ced3b3d51b3116f767685ca4e4e0076f624e2d2307d"}, + {file = "vtk-9.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:685988e09070e06c8605886591698fd42d8225489509b6537a5046cd034cc93e"}, +] + +[[package]] +name = "wcwidth" +version = "0.2.13" +summary = "Measures the displayed width of unicode strings in a terminal" +groups = ["dev"] +marker = "python_version >= \"3.12\" and python_version < \"3.13\"" +dependencies = [ + "backports-functools-lru-cache>=1.2.1; python_version < \"3.2\"", +] +files = [ + {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, + {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, +] diff --git a/pyproject.toml b/pyproject.toml index 0158937..43adc39 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,8 +5,8 @@ description = "A solar car racing simulation library and GUI tool" authors = [ {name = "saji", email = "saji@saji.dev"}, ] -dependencies = ["pyqtgraph>=0.13.7", "jax>=0.4.35", "pytest>=8.3.3"] -requires-python = ">=3.12" +dependencies = ["pyqtgraph>=0.13.7", "jax>=0.4.35", "pytest>=8.3.3", "pyside6>=6.8.0.2", "matplotlib>=3.9.2", "gymnasium>=1.0.0", "pyvista>=0.44.2", "pyvistaqt>=0.11.1"] +requires-python = ">=3.10,<3.13" readme = "README.md" license = {text = "MIT"} @@ -17,3 +17,16 @@ build-backend = "pdm.backend" [tool.pdm] distribution = true + + +[tool.ruff.lint] + + +[tool.basedpyright] +reportInvalidTypeForm = false +typeCheckingMode = "off" + +[dependency-groups] +dev = [ + "ipykernel>=6.29.5", +] diff --git a/src/solarcarsim/environments.py b/src/solarcarsim/environments.py index efd375f..ab7fffe 100644 --- a/src/solarcarsim/environments.py +++ b/src/solarcarsim/environments.py @@ -1,3 +1,121 @@ # models to generate different environments that the car can drive in. # This includes terrain, clouds, wind, solar conditions, and the route along the terrain. + +import jax +import jax.numpy as jnp +from jax import random +import pyqtgraph as pg +from functools import partial +from pyqtgraph.Qt import QtCore, QtGui +from typing import NamedTuple +import matplotlib.pyplot as plt +import sys + + +class TerrainParams(NamedTuple): + size: int = 256 + octaves: int = 6 + persistence: float = 0.5 + lacunarity: float = 2.0 + seed: int = 42 + + +def lerp(a, b, t): + # assume a and b are pairs of numbers + x = jnp.array([0,1]) + f = jnp.array([a,b]) + return jnp.interp(t, x, f) + +# @partial(jax.jit, static_argnums=(2,)) +# def _make_noise_layer(key: random.PRNGKey, frequency: float, shape) -> jnp.ndarray: +# +# noise = random.normal(key, shape) +# # create the grid. +# x = jnp.linspace(0, shape[0] - 1, ) + +import jax +import jax.numpy as jnp + +def generate_permutation(): + """Generate a permutation table.""" + p = jnp.arange(256, dtype=jnp.int32) + return jnp.concatenate([p, p]) + +@jax.jit +def fade(t): + """Fade function for smooth interpolation.""" + return t * t * t * (t * (t * 6 - 15) + 10) + +@jax.jit +def lerp(t, a, b): + """Linear interpolation.""" + return a + t * (b - a) + +@jax.jit +def grad(hash, x, y): + """Calculate gradient.""" + h = hash & 15 + grad_x = jnp.where(h < 8, x, y) + grad_y = jnp.where(h < 4, y, jnp.where((h == 12) | (h == 14), x, y)) + return jnp.where(h & 1, -grad_x, grad_x) + jnp.where(h & 2, -grad_y, grad_y) + +def perlin(pos): + """ Perlin noise. Shape (N) where N = n_dims (2,3) """ + + cellpos = pos % 1.0 # get the position inside the cell + + upos = fade(pos) + +@jax.jit +def perlin_noise_2d(x, y, p): + """Generate 2D Perlin noise value.""" + # Floor coordinates + xi = jnp.floor(x).astype(jnp.int32) & 255 + yi = jnp.floor(y).astype(jnp.int32) & 255 + + # Fractional coordinates + xf = x - jnp.floor(x) + yf = y - jnp.floor(y) + + # Fade curves + u = fade(xf) + v = fade(yf) + + # Hash coordinates of cube corners + aa = p[p[xi] + yi] + ab = p[p[xi] + yi + 1] + ba = p[p[xi + 1] + yi] + bb = p[p[xi + 1] + yi + 1] + + # Gradients + g1 = grad(aa, xf, yf) + g2 = grad(ba, xf - 1, yf) + g3 = grad(ab, xf, yf - 1) + g4 = grad(bb, xf - 1, yf - 1) + + # Interpolate + x1 = lerp(u, g1, g2) + x2 = lerp(u, g3, g4) + return lerp(v, x1, x2) + +def generate_noise_grid(width, height, scale=50.0): + """Generate a grid of Perlin noise values.""" + p = generate_permutation() + # compute the gradient grid. + gradgrid = + x = jnp.linspace(0, width/scale, width) + y = jnp.linspace(0, height/scale, height) + X, Y = jnp.meshgrid(x, y) + return perlin_noise_2d(X, Y, p) + +# Example usage: +key = jax.random.PRNGKey(23) +noise = generate_noise_grid(256, 256) +plt.imshow(noise) +plt.savefig("output.png") + + +def GymV1(): + """ Makes a version 1 gym - simply an elevation profile. """ + diff --git a/src/solarcarsim/gym.py b/src/solarcarsim/gym.py new file mode 100644 index 0000000..0fb434a --- /dev/null +++ b/src/solarcarsim/gym.py @@ -0,0 +1,34 @@ + +from typing import Optional +import numpy as np +import gymnasium as gym +from solarcarsim.physsim import CarParams, DefaultCar + + + + + +class SolarRaceV1(gym.Env): + """ A primitive hill climber. Aims to solve the given route optimizing + for energy usage and on-time arrival. Does not have wind or cloud simulations. + Does simulate drag, rolling resistance, and slope power. The action space is the + velocity of the car. + """ + + def __init__(self, car: CarParams = DefaultCar(), terrain = None, timestep: float = 1.0): + # TODO: terrain parameters + + # car max speed. + self.params = { + "timestep": timestep, + "car": car + } + + self.observation_space = gym.spaces.Dict({ + "position": gym.spaces.Box(0, 1000.0, shape=(1,)), + "time": gym.spaces.Box(0,1000), + "energy": gym.spaces.Box(-1.0e6, 0.) + # TODO: add the elevation profile to the observations. + }) + + self.action_space = gym.spaces.Box(0, 5.0, shape=(1,)) #velocity, m/s diff --git a/src/solarcarsim/perlin.py b/src/solarcarsim/perlin.py new file mode 100644 index 0000000..152a07b --- /dev/null +++ b/src/solarcarsim/perlin.py @@ -0,0 +1,137 @@ +import jax +import jax.numpy as jnp +from jax import grad, jit, vmap +from functools import partial +from typing import Optional, Tuple, Union + +def generate_permutation(key: jax.random.PRNGKey, size: int = 256) -> jnp.ndarray: + """Generate a random permutation table.""" + perm = jax.random.permutation(key, size) + # Double the permutation to avoid need for wrapping + return jnp.concatenate([perm, perm]) + +@partial(jit, static_argnums=(1,)) +def generate_gradients(key: jax.random.PRNGKey, dim: int, size: int = 256) -> jnp.ndarray: + """Generate random unit vectors for gradient table.""" + # Generate random vectors + grads = jax.random.normal(key, (size, dim)) + # Normalize to unit vectors + grads = grads / jnp.linalg.norm(grads, axis=1, keepdims=True) + # Double the gradients to avoid need for wrapping + return jnp.concatenate([grads, grads], axis=0) + +@jit +def fade(t: jnp.ndarray) -> jnp.ndarray: + """Fade function 6t^5 - 15t^4 + 10t^3.""" + return t * t * t * (t * (t * 6 - 15) + 10) + +def perlin_noise(coords: jnp.ndarray, + gradients: jnp.ndarray, + perm: jnp.ndarray, + octaves: int = 1, + persistence: float = 0.5, + lacunarity: float = 2.0, + ridged: bool = False, + billow: bool = False) -> jnp.ndarray: + """ + Generate N-dimensional Perlin noise. + + Args: + coords: Array of shape (..., dim) containing coordinates + gradients: Gradient vectors of shape (size, dim) + perm: Permutation table + octaves: Number of octaves for fractal noise + persistence: Amplitude multiplier for each octave + lacunarity: Frequency multiplier for each octave + ridged: If True, generates ridged multifractal noise + billow: If True, generates billow noise (squared) + + Returns: + Array of noise values + """ + def single_noise(p): + # Get integer coordinates + pi = jnp.floor(p).astype(jnp.int32) + + # Get decimal part + pf = p - pi + + # Generate corner coordinates + corners = jnp.stack(jnp.meshgrid( + *[jnp.array([0, 1]) for _ in range(p.shape[0])], + indexing='ij' + )).reshape(p.shape[0], -1).T + + # Get gradients for each corner + corner_gradients = jnp.zeros((corners.shape[0], p.shape[0])) + + for i in range(corners.shape[0]): + corner_coords = pi + corners[i] + # Hash coordinates to get gradient index + index = corner_coords[0] + for j in range(1, p.shape[0]): + index = perm[index] + corner_coords[j] + index = perm[index] % (gradients.shape[0] // 2) + corner_gradients = corner_gradients.at[i].set(gradients[index]) + + # Calculate dot products + vectors = pf - corners + dots = jnp.sum(vectors * corner_gradients, axis=1) + + # Interpolate + fade_coords = fade(pf) + for i in range(p.shape[0]): + n_corners = 2 ** i + for j in range(0, dots.shape[0], n_corners * 2): + t = fade_coords[i] + dots = dots.at[j:j+n_corners].set( + dots[j:j+n_corners] + t * (dots[j+n_corners:j+2*n_corners] - dots[j:j+n_corners]) + ) + + return dots[0] + + # Vectorize over multiple coordinates + noise_fn = vmap(single_noise) + + # Initialize accumulator + result = jnp.zeros(coords.shape[:-1]) + frequency = 1.0 + amplitude = 1.0 + max_value = 0.0 + + # Generate fractal noise + for _ in range(octaves): + noise = noise_fn(coords * frequency) + + if ridged: + noise = 1.0 - jnp.abs(noise) + elif billow: + noise = noise * noise + + result += noise * amplitude + max_value += amplitude + + frequency *= lacunarity + amplitude *= persistence + + # Normalize + result /= max_value + return result + +# Example usage for 1D noise +key = jax.random.PRNGKey(0) +key1, key2 = jax.random.split(key) + +# Generate tables +perm = generate_permutation(key1) +gradients = generate_gradients(key2, dim=1) + +# Generate 1D coordinates +x = jnp.linspace(0, 10, 1000) +coords = jnp.expand_dims(x, axis=1) + +# Generate different types of noise +basic_noise = perlin_noise(coords, gradients, perm) +fractal_noise = perlin_noise(coords, gradients, perm, octaves=6) +ridged_noise = perlin_noise(coords, gradients, perm, octaves=6, ridged=True) +billow_noise = perlin_noise(coords, gradients, perm, octaves=6, billow=True) \ No newline at end of file diff --git a/src/solarcarsim/physsim.py b/src/solarcarsim/physsim.py index 1d887c7..fff7101 100644 --- a/src/solarcarsim/physsim.py +++ b/src/solarcarsim/physsim.py @@ -1,16 +1,133 @@ import jax.numpy as jnp +from jax import grad, jit, vmap, lax +from functools import partial -def calculate_energy_consumption(car_params, elevation_profile): +from typing import NamedTuple, Tuple + +class MotorParams(NamedTuple): + kv: float + kt: float + resistance: float + friction_coeff: float + iron_coeff: float + + +class BatteryParams(NamedTuple): + shape: Tuple[int, int] # (series,parallel) array of batteries + resistance: float # ohms + initial_energy: float # joules + +class CarParams(NamedTuple): + """ Physical Data for Solar Car Parameters """ + mass: float = 800 # kg + frontal_area: float = 1.3 # m^2 + drag_coeff: float = 0.018 # drag coefficient, dimensionless + rolling_coeff: float = 0.002 # rolling resistance. + moter_eff: float = 0.93 # 0 < x < 1 scaling factor + solar_area: float = 5.0 # m^2, typically 5.0 + solar_eff: float = 0.20 # 0 < x < 1, typically ~.25 + n_motors: int = 2 # how many motors we have. + motor: MotorParams = MotorParams(8.43, 1.1, 100.0, 0.001, 0.001) # mitsuba m2090 estimate + battery: BatteryParams = BatteryParams((36,19), 0.0126, 66.6e3) # freebasing 50s pack. + + + +def DefaultCar() -> CarParams: + """ Creates a basic car """ + return CarParams(1000, 1.3, 0.18, 0.002, 0.85, 5.0, 0.23) + + + +# some physics equations using jax + + +@jit +def normal_force(mass, theta): + return mass * 9.8 * jnp.cos(theta) + +@jit +def downslope_force(mass, theta): + return mass * 9.8 * jnp.sin(theta) + +@partial(jit, static_argnames=['crr']) +def rolling_force(mass, theta, crr): + return normal_force(mass, theta) * crr + +@partial(jit, static_argnames=['area', 'cd', 'rho']) +def drag_force(u, area, cd, rho): + return 0.5 * rho * jnp.pow(u, 2) * cd * area + +# we can use those forces above to determine what forces we have to overcome. Sum(F)=0 + +@partial(jit, static_argnums=(3,4,5,6,7,)) +def bldc_power_draw(torque, velocity, resistance=0.1, kt=0.1, + Cf=0.01, iron_loss_coeff=0.005): """ - Calculate energy consumption based on car parameters and elevation profile. + Approximates power draw of a BLDC motor outputting a torque at a given velocity Args: - car_params (dict): Dictionary containing car parameters. - elevation_profile (list): List of elevation points. - + torq: Applied force in Newton/meters + velocity: Angular velocity in rad/s + resistance: Motor phase resistance (ohms) + kt: Torque constant (N⋅m/A) + friction_coeff: Mechanical friction coefficient + iron_loss_coeff: Iron loss coefficient (core losses) + Returns: - float: Total energy consumed. + Total electrical power draw in Watts """ - # Placeholder for actual calculations - return 0.0 + + # Current required for torque (simplified relationship) + current = torque / kt + + # Copper losses (I²R) + copper_losses = resistance * current**2 + # Mechanical friction losses + friction_losses = Cf * velocity**2 + # Iron losses (simplified model - primarily dependent on speed) + iron_losses = iron_loss_coeff * velocity**2 + # Mechanical power output + mechanical_power = torque * velocity + + # Total electrical power input + total_power = mechanical_power + copper_losses + friction_losses + iron_losses + + return total_power +@partial(jit, static_argnames=['resistance', 'kt', 'kv', 'vmax', 'Cf']) +def bldc_torque(velocity, current_limit, resistance, kt, kv, vmax, Cf): + + bemf = velocity / kv + v_avail = jnp.clip(vmax - bemf, 0.0, vmax) + current = jnp.clip(v_avail / resistance, 0.0, current_limit) + + torque = kt * current + friction_torque = Cf * velocity + net_torque = jnp.maximum(torque - friction_torque, 0.0) + stall_torque = kt * current_limit + return jnp.where(velocity < 0.01, stall_torque, net_torque) + +@partial(jit, static_argnums=(2,3,)) +def battery_powerloss(current,cell_r, battery_shape: Tuple[int,int]): + r_array = jnp.full(battery_shape, cell_r) + branch_current = current / battery_shape[1] + I_array = jnp.full(battery_shape, branch_current) + cell_Ploss = jnp.square(I_array) * r_array + return jnp.sum(cell_Ploss) + + + +def forward(state, timestep, control, params: CarParams): + # state is (position, time, velocity, energy) + # control is -1 to 1 (motor max current percent.) + # timestep is >0 time to advance + # params is the params dictionary. + # returns the next state with (position', time + timestep, velocity', energy') + # TODO: terrain, weather, solar + + # determine the forces acting on the car. + dragf = drag_force(state[2], params.frontal_area, params.drag_coeff, 1.184) + rollf = rolling_force(params.mass, 0, params.rolling_coeff) + hillforce = downslope_force(params.mass, 0) + + pass diff --git a/src/solarcarsim/vis.py b/src/solarcarsim/vis.py index e69de29..bb1776c 100644 --- a/src/solarcarsim/vis.py +++ b/src/solarcarsim/vis.py @@ -0,0 +1 @@ +import pyray as ray \ No newline at end of file