├── 00_tips.ipynb ├── 01_intro.ipynb ├── 02_numpy.ipynb ├── 03_functions.ipynb ├── 04_matplotlib.ipynb ├── 05_sympy.ipynb ├── 06_scipy.ipynb ├── README.md ├── TODO.md ├── _config.yml ├── _toc.yml ├── front.md ├── logo.png └── requirements.txt /00_tips.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "9bbee9ab-addf-4cb2-8d9b-ee89ddfd7b15", 6 | "metadata": {}, 7 | "source": [ 8 | "# Markdown, Latex, programming tips\n", 9 | "\n", 10 | "There are two types of blocks in a Jupyter notebook: code and markdown. Code is for entering Python code while markdown is for markdown and Latex.\n", 11 | "\n", 12 | "To execute a block, press shift+enter key.\n", 13 | "\n", 14 | "Title and sections are made by\n", 15 | "\n", 16 | "```\n", 17 | "# Main title\n", 18 | "## Section\n", 19 | "### Subsection\n", 20 | "#### Subsubsection\n", 21 | "```\n", 22 | "\n", 23 | "gives\n", 24 | "\n", 25 | "# Main title\n", 26 | "## Section\n", 27 | "### Subsection\n", 28 | "#### Subsubsection" 29 | ] 30 | }, 31 | { 32 | "cell_type": "markdown", 33 | "id": "944e52e9-a0ff-40d2-b1f0-2d3d3dfaefbd", 34 | "metadata": {}, 35 | "source": [ 36 | "Itemize\n", 37 | "\n", 38 | "```\n", 39 | "* First item\n", 40 | "* Second item\n", 41 | "* Third item\n", 42 | " * sub item\n", 43 | " * sub item\n", 44 | "```\n", 45 | "\n", 46 | "gives\n", 47 | "\n", 48 | "* First item\n", 49 | "* Second item\n", 50 | "* Third item\n", 51 | " * sub item\n", 52 | " * sub item" 53 | ] 54 | }, 55 | { 56 | "cell_type": "markdown", 57 | "id": "5955a0fd-315c-4169-aa97-d07b28ae9e64", 58 | "metadata": {}, 59 | "source": [ 60 | "Enumerate\n", 61 | "\n", 62 | "```\n", 63 | "1. First item\n", 64 | "1. Second item\n", 65 | "1. Third item\n", 66 | " 1. sub item\n", 67 | " 1. sub item\n", 68 | "```\n", 69 | "\n", 70 | "gives\n", 71 | "\n", 72 | "1. First item\n", 73 | "1. Second item\n", 74 | "1. Third item\n", 75 | " 1. sub item\n", 76 | " 1. sub item" 77 | ] 78 | }, 79 | { 80 | "cell_type": "markdown", 81 | "id": "948bc1fd-5188-491c-b70c-310ffa70e881", 82 | "metadata": {}, 83 | "source": [ 84 | "Verbatim text can be put inline like this: `Python` and as a code block like this (double click to see the code)\n", 85 | "\n", 86 | "```python\n", 87 | "x = 0\n", 88 | "while abs(f(x)) < eps:\n", 89 | " x = x - f(x)/df(x)\n", 90 | "```" 91 | ] 92 | }, 93 | { 94 | "cell_type": "markdown", 95 | "id": "7fefaf7f-80a0-4681-b56d-5513b7f45576", 96 | "metadata": {}, 97 | "source": [ 98 | "Quoted text: begin with a greater than symbol\n", 99 | "\n", 100 | "```\n", 101 | "> One reason why mathematics enjoys special esteem, above all other sciences, is that its laws are absolutely certain and indisputable, while those of all other sciences are to some extent debatable and in constant danger of being overthrown by newly discovered facts.\n", 102 | "```\n", 103 | "\n", 104 | "> One reason why mathematics enjoys special esteem, above all other sciences, is that its laws are absolutely certain and indisputable, while those of all other sciences are to some extent debatable and in constant danger of being overthrown by newly discovered facts.\n", 105 | "> \n", 106 | "> In spite of this, the investigator in another department of science would not need to envy the mathematician if the laws of mathematics referred to objects of our mere imagination, and not to objects of reality. For it cannot occasion surprise that different persons should arrive at the same logical conclusions when they have already agreed upon the fundamental laws (axioms), as well as the methods by which other laws are to be deduced therefrom. But there is another reason for the high repute of mathematics, in that it is mathematics which affords the exact natural sciences a certain measure of security, to which without mathematics they could not attain.\n", 107 | "> \n", 108 | "> At this point an enigma presents itself which in all ages has agitated inquiring minds. How can it be that mathematics, being after all a product of human thought which is independent of experience, is so admirably appropriate to the objects of reality? Is human reason, then, without experience, merely by taking thought, able to fathom the properties of real things.\n", 109 | "> \n", 110 | "> In my opinion the answer to this question is, briefly, this:- As far as the laws of mathematics refer to reality, they are not certain; and as far as they are certain, they do not refer to reality.\n", 111 | ">\n", 112 | "> (Albert Einstein, \"Geometry and Experience\", Prussian Academy of Science, Berlin, 27 January 1921)" 113 | ] 114 | }, 115 | { 116 | "cell_type": "markdown", 117 | "id": "1e17e120-76e8-4262-a204-166f00942e1b", 118 | "metadata": {}, 119 | "source": [ 120 | "## Latex \n", 121 | "Jupyter supports only a small subset of Latex." 122 | ] 123 | }, 124 | { 125 | "cell_type": "markdown", 126 | "id": "e0b7cb23-8abb-4f2c-8cb7-635f82bd01fb", 127 | "metadata": {}, 128 | "source": [ 129 | "Inline math is enclosed in dollars: `$y = f(x)$` gives $y = f(x)$" 130 | ] 131 | }, 132 | { 133 | "cell_type": "markdown", 134 | "id": "a079e24f-7c21-4faa-9806-310ddbfdbfc4", 135 | "metadata": {}, 136 | "source": [ 137 | "Equations are enclosed in double dollars\n", 138 | "\n", 139 | "```\n", 140 | "$$\n", 141 | "y = f(x)\n", 142 | "$$\n", 143 | "```\n", 144 | "\n", 145 | "$$\n", 146 | "y = f(x)\n", 147 | "$$" 148 | ] 149 | }, 150 | { 151 | "cell_type": "markdown", 152 | "id": "5df6ed4e-8dc1-457a-bfb0-860a702de216", 153 | "metadata": {}, 154 | "source": [ 155 | "Math functions: use `\\sin`, `\\cos`, etc.\n", 156 | "\n", 157 | "```\n", 158 | "$$\n", 159 | "\\sin(x), \\qquad \\cos(x), \\qquad \\log(x), \\qquad \\exp(x)\n", 160 | "$$\n", 161 | "```\n", 162 | "\n", 163 | "$$\n", 164 | "\\sin(x), \\qquad \\cos(x), \\qquad \\log(x), \\qquad \\exp(x)\n", 165 | "$$" 166 | ] 167 | }, 168 | { 169 | "cell_type": "markdown", 170 | "id": "c40e44cb-3eef-4fbe-ad32-8a6454ec6096", 171 | "metadata": {}, 172 | "source": [ 173 | "We can put space in math using `\\quad` and `\\qquad`.\n", 174 | "\n", 175 | "Greek symbols are obtained naturally by adding a forward slash\n", 176 | "\n", 177 | "```\n", 178 | "$$\n", 179 | "\\alpha, \\qquad \\beta, \\qquad \\gamma, \\qquad \\delta, \\qquad \\epsilon, \\qquad \\varepsilon\n", 180 | "$$\n", 181 | "```\n", 182 | "\n", 183 | "$$\n", 184 | "\\alpha, \\qquad \\beta, \\qquad \\gamma, \\qquad \\delta, \\qquad \\epsilon, \\qquad \\varepsilon\n", 185 | "$$" 186 | ] 187 | }, 188 | { 189 | "cell_type": "markdown", 190 | "id": "3122cdd9-c01c-4c0b-8739-e5ea75cf06f6", 191 | "metadata": {}, 192 | "source": [ 193 | "Subscripts and superscripts\n", 194 | "\n", 195 | "```\n", 196 | "$$\n", 197 | "a_m, \\qquad a_{mn}, \\qquad x^n, \\qquad y^{n+1}, \\qquad a^n_m\n", 198 | "$$\n", 199 | "```\n", 200 | "\n", 201 | "$$\n", 202 | "a_m, \\qquad a_{mn}, \\qquad x^n, \\qquad y^{n+1}, \\qquad a^n_m\n", 203 | "$$" 204 | ] 205 | }, 206 | { 207 | "cell_type": "markdown", 208 | "id": "f2c67c02-561c-41e8-9b45-4ea8df09763e", 209 | "metadata": {}, 210 | "source": [ 211 | "Fractions using `\\frac` and `\\tfrac`\n", 212 | "\n", 213 | "```\n", 214 | "$$\n", 215 | "\\frac{x}{y}, \\qquad \\tfrac{x}{y}\n", 216 | "$$\n", 217 | "```\n", 218 | "\n", 219 | "$$\n", 220 | "\\frac{x}{y}, \\qquad \\tfrac{x}{y}\n", 221 | "$$" 222 | ] 223 | }, 224 | { 225 | "cell_type": "markdown", 226 | "id": "3cdf7e9b-94ff-4556-85cf-b6fccb4bbe05", 227 | "metadata": {}, 228 | "source": [ 229 | "Automatically adjusting brackets\n", 230 | "\n", 231 | "```\n", 232 | "$$\n", 233 | "f(x) = \\left( 1 + \\frac{e^x}{1+x} \\right) \\left[ 1 - \\frac{e^x}{1-x} \\right]\n", 234 | "$$\n", 235 | "```\n", 236 | "\n", 237 | "$$\n", 238 | "f(x) = \\left( 1 + \\frac{e^x}{1+x} \\right) \\left[ 1 - \\frac{e^x}{1-x} \\right]\n", 239 | "$$" 240 | ] 241 | }, 242 | { 243 | "cell_type": "markdown", 244 | "id": "fa9313f1-8a20-4feb-997a-7c6dbf803474", 245 | "metadata": {}, 246 | "source": [ 247 | "ODE\n", 248 | "\n", 249 | "```\n", 250 | "$$\n", 251 | "\\frac{d y}{d t} = f(t,y)\n", 252 | "$$\n", 253 | "```\n", 254 | "\n", 255 | "$$\n", 256 | "\\frac{d y}{d t} = f(t,y)\n", 257 | "$$" 258 | ] 259 | }, 260 | { 261 | "cell_type": "markdown", 262 | "id": "66923694-7603-4b1b-96de-56e36f03fa34", 263 | "metadata": {}, 264 | "source": [ 265 | "PDE\n", 266 | "\n", 267 | "```\n", 268 | "$$\n", 269 | "\\frac{\\partial u}{\\partial t} + \\frac{\\partial f}{\\partial x} = 0\n", 270 | "$$\n", 271 | "```\n", 272 | "\n", 273 | "$$\n", 274 | "\\frac{\\partial u}{\\partial t} + \\frac{\\partial f}{\\partial x} = 0\n", 275 | "$$" 276 | ] 277 | }, 278 | { 279 | "cell_type": "markdown", 280 | "id": "e59d109c-e062-4b49-86d5-ce0a721f087f", 281 | "metadata": {}, 282 | "source": [ 283 | "To reduce typing, we will define some aliases\n", 284 | "\n", 285 | "```\n", 286 | "$$\n", 287 | "\\newcommand{\\re}{\\mathbb{R}}\n", 288 | "\\newcommand{\\mathd}{\\textrm{d}}\n", 289 | "\\newcommand{\\od}[2]{\\frac{\\mathd #1}{\\mathd #2}}\n", 290 | "\\newcommand{\\pd}[2]{\\frac{\\partial #1}{\\partial #2}}\n", 291 | "$$\n", 292 | "```\n", 293 | "\n", 294 | "$$\n", 295 | "\\newcommand{\\re}{\\mathbb{R}}\n", 296 | "\\newcommand{\\mathd}{\\textrm{d}}\n", 297 | "\\newcommand{\\od}[2]{\\frac{\\mathd #1}{\\mathd #2}}\n", 298 | "\\newcommand{\\pd}[2]{\\frac{\\partial #1}{\\partial #2}}\n", 299 | "$$\n", 300 | "\n", 301 | "We write the ODE and PDE again\n", 302 | "\n", 303 | "```\n", 304 | "$$\n", 305 | "\\od{y}{t} = f(t,y), \\qquad \\pd{u}{t} + \\pd{f}{x} = 0\n", 306 | "$$\n", 307 | "```\n", 308 | "\n", 309 | "$$\n", 310 | "\\od{y}{t} = f(t,y), \\qquad \\pd{u}{t} + \\pd{f}{x} = 0\n", 311 | "$$" 312 | ] 313 | }, 314 | { 315 | "cell_type": "markdown", 316 | "id": "36c0a395-d864-41d0-98da-e9562d6df399", 317 | "metadata": {}, 318 | "source": [ 319 | "Heaviside function\n", 320 | "\n", 321 | "```\n", 322 | "$$\n", 323 | "H(x) = \\begin{cases}\n", 324 | "0, & x < 0 \\\\\n", 325 | "1, & x > 1\n", 326 | "\\end{cases}\n", 327 | "$$\n", 328 | "```\n", 329 | "\n", 330 | "$$\n", 331 | "H(x) = \\begin{cases}\n", 332 | "0, & x < 0 \\\\\n", 333 | "1, & x > 0\n", 334 | "\\end{cases}\n", 335 | "$$" 336 | ] 337 | }, 338 | { 339 | "cell_type": "markdown", 340 | "id": "75feecc1-585c-412d-b054-28c64de08f23", 341 | "metadata": {}, 342 | "source": [ 343 | "Multi-line equation: `\\eqnarray`\n", 344 | "\n", 345 | "```\n", 346 | "\\begin{eqnarray}\n", 347 | "y &=& (\\sin(x) + \\cos(x))^2 \\\\\n", 348 | " &=& \\sin^2(x) + \\cos^2(x) + 2 \\sin(x) \\cos(x) \\\\\n", 349 | " &=& 1 + \\sin(2x)\n", 350 | "\\end{eqnarray}\n", 351 | "```\n", 352 | "\n", 353 | "\\begin{eqnarray}\n", 354 | "y &=& (\\sin(x) + \\cos(x))^2 \\\\\n", 355 | " &=& \\sin^2(x) + \\cos^2(x) + 2 \\sin(x) \\cos(x) \\\\\n", 356 | " &=& 1 + \\sin(2x)\n", 357 | "\\end{eqnarray}" 358 | ] 359 | }, 360 | { 361 | "cell_type": "markdown", 362 | "id": "3b736103-e0c4-4f4c-a1b7-a7b1c646a600", 363 | "metadata": {}, 364 | "source": [ 365 | "Multi-line equation: `\\align`\n", 366 | "\n", 367 | "```\n", 368 | "\\begin{align}\n", 369 | "y &= (\\sin(x) + \\cos(x))^2 \\\\\n", 370 | " &= \\sin^2(x) + \\cos^2(x) + 2 \\sin(x) \\cos(x) \\\\\n", 371 | " &= 1 + \\sin(2x)\n", 372 | "\\end{align}\n", 373 | "```\n", 374 | "\n", 375 | "\\begin{align}\n", 376 | "y &= (\\sin(x) + \\cos(x))^2 \\\\\n", 377 | " &= \\sin^2(x) + \\cos^2(x) + 2 \\sin(x) \\cos(x) \\\\\n", 378 | " &= 1 + \\sin(2x)\n", 379 | "\\end{align}\n", 380 | "\n", 381 | "which allows multiple alignments\n", 382 | "\n", 383 | "```\n", 384 | "\\begin{align}\n", 385 | "y &= (\\sin(x) + \\cos(x))^2 & \\\\\n", 386 | " &= \\sin^2(x) + \\cos^2(x) + 2 \\sin(x) \\cos(x) & \\\\\n", 387 | " &= 1 + \\sin(2x), & \\textrm{since } \\sin^2(x) + \\cos^2(x) = 1\n", 388 | "\\end{align}\n", 389 | "```\n", 390 | "\n", 391 | "\\begin{align}\n", 392 | "y &= (\\sin(x) + \\cos(x))^2 & \\\\\n", 393 | " &= \\sin^2(x) + \\cos^2(x) + 2 \\sin(x) \\cos(x) & \\\\\n", 394 | " &= 1 + \\sin(2x), & \\textrm{since } \\sin^2(x) + \\cos^2(x) = 1\n", 395 | "\\end{align}" 396 | ] 397 | }, 398 | { 399 | "cell_type": "markdown", 400 | "id": "3730f88b-0b28-4269-8de3-5a76666ef93d", 401 | "metadata": {}, 402 | "source": [ 403 | "Use `\\gather` to stack many equations without alignment\n", 404 | "\n", 405 | "```\n", 406 | "\\begin{gather}\n", 407 | "y = x_1 + x_2 + x_3 + x_4 \\\\\n", 408 | "z = x_1 + x_2\n", 409 | "\\end{gather}\n", 410 | "```\n", 411 | "\n", 412 | "\\begin{gather}\n", 413 | "y = x_1 + x_2 + x_3 + x_4 \\\\\n", 414 | "z = x_1 + x_2\n", 415 | "\\end{gather}" 416 | ] 417 | }, 418 | { 419 | "cell_type": "markdown", 420 | "id": "6c358b92-289a-4d3c-a0bf-e98ce96c0d6b", 421 | "metadata": {}, 422 | "source": [ 423 | "Use `\\underbrace` to add extra information\n", 424 | "\n", 425 | "```\n", 426 | "\\begin{align}\n", 427 | "y &= (\\sin(x) + \\cos(x))^2 \\\\\n", 428 | " &= \\underbrace{\\sin^2(x) + \\cos^2(x)}_{=1} + 2 \\sin(x) \\cos(x) \\\\\n", 429 | " &= 1 + \\sin(2x)\n", 430 | "\\end{align}\n", 431 | "```\n", 432 | "\n", 433 | "\\begin{align}\n", 434 | "y &= (\\sin(x) + \\cos(x))^2 \\\\\n", 435 | " &= \\underbrace{\\sin^2(x) + \\cos^2(x)}_{=1} + 2 \\sin(x) \\cos(x) \\\\\n", 436 | " &= 1 + \\sin(2x)\n", 437 | "\\end{align}" 438 | ] 439 | }, 440 | { 441 | "cell_type": "markdown", 442 | "id": "4864648b-968f-40f0-aea8-357273df36c1", 443 | "metadata": {}, 444 | "source": [ 445 | "Equation numbering is not well supported in markdown, but we can put numbers by hard-coding them\n", 446 | "\n", 447 | "```\n", 448 | "$$\n", 449 | "u_t + u \\cdot \\nabla u + \\nabla p = \\epsilon \\Delta u \\tag{1}\n", 450 | "$$\n", 451 | "```\n", 452 | "\n", 453 | "$$\n", 454 | "u_t + u \\cdot \\nabla u + \\nabla p = \\epsilon \\Delta u \\tag{1}\n", 455 | "$$" 456 | ] 457 | }, 458 | { 459 | "cell_type": "markdown", 460 | "id": "a0a166b6-24bb-461b-a92b-bab6db6a167b", 461 | "metadata": {}, 462 | "source": [ 463 | "Linear Algebra: \n", 464 | "\n", 465 | "```\n", 466 | "> Given $b \\in R^m$ and $A \\in R^{m \\times m}$, find $x \\in R^m$ such that\n", 467 | "> \n", 468 | "> $$\n", 469 | " A x = b\n", 470 | " $$\n", 471 | "```\n", 472 | "\n", 473 | "> Given $b \\in R^m$ and $A \\in R^{m \\times m}$, find $x \\in R^m$ such that\n", 474 | "> \n", 475 | "> $$\n", 476 | " A x = b\n", 477 | " $$" 478 | ] 479 | }, 480 | { 481 | "cell_type": "markdown", 482 | "id": "a8b9d71a-0f60-4468-99b7-936fac0f9e50", 483 | "metadata": {}, 484 | "source": [ 485 | "The set of reals and complex are usually denoted as: $\\mathbb{R}$ and $\\mathbb{C}$. So if we are very strict, we should write: \n", 486 | "\n", 487 | "```\n", 488 | "> Given $b \\in \\mathbb{R}^m$ and $A \\in \\mathbb{R}^{m \\times m}$, find $x \\in \\mathbb{R}^m$ such that\n", 489 | "> \n", 490 | "> $$\n", 491 | " A x = b\n", 492 | " $$\n", 493 | "```\n", 494 | "\n", 495 | "> Given $b \\in \\mathbb{R}^m$ and $A \\in \\mathbb{R}^{m \\times m}$, find $x \\in \\mathbb{R}^m$ such that\n", 496 | "> \n", 497 | "> $$\n", 498 | " A x = b\n", 499 | " $$" 500 | ] 501 | }, 502 | { 503 | "cell_type": "markdown", 504 | "id": "0fa5dfd6-85aa-4ef7-bc96-a3800c389729", 505 | "metadata": {}, 506 | "source": [ 507 | "Matrix\n", 508 | "\n", 509 | "```\n", 510 | "$$\n", 511 | "A = \\begin{bmatrix}\n", 512 | "a_{11} & a_{12} & a_{13} \\\\\n", 513 | "a_{21} & a_{22} & a_{23} \\\\\n", 514 | "a_{31} & a_{32} & a_{33}\n", 515 | "\\end{bmatrix}\n", 516 | "$$\n", 517 | "```\n", 518 | "\n", 519 | "$$\n", 520 | "A = \\begin{bmatrix}\n", 521 | "a_{11} & a_{12} & a_{13} \\\\\n", 522 | "a_{21} & a_{22} & a_{23} \\\\\n", 523 | "a_{31} & a_{32} & a_{33}\n", 524 | "\\end{bmatrix}\n", 525 | "$$" 526 | ] 527 | }, 528 | { 529 | "cell_type": "markdown", 530 | "id": "cd33aaa6-0dca-45a9-950f-d60e13e0aa5c", 531 | "metadata": {}, 532 | "source": [ 533 | "Condition number of matrix $A \\in \\re^{m \\times m}$ with respect to some norm\n", 534 | "\n", 535 | "```\n", 536 | "$$\n", 537 | "\\kappa = \\| A \\| \\| A^{-1} \\|\n", 538 | "$$\n", 539 | "```\n", 540 | "\n", 541 | "$$\n", 542 | "\\kappa = \\| A \\| \\| A^{-1} \\|\n", 543 | "$$" 544 | ] 545 | }, 546 | { 547 | "cell_type": "markdown", 548 | "id": "a50968bd", 549 | "metadata": {}, 550 | "source": [ 551 | "## Tips for programming\n", 552 | "\n", 553 | "1. Always\n", 554 | " 1. Think about your problem first, write it down mathematically in terms of equations.\n", 555 | " 1. Write down the algorithm on paper.\n", 556 | " 1. Now start implementing it in code.\n", 557 | "\n", 558 | "1. Possibly break the code down into some functions, so that you avoid repeating the same code in multiple places.\n", 559 | "\n", 560 | "1. Put checks for array sizes, etc.\n", 561 | "\n", 562 | "1. Be careful while dividing (denominator should not be zero), taking square roots (should be non-negative), etc.\n", 563 | "\n", 564 | "1. Test the code on some inputs to see it is working correctly. Also test individual functions that they are correct.\n", 565 | "\n", 566 | "1. If code crashes with some error, read the error message and fix the mistake. Cut and paste the error in a search engine to find solution.\n", 567 | "\n", 568 | "1. Do not hard code values, define some variables and use them. This way, if you change the value, you only need to change it in one place.\n", 569 | "\n", 570 | "1. Write comments in code to explain what you are doing.\n", 571 | " \n", 572 | "1. Indent code for better readability. This is essential for Python and the notebook editor automatically does this.\n", 573 | "\n", 574 | "1. Put spaces in formulae for better readability.\n", 575 | " ```\n", 576 | " f = x+y+z*sin(a)*cos(b)\n", 577 | " f = x + y + z * sin(a) * cos(b) <== Better\n", 578 | " ```\n", 579 | " \n", 580 | "1. Use brackets in formulae where needed. E.g., $f = \\frac{a}{b c}$\n", 581 | "\n", 582 | " $$\n", 583 | " \\textrm{f = a / b * c} \\qquad \\textrm{wrong, this gives} \\qquad f = \\left(\\frac{a}{b}\\right) c\n", 584 | " $$\n", 585 | "\n", 586 | " correct code is\n", 587 | "\n", 588 | " $$\n", 589 | " \\textrm{f = a / (b * c)}\n", 590 | " $$\n", 591 | "\n", 592 | " Another example\n", 593 | "\n", 594 | " $$\n", 595 | " \\textrm{f = x + y + z * sin(a) * cos(b)} \\qquad \\textrm{gives} \\qquad f = x + y + (z \\sin(a) \\cos(b)) \n", 596 | " $$\n", 597 | "\n", 598 | " $$\n", 599 | " \\textrm{f = (x + y + z) * sin(a) * cos(b)} \\qquad \\textrm{gives} \\qquad f = (x + y + z) \\sin(a) \\cos(b)\n", 600 | " $$\n", 601 | "\n", 602 | "1. Put a decimal when assigning float values; note that Python infers type based on the value you assign.\n", 603 | "\n", 604 | "1. Avoid writing long lines; continue long lines to new line or break into multiple statements of smaller size.\n", 605 | "\n", 606 | "1. Print some values to see computations are correct, and to monitor progress of code.\n", 607 | "\n", 608 | "1. In figures, \n", 609 | " 1. put axes labels, legend if there is more than one graph, title if needed. \n", 610 | " 1. Draw grid lines for better readability, `plt.grid(True)`.\n", 611 | " 1. Use different line style or symbols style to distinguish multiple graphs in same figure.\n", 612 | " 1. Choose appropriate axis scale; linear scale is not always optimal." 613 | ] 614 | } 615 | ], 616 | "metadata": { 617 | "kernelspec": { 618 | "display_name": "Python 3 (ipykernel)", 619 | "language": "python", 620 | "name": "python3" 621 | }, 622 | "language_info": { 623 | "codemirror_mode": { 624 | "name": "ipython", 625 | "version": 3 626 | }, 627 | "file_extension": ".py", 628 | "mimetype": "text/x-python", 629 | "name": "python", 630 | "nbconvert_exporter": "python", 631 | "pygments_lexer": "ipython3", 632 | "version": "3.12.8" 633 | } 634 | }, 635 | "nbformat": 4, 636 | "nbformat_minor": 5 637 | } 638 | -------------------------------------------------------------------------------- /01_intro.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Introduction" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "$\\newcommand{\\re}{\\mathbb{R}}$\n", 15 | "Python comes in two versions, 2 and 3. Version 2 is still available on some old computers but it is deprecated and should not be used. Hence we will use version 3 throughout these lectures. To see if Python is already installed\n", 16 | "\n", 17 | "```shell\n", 18 | "which python\n", 19 | "```\n", 20 | "\n", 21 | "You can check the version like this on the terminal\n", 22 | "\n", 23 | "```shell\n", 24 | "$ python --version\n", 25 | "```\n", 26 | "\n", 27 | "On some systems, you may have to use `python3` to get version 3 python.\n", 28 | "\n", 29 | "Usually Python is available on Linux/Unix computers, though it may not provide all the required libraries. You can install them using your system package manager (apt on Debian/Ubuntu) or by installing a full Python distribution like [Miniforge](https://github.com/conda-forge/miniforge). It is highly recommended to use Conda to install Python, rather than using your system package manager. If you use Conda, then make sure to set your `PATH` variable so that it finds Anaconda python rather than your system python.\n", 30 | "\n", 31 | "```shell\n", 32 | "export PATH=/path/to/miniforge/bin:$PATH\n", 33 | "```\n", 34 | "\n", 35 | "Then test that the correct python is in your `PATH`\n", 36 | "\n", 37 | "```shell\n", 38 | "$ which python\n", 39 | "```\n", 40 | "\n", 41 | "Python is organized into modules and some of the useful Python modules we will use in this tutorial are\n", 42 | "\n", 43 | " * **numpy**: provides arrays, linear algebra, random numbers, etc.\n", 44 | " * **scipy**: integration, optimization, linear algebra\n", 45 | " * **matplotlib**: for making graphs\n", 46 | " * **sympy**: symbolic math\n", 47 | "\n", 48 | "There are several ways to use Python.\n", 49 | " * python: type this in terminal, very basic, does not have interactivity or help\n", 50 | " \n", 51 | "```shell\n", 52 | "$ python\n", 53 | "Python 3.10.8 | packaged by conda-forge | (main, Nov 22 2022, 08:25:13) [Clang 14.0.6 ] on darwin\n", 54 | "Type \"help\", \"copyright\", \"credits\" or \"license\" for more information.\n", 55 | ">>>\n", 56 | "```\n", 57 | "\n", 58 | " * ipython: better python terminal\n", 59 | " \n", 60 | "```shell\n", 61 | "Python 3.10.8 | packaged by conda-forge | (main, Nov 22 2022, 08:25:13) [Clang 14.0.6 ]\n", 62 | "Type 'copyright', 'credits' or 'license' for more information\n", 63 | "IPython 8.7.0 -- An enhanced Interactive Python. Type '?' for help.\n", 64 | "\n", 65 | "In [1]:\n", 66 | "```\n", 67 | "\n", 68 | " * pylab: imports some modules like numpy; define an alias\n", 69 | " \n", 70 | "```shell\n", 71 | "alias pylab=\"ipython --pylab --matplotlib --nosep --pprint\"\n", 72 | "```\n", 73 | "\n", 74 | " * jupyter notebook: This is what you are reading now. On some computers you can start a notebook using\n", 75 | " \n", 76 | "```shell\n", 77 | "$ ipython-notebook (conda install notebook)\n", 78 | "$ jupyter-lab (conda install jupyterlab)\n", 79 | "```\n", 80 | "\n", 81 | "I prefer using jupyterlab since it seems more modern." 82 | ] 83 | }, 84 | { 85 | "cell_type": "markdown", 86 | "metadata": {}, 87 | "source": [ 88 | "## Basic math" 89 | ] 90 | }, 91 | { 92 | "cell_type": "markdown", 93 | "metadata": {}, 94 | "source": [ 95 | "The basic number types we commonly use are integers, reals and complex numbers. In Python, we can directly use variables without declaring their type. This is in contrast to most other programming languages like Fortran/C/C++ where the type of variable has to be declared before using it." 96 | ] 97 | }, 98 | { 99 | "cell_type": "code", 100 | "execution_count": 6, 101 | "metadata": {}, 102 | "outputs": [ 103 | { 104 | "name": "stdout", 105 | "output_type": "stream", 106 | "text": [ 107 | "3\n" 108 | ] 109 | } 110 | ], 111 | "source": [ 112 | "x = 1\n", 113 | "y = 2\n", 114 | "z = x + y\n", 115 | "print(z)" 116 | ] 117 | }, 118 | { 119 | "cell_type": "markdown", 120 | "metadata": {}, 121 | "source": [ 122 | "The type of the variable is automatically determined by what we assign to it." 123 | ] 124 | }, 125 | { 126 | "cell_type": "code", 127 | "execution_count": 7, 128 | "metadata": {}, 129 | "outputs": [ 130 | { 131 | "name": "stdout", 132 | "output_type": "stream", 133 | "text": [ 134 | " \n" 135 | ] 136 | } 137 | ], 138 | "source": [ 139 | "print(type(x),type(y),type(z))" 140 | ] 141 | }, 142 | { 143 | "cell_type": "code", 144 | "execution_count": 8, 145 | "metadata": {}, 146 | "outputs": [ 147 | { 148 | "name": "stdout", 149 | "output_type": "stream", 150 | "text": [ 151 | "3.0\n", 152 | "\n" 153 | ] 154 | } 155 | ], 156 | "source": [ 157 | "x = 1.0\n", 158 | "y = 2.0\n", 159 | "z = x + y\n", 160 | "print(z)\n", 161 | "print(type(z))" 162 | ] 163 | }, 164 | { 165 | "cell_type": "markdown", 166 | "metadata": {}, 167 | "source": [ 168 | "The float type corresponds to double precision in C/C++ and has about 16 decimal places of accuracy. It is good programming practice to assign numerical values based on their intended type. If you want `x` to be a float then assign its value as `x = 1.0` and not as `x = 1`.\n", 169 | "\n", 170 | "Python will automatically determine the type when you have mixed types in some expression." 171 | ] 172 | }, 173 | { 174 | "cell_type": "code", 175 | "execution_count": 9, 176 | "metadata": {}, 177 | "outputs": [ 178 | { 179 | "name": "stdout", 180 | "output_type": "stream", 181 | "text": [ 182 | "3.345\n", 183 | " \n" 184 | ] 185 | } 186 | ], 187 | "source": [ 188 | "a = 1\n", 189 | "b = 2.345\n", 190 | "c = a + b\n", 191 | "print(c)\n", 192 | "print(type(a),type(b),type(c))" 193 | ] 194 | }, 195 | { 196 | "cell_type": "markdown", 197 | "metadata": {}, 198 | "source": [ 199 | "> Implicit typing reduces code clutter, but there is potential for making mistakes, so be careful to set correct values to reflect the intended type.\n", 200 | "\n", 201 | "Variable names are case sensitive; below `a` and `A` are different variables." 202 | ] 203 | }, 204 | { 205 | "cell_type": "code", 206 | "execution_count": 10, 207 | "metadata": {}, 208 | "outputs": [ 209 | { 210 | "name": "stdout", 211 | "output_type": "stream", 212 | "text": [ 213 | "a = 1 , A = 2\n" 214 | ] 215 | } 216 | ], 217 | "source": [ 218 | "a = 1\n", 219 | "A = 2\n", 220 | "print('a = ',a,', A = ',A)" 221 | ] 222 | }, 223 | { 224 | "cell_type": "markdown", 225 | "metadata": {}, 226 | "source": [ 227 | "\n", 228 | "**Division** is performed using backslash symbol" 229 | ] 230 | }, 231 | { 232 | "cell_type": "code", 233 | "execution_count": 11, 234 | "metadata": {}, 235 | "outputs": [ 236 | { 237 | "name": "stdout", 238 | "output_type": "stream", 239 | "text": [ 240 | "0.3333333333333333\n" 241 | ] 242 | } 243 | ], 244 | "source": [ 245 | "x = 1.0\n", 246 | "y = 3.0\n", 247 | "z = x/y\n", 248 | "print(z)" 249 | ] 250 | }, 251 | { 252 | "cell_type": "markdown", 253 | "metadata": {}, 254 | "source": [ 255 | "Division of integers still returns a float (This behaviour was different in Version 2 and earlier)." 256 | ] 257 | }, 258 | { 259 | "cell_type": "code", 260 | "execution_count": 12, 261 | "metadata": {}, 262 | "outputs": [ 263 | { 264 | "name": "stdout", 265 | "output_type": "stream", 266 | "text": [ 267 | "0.5\n" 268 | ] 269 | } 270 | ], 271 | "source": [ 272 | "print(1/2)" 273 | ] 274 | }, 275 | { 276 | "cell_type": "markdown", 277 | "metadata": {}, 278 | "source": [ 279 | "Integer division can be performed with double backslash operator" 280 | ] 281 | }, 282 | { 283 | "cell_type": "code", 284 | "execution_count": 13, 285 | "metadata": {}, 286 | "outputs": [ 287 | { 288 | "name": "stdout", 289 | "output_type": "stream", 290 | "text": [ 291 | "1/2, 1//2 = 0.5 0\n", 292 | "1/3, 1//3 = 0.3333333333333333 0\n", 293 | "2/3, 2//3 = 0.6666666666666666 0\n", 294 | "3/2, 3//2 = 1.5 1\n", 295 | "5/3, 5//3 = 1.6666666666666667 1\n" 296 | ] 297 | } 298 | ], 299 | "source": [ 300 | "print('1/2, 1//2 =', 1/2, 1//2)\n", 301 | "print('1/3, 1//3 =', 1/3, 1//3)\n", 302 | "print('2/3, 2//3 =', 2/3, 2//3)\n", 303 | "print('3/2, 3//2 =', 3/2, 3//2)\n", 304 | "print('5/3, 5//3 =', 5/3, 5//3)" 305 | ] 306 | }, 307 | { 308 | "cell_type": "markdown", 309 | "metadata": {}, 310 | "source": [ 311 | "The result is rounded down to the integer value." 312 | ] 313 | }, 314 | { 315 | "cell_type": "markdown", 316 | "metadata": {}, 317 | "source": [ 318 | "**Raising to some power**\n", 319 | "\n", 320 | "$$\n", 321 | "c = a^b\n", 322 | "$$\n", 323 | "\n", 324 | "is done like this" 325 | ] 326 | }, 327 | { 328 | "cell_type": "code", 329 | "execution_count": 14, 330 | "metadata": {}, 331 | "outputs": [ 332 | { 333 | "name": "stdout", 334 | "output_type": "stream", 335 | "text": [ 336 | "9\n" 337 | ] 338 | } 339 | ], 340 | "source": [ 341 | "a, b = 3, 2\n", 342 | "c = a**b\n", 343 | "print(c)" 344 | ] 345 | }, 346 | { 347 | "cell_type": "markdown", 348 | "metadata": {}, 349 | "source": [ 350 | "If the power $n$ in\n", 351 | "\n", 352 | "$$\n", 353 | "y = x^n\n", 354 | "$$\n", 355 | "\n", 356 | "is an integer, declare $n$ as integer 2 which will be faster than if you declare it as 2.0." 357 | ] 358 | }, 359 | { 360 | "cell_type": "code", 361 | "execution_count": 15, 362 | "metadata": {}, 363 | "outputs": [ 364 | { 365 | "name": "stdout", 366 | "output_type": "stream", 367 | "text": [ 368 | "1.234 2 1.522756\n" 369 | ] 370 | } 371 | ], 372 | "source": [ 373 | "x, n = 1.234, 2\n", 374 | "y = x**n\n", 375 | "print(x,n,y)" 376 | ] 377 | }, 378 | { 379 | "cell_type": "markdown", 380 | "metadata": {}, 381 | "source": [ 382 | "## Formatted print\n", 383 | "We can use C-style formatting" 384 | ] 385 | }, 386 | { 387 | "cell_type": "code", 388 | "execution_count": 16, 389 | "metadata": {}, 390 | "outputs": [ 391 | { 392 | "name": "stdout", 393 | "output_type": "stream", 394 | "text": [ 395 | "i, x = 10 1.234568 1.234568e+00\n" 396 | ] 397 | } 398 | ], 399 | "source": [ 400 | "i = 10\n", 401 | "x = 1.23456789\n", 402 | "print('i, x = %5d %12.6f %14.6e' % (i,x,x))" 403 | ] 404 | }, 405 | { 406 | "cell_type": "markdown", 407 | "metadata": {}, 408 | "source": [ 409 | "Since we used 6 decimal places, the floating point numbers are rounded. The exponential form is preferred if we have very small or very large numbers." 410 | ] 411 | }, 412 | { 413 | "cell_type": "code", 414 | "execution_count": 17, 415 | "metadata": {}, 416 | "outputs": [ 417 | { 418 | "name": "stdout", 419 | "output_type": "stream", 420 | "text": [ 421 | " 0.000000 1.234560e-08\n" 422 | ] 423 | } 424 | ], 425 | "source": [ 426 | "x = 0.0000000123456\n", 427 | "print('%16.6f %16.6e' % (x,x))" 428 | ] 429 | }, 430 | { 431 | "cell_type": "markdown", 432 | "metadata": {}, 433 | "source": [ 434 | "## Math functions" 435 | ] 436 | }, 437 | { 438 | "cell_type": "markdown", 439 | "metadata": {}, 440 | "source": [ 441 | "The basic Python language does not have mathematical functions like sin, cos, etc. These are implemented in additional **modules**. The `math` module provides many of these standard functions. We have to first import the module like this" 442 | ] 443 | }, 444 | { 445 | "cell_type": "code", 446 | "execution_count": 18, 447 | "metadata": {}, 448 | "outputs": [], 449 | "source": [ 450 | "import math" 451 | ] 452 | }, 453 | { 454 | "cell_type": "markdown", 455 | "metadata": {}, 456 | "source": [ 457 | "Now we can use the functions available in this module." 458 | ] 459 | }, 460 | { 461 | "cell_type": "code", 462 | "execution_count": 19, 463 | "metadata": {}, 464 | "outputs": [ 465 | { 466 | "name": "stdout", 467 | "output_type": "stream", 468 | "text": [ 469 | "-0.5440211108893698\n" 470 | ] 471 | } 472 | ], 473 | "source": [ 474 | "x = 10.0\n", 475 | "z = math.sin(x)\n", 476 | "print(z)" 477 | ] 478 | }, 479 | { 480 | "cell_type": "markdown", 481 | "metadata": {}, 482 | "source": [ 483 | "Value of $\\pi$" 484 | ] 485 | }, 486 | { 487 | "cell_type": "code", 488 | "execution_count": 20, 489 | "metadata": {}, 490 | "outputs": [ 491 | { 492 | "name": "stdout", 493 | "output_type": "stream", 494 | "text": [ 495 | "3.141592653589793\n" 496 | ] 497 | } 498 | ], 499 | "source": [ 500 | "print(math.pi)" 501 | ] 502 | }, 503 | { 504 | "cell_type": "markdown", 505 | "metadata": {}, 506 | "source": [ 507 | "## On import" 508 | ] 509 | }, 510 | { 511 | "cell_type": "markdown", 512 | "metadata": {}, 513 | "source": [ 514 | "We can also import everything into the current workspace and then we can use it without prepending ```math```\n", 515 | "\n", 516 | "```python\n", 517 | ">> from math import *\n", 518 | ">> x = sin(1.5*pi)\n", 519 | "```\n", 520 | "\n", 521 | "but this is not recommended usage since there may exist functions with same name in different modules. We can also import only what we need, e.g.,\n", 522 | "\n", 523 | "```python\n", 524 | "from math import sin,cos,pi\n", 525 | "```" 526 | ] 527 | }, 528 | { 529 | "cell_type": "markdown", 530 | "metadata": {}, 531 | "source": [ 532 | "## Strings\n", 533 | "\n", 534 | "Strings can be created by enclosing characters between **single quote** or **double quotes**." 535 | ] 536 | }, 537 | { 538 | "cell_type": "code", 539 | "execution_count": 21, 540 | "metadata": {}, 541 | "outputs": [ 542 | { 543 | "name": "stdout", 544 | "output_type": "stream", 545 | "text": [ 546 | "Hello, World!\n" 547 | ] 548 | } 549 | ], 550 | "source": [ 551 | "a, b, c, d = 'Hello', ',', ' ', 'World!'\n", 552 | "print(a+b+c+d)" 553 | ] 554 | }, 555 | { 556 | "cell_type": "markdown", 557 | "metadata": {}, 558 | "source": [ 559 | "Addition operator on strings concatenates them.\n", 560 | "\n", 561 | "If we want to create a string of the form `sol_100.txt`" 562 | ] 563 | }, 564 | { 565 | "cell_type": "code", 566 | "execution_count": 22, 567 | "metadata": {}, 568 | "outputs": [ 569 | { 570 | "name": "stdout", 571 | "output_type": "stream", 572 | "text": [ 573 | "sol_100.txt\n" 574 | ] 575 | } 576 | ], 577 | "source": [ 578 | "base = 'sol_'\n", 579 | "it = 100\n", 580 | "ext = '.txt'\n", 581 | "filename = base + str(it) + ext\n", 582 | "print(filename)" 583 | ] 584 | }, 585 | { 586 | "cell_type": "markdown", 587 | "metadata": {}, 588 | "source": [ 589 | "## Lists" 590 | ] 591 | }, 592 | { 593 | "cell_type": "markdown", 594 | "metadata": {}, 595 | "source": [ 596 | "Lists allow us to store a collection of objects. Here is a list of integers" 597 | ] 598 | }, 599 | { 600 | "cell_type": "code", 601 | "execution_count": 23, 602 | "metadata": {}, 603 | "outputs": [ 604 | { 605 | "name": "stdout", 606 | "output_type": "stream", 607 | "text": [ 608 | "[1, 2, 3, 4, 5]\n" 609 | ] 610 | } 611 | ], 612 | "source": [ 613 | "a = [1, 2, 3, 4, 5]\n", 614 | "print(a)" 615 | ] 616 | }, 617 | { 618 | "cell_type": "markdown", 619 | "metadata": {}, 620 | "source": [ 621 | "But lists can be made up of different types of elements." 622 | ] 623 | }, 624 | { 625 | "cell_type": "code", 626 | "execution_count": 24, 627 | "metadata": {}, 628 | "outputs": [ 629 | { 630 | "name": "stdout", 631 | "output_type": "stream", 632 | "text": [ 633 | "[1, 2.0, 3.0, 4, 'x']\n" 634 | ] 635 | } 636 | ], 637 | "source": [ 638 | "b = [1, 2.0, 3.0, 4, 'x']\n", 639 | "print(b)" 640 | ] 641 | }, 642 | { 643 | "cell_type": "markdown", 644 | "metadata": {}, 645 | "source": [ 646 | "Lists look like vectors but they do not obey rules of algebra." 647 | ] 648 | }, 649 | { 650 | "cell_type": "code", 651 | "execution_count": 25, 652 | "metadata": {}, 653 | "outputs": [ 654 | { 655 | "name": "stdout", 656 | "output_type": "stream", 657 | "text": [ 658 | "[1, 2, 3, 5, 6, 1]\n" 659 | ] 660 | } 661 | ], 662 | "source": [ 663 | "x = [1, 2, 3]\n", 664 | "y = [5, 6, 1]\n", 665 | "print(x + y)" 666 | ] 667 | }, 668 | { 669 | "cell_type": "markdown", 670 | "metadata": {}, 671 | "source": [ 672 | "Note that ```x``` and ```y``` have been concatenated. So a list behaves more like a set, but they are not sets since elements in a list can be repeated. To get the behaviour of vector addition, use Numpy arrays which we discuss later.\n", 673 | "\n", 674 | "We can access an element of a list using its **index**" 675 | ] 676 | }, 677 | { 678 | "cell_type": "code", 679 | "execution_count": 26, 680 | "metadata": {}, 681 | "outputs": [ 682 | { 683 | "name": "stdout", 684 | "output_type": "stream", 685 | "text": [ 686 | "x = [1, 2, 3]\n", 687 | "x[0] = 1\n", 688 | "x[1] = 2\n", 689 | "x[2] = 3\n" 690 | ] 691 | } 692 | ], 693 | "source": [ 694 | "print('x =',x)\n", 695 | "print('x[0] =',x[0])\n", 696 | "print('x[1] =',x[1])\n", 697 | "print('x[2] =',x[2])" 698 | ] 699 | }, 700 | { 701 | "cell_type": "markdown", 702 | "metadata": {}, 703 | "source": [ 704 | "> Indices in Python start from 0.\n", 705 | "\n", 706 | "You can get the length of a list using ```len```." 707 | ] 708 | }, 709 | { 710 | "cell_type": "code", 711 | "execution_count": 27, 712 | "metadata": {}, 713 | "outputs": [ 714 | { 715 | "name": "stdout", 716 | "output_type": "stream", 717 | "text": [ 718 | "[1, 2, 3]\n", 719 | "3\n" 720 | ] 721 | } 722 | ], 723 | "source": [ 724 | "print(x)\n", 725 | "print(len(x))" 726 | ] 727 | }, 728 | { 729 | "cell_type": "markdown", 730 | "metadata": {}, 731 | "source": [ 732 | "We can modify the elements of a list" 733 | ] 734 | }, 735 | { 736 | "cell_type": "code", 737 | "execution_count": 28, 738 | "metadata": {}, 739 | "outputs": [ 740 | { 741 | "name": "stdout", 742 | "output_type": "stream", 743 | "text": [ 744 | "[1, 0, 3]\n" 745 | ] 746 | } 747 | ], 748 | "source": [ 749 | "x[1] = 0\n", 750 | "print(x)" 751 | ] 752 | }, 753 | { 754 | "cell_type": "markdown", 755 | "metadata": {}, 756 | "source": [ 757 | "We can incrementally build a list" 758 | ] 759 | }, 760 | { 761 | "cell_type": "code", 762 | "execution_count": 29, 763 | "metadata": {}, 764 | "outputs": [ 765 | { 766 | "name": "stdout", 767 | "output_type": "stream", 768 | "text": [ 769 | "[1, 2, 3]\n" 770 | ] 771 | } 772 | ], 773 | "source": [ 774 | "a = [] # empty list\n", 775 | "a.append(1)\n", 776 | "a.append(2)\n", 777 | "a.append(3)\n", 778 | "print(a)" 779 | ] 780 | }, 781 | { 782 | "cell_type": "markdown", 783 | "metadata": {}, 784 | "source": [ 785 | "## Tuples\n", 786 | "\n", 787 | "Tuples are similar to lists but they cannot be modified, they are **immutable**." 788 | ] 789 | }, 790 | { 791 | "cell_type": "code", 792 | "execution_count": 30, 793 | "metadata": {}, 794 | "outputs": [ 795 | { 796 | "name": "stdout", 797 | "output_type": "stream", 798 | "text": [ 799 | "(1, 2, 3)\n", 800 | "1\n", 801 | "2\n", 802 | "3\n" 803 | ] 804 | } 805 | ], 806 | "source": [ 807 | "x = (1,2,3)\n", 808 | "print(x)\n", 809 | "print(x[0])\n", 810 | "print(x[1])\n", 811 | "print(x[2])" 812 | ] 813 | }, 814 | { 815 | "cell_type": "markdown", 816 | "metadata": {}, 817 | "source": [ 818 | "Try to modify some element of a tuple, for example\n", 819 | "\n", 820 | "```python\n", 821 | "x[1] = 0\n", 822 | "```" 823 | ] 824 | }, 825 | { 826 | "cell_type": "markdown", 827 | "metadata": {}, 828 | "source": [ 829 | "**NOTE**: Lists and tuples can contain elements of different types" 830 | ] 831 | }, 832 | { 833 | "cell_type": "code", 834 | "execution_count": 31, 835 | "metadata": {}, 836 | "outputs": [ 837 | { 838 | "name": "stdout", 839 | "output_type": "stream", 840 | "text": [ 841 | "a = [1, 2, 'a']\n", 842 | "b = (1, 2, 'a')\n" 843 | ] 844 | } 845 | ], 846 | "source": [ 847 | "a = [1,2,'a']\n", 848 | "b = (1,2,'a')\n", 849 | "print(\"a = \", a)\n", 850 | "print(\"b = \", b)" 851 | ] 852 | }, 853 | { 854 | "cell_type": "markdown", 855 | "metadata": {}, 856 | "source": [ 857 | "## Sets\n", 858 | "\n", 859 | "A set is a collection of some objects which can be of any and different types." 860 | ] 861 | }, 862 | { 863 | "cell_type": "code", 864 | "execution_count": 32, 865 | "metadata": {}, 866 | "outputs": [ 867 | { 868 | "name": "stdout", 869 | "output_type": "stream", 870 | "text": [ 871 | "{1, 2, 3, 'a', 'c', 'b'}\n" 872 | ] 873 | } 874 | ], 875 | "source": [ 876 | "a = {1, 2, 3, 'a', 'b', 'c'}\n", 877 | "print(a)" 878 | ] 879 | }, 880 | { 881 | "cell_type": "markdown", 882 | "metadata": {}, 883 | "source": [ 884 | "Elements of a set must be unique." 885 | ] 886 | }, 887 | { 888 | "cell_type": "code", 889 | "execution_count": 33, 890 | "metadata": {}, 891 | "outputs": [ 892 | { 893 | "name": "stdout", 894 | "output_type": "stream", 895 | "text": [ 896 | "{1, 2, 3}\n" 897 | ] 898 | } 899 | ], 900 | "source": [ 901 | "b = {1, 2, 3, 3}\n", 902 | "print(b)" 903 | ] 904 | }, 905 | { 906 | "cell_type": "markdown", 907 | "metadata": {}, 908 | "source": [ 909 | "Minus performs set minus." 910 | ] 911 | }, 912 | { 913 | "cell_type": "code", 914 | "execution_count": 34, 915 | "metadata": {}, 916 | "outputs": [ 917 | { 918 | "name": "stdout", 919 | "output_type": "stream", 920 | "text": [ 921 | "{4}\n", 922 | "set()\n" 923 | ] 924 | } 925 | ], 926 | "source": [ 927 | "a = {1,2,3,4}\n", 928 | "b = {1,2,3}\n", 929 | "print(a-b)\n", 930 | "print(b-a)" 931 | ] 932 | }, 933 | { 934 | "cell_type": "markdown", 935 | "metadata": {}, 936 | "source": [ 937 | "Union of sets" 938 | ] 939 | }, 940 | { 941 | "cell_type": "code", 942 | "execution_count": 35, 943 | "metadata": {}, 944 | "outputs": [ 945 | { 946 | "name": "stdout", 947 | "output_type": "stream", 948 | "text": [ 949 | "{1, 2, 3, 4, 5, 6}\n", 950 | "{1, 2, 3, 4, 5, 6}\n" 951 | ] 952 | } 953 | ], 954 | "source": [ 955 | "c = {1,2,3,4}\n", 956 | "d = {3,4,5,6}\n", 957 | "print(c.union(d))\n", 958 | "print(c|d)" 959 | ] 960 | }, 961 | { 962 | "cell_type": "markdown", 963 | "metadata": {}, 964 | "source": [ 965 | "## For loops" 966 | ] 967 | }, 968 | { 969 | "cell_type": "code", 970 | "execution_count": 36, 971 | "metadata": {}, 972 | "outputs": [ 973 | { 974 | "name": "stdout", 975 | "output_type": "stream", 976 | "text": [ 977 | "0\n", 978 | "1\n", 979 | "2\n", 980 | "3\n", 981 | "4\n" 982 | ] 983 | } 984 | ], 985 | "source": [ 986 | "for i in range(5):\n", 987 | " print(i)" 988 | ] 989 | }, 990 | { 991 | "cell_type": "markdown", 992 | "metadata": {}, 993 | "source": [ 994 | "> `range(n)` produces the integers: $0,1,2,\\ldots,n-1$. **Note**: $n$ is not included." 995 | ] 996 | }, 997 | { 998 | "cell_type": "code", 999 | "execution_count": 37, 1000 | "metadata": {}, 1001 | "outputs": [ 1002 | { 1003 | "name": "stdout", 1004 | "output_type": "stream", 1005 | "text": [ 1006 | "range(0, 5)\n", 1007 | "\n" 1008 | ] 1009 | } 1010 | ], 1011 | "source": [ 1012 | "print(range(5))\n", 1013 | "print(type(range(5)))" 1014 | ] 1015 | }, 1016 | { 1017 | "cell_type": "markdown", 1018 | "metadata": {}, 1019 | "source": [ 1020 | "Specify both start and end" 1021 | ] 1022 | }, 1023 | { 1024 | "cell_type": "code", 1025 | "execution_count": 38, 1026 | "metadata": {}, 1027 | "outputs": [ 1028 | { 1029 | "name": "stdout", 1030 | "output_type": "stream", 1031 | "text": [ 1032 | "5\n", 1033 | "6\n", 1034 | "7\n", 1035 | "8\n", 1036 | "9\n" 1037 | ] 1038 | } 1039 | ], 1040 | "source": [ 1041 | "for i in range(5,10):\n", 1042 | " print(i)" 1043 | ] 1044 | }, 1045 | { 1046 | "cell_type": "markdown", 1047 | "metadata": {}, 1048 | "source": [ 1049 | "> `range(m,n)` produces the integers: $m,m+1,\\ldots,n-1$ provided $m < n$." 1050 | ] 1051 | }, 1052 | { 1053 | "cell_type": "code", 1054 | "execution_count": 39, 1055 | "metadata": {}, 1056 | "outputs": [ 1057 | { 1058 | "name": "stdout", 1059 | "output_type": "stream", 1060 | "text": [ 1061 | "0\n", 1062 | "2\n", 1063 | "4\n", 1064 | "6\n", 1065 | "8\n" 1066 | ] 1067 | } 1068 | ], 1069 | "source": [ 1070 | "for i in range(0,10,2):\n", 1071 | " print(i)" 1072 | ] 1073 | }, 1074 | { 1075 | "cell_type": "markdown", 1076 | "metadata": {}, 1077 | "source": [ 1078 | "> `range(m,n,s)` produces the integers: $m,m+s,m+2s,\\ldots$ until $n$, but excluding $n$.\n", 1079 | "\n", 1080 | "We can have a negative step size." 1081 | ] 1082 | }, 1083 | { 1084 | "cell_type": "code", 1085 | "execution_count": 40, 1086 | "metadata": {}, 1087 | "outputs": [ 1088 | { 1089 | "name": "stdout", 1090 | "output_type": "stream", 1091 | "text": [ 1092 | "10\n", 1093 | "8\n", 1094 | "6\n", 1095 | "4\n", 1096 | "2\n" 1097 | ] 1098 | } 1099 | ], 1100 | "source": [ 1101 | "for i in range(10,0,-2):\n", 1102 | " print(i)" 1103 | ] 1104 | }, 1105 | { 1106 | "cell_type": "markdown", 1107 | "metadata": {}, 1108 | "source": [ 1109 | "Again, the last element, here 0, is not included." 1110 | ] 1111 | }, 1112 | { 1113 | "cell_type": "markdown", 1114 | "metadata": {}, 1115 | "source": [ 1116 | "## In built manual/help\n", 1117 | "\n", 1118 | "To see the inbuilt manual in terminal\n", 1119 | "\n", 1120 | "```\n", 1121 | ">>> range?\n", 1122 | "```\n", 1123 | "\n", 1124 | "This works for all functions, etc.\n", 1125 | "\n", 1126 | "```\n", 1127 | ">>> import math\n", 1128 | ">>> math.sin?\n", 1129 | "```\n", 1130 | "\n", 1131 | "In a notebook, type this in a code cell\n", 1132 | "\n", 1133 | "```\n", 1134 | "range?\n", 1135 | "```\n", 1136 | "\n", 1137 | "get the help documentation." 1138 | ] 1139 | }, 1140 | { 1141 | "cell_type": "markdown", 1142 | "metadata": {}, 1143 | "source": [ 1144 | "### Example: Sum a list of integers\n", 1145 | "\n", 1146 | "Given a vector $a \\in \\re^n$, compute the sum of its element\n", 1147 | "\n", 1148 | "$$\n", 1149 | "s = \\sum_{i=0}^{n-1} a_i\n", 1150 | "$$\n", 1151 | "\n", 1152 | "We will need some mechanism to iterate over the elements to compute the sum, and we can use a `for` loop." 1153 | ] 1154 | }, 1155 | { 1156 | "cell_type": "code", 1157 | "execution_count": 41, 1158 | "metadata": {}, 1159 | "outputs": [ 1160 | { 1161 | "name": "stdout", 1162 | "output_type": "stream", 1163 | "text": [ 1164 | "Sum = 55\n" 1165 | ] 1166 | } 1167 | ], 1168 | "source": [ 1169 | "a = [1,2,3,4,5,6,7,8,9,10]\n", 1170 | "s = 0\n", 1171 | "for x in a:\n", 1172 | " s += x\n", 1173 | "print('Sum = ',s)" 1174 | ] 1175 | }, 1176 | { 1177 | "cell_type": "markdown", 1178 | "metadata": {}, 1179 | "source": [ 1180 | "Note that ```s += x``` is shorthand for ```s = s + x```. Since we accumulate the sum into ```s```, we have to first initialize it to zero.\n", 1181 | "\n", 1182 | "Another way is to use indices" 1183 | ] 1184 | }, 1185 | { 1186 | "cell_type": "code", 1187 | "execution_count": 42, 1188 | "metadata": {}, 1189 | "outputs": [ 1190 | { 1191 | "name": "stdout", 1192 | "output_type": "stream", 1193 | "text": [ 1194 | "Sum = 55\n" 1195 | ] 1196 | } 1197 | ], 1198 | "source": [ 1199 | "s = 0\n", 1200 | "for i in range(len(a)):\n", 1201 | " s += a[i]\n", 1202 | "print('Sum = ',s)" 1203 | ] 1204 | }, 1205 | { 1206 | "cell_type": "markdown", 1207 | "metadata": {}, 1208 | "source": [ 1209 | "## while loop" 1210 | ] 1211 | }, 1212 | { 1213 | "cell_type": "markdown", 1214 | "metadata": {}, 1215 | "source": [ 1216 | "A `for` loop is useful when we know a-priori how many steps we have to do. When we dont know in advance how many steps are needed, a `while` loop may be more useful.\n", 1217 | "\n", 1218 | "*Example*: Generate independent uniform random numbers $x_j$ such that\n", 1219 | "\n", 1220 | "$$\n", 1221 | "\\sum_{j=0}^{n-1} x_j < 10, \\qquad \\sum_{j=0}^{n} x_j > 10\n", 1222 | "$$\n", 1223 | "\n", 1224 | "We dont know the value of `n` a-priori." 1225 | ] 1226 | }, 1227 | { 1228 | "cell_type": "code", 1229 | "execution_count": 43, 1230 | "metadata": {}, 1231 | "outputs": [ 1232 | { 1233 | "name": "stdout", 1234 | "output_type": "stream", 1235 | "text": [ 1236 | " 1 0.8873716434\n", 1237 | " 2 0.9739100601\n", 1238 | " 3 1.1960480491\n", 1239 | " 4 1.6826736515\n", 1240 | " 5 2.5353051026\n", 1241 | " 6 2.9297979733\n", 1242 | " 7 3.2043422871\n", 1243 | " 8 4.1510888250\n", 1244 | " 9 4.4179353035\n", 1245 | " 10 5.0078992111\n", 1246 | " 11 5.5844680478\n", 1247 | " 12 5.8572785197\n", 1248 | " 13 6.5139710357\n", 1249 | " 14 6.7351061446\n", 1250 | " 15 6.9718965215\n", 1251 | " 16 7.1313697227\n", 1252 | " 17 7.8804056880\n", 1253 | " 18 8.3069360047\n", 1254 | " 19 8.4680433264\n", 1255 | " 20 8.9498376224\n", 1256 | " 21 9.1751912676\n", 1257 | " 22 9.4168240331\n", 1258 | " 23 9.8345663817\n", 1259 | " 24 10.7104728221\n" 1260 | ] 1261 | } 1262 | ], 1263 | "source": [ 1264 | "import random\n", 1265 | "s, i = 0.0, 0\n", 1266 | "while s < 10.0:\n", 1267 | " s += random.random()\n", 1268 | " i += 1\n", 1269 | " print(\"%5d %20.10f\" % (i,s))" 1270 | ] 1271 | }, 1272 | { 1273 | "cell_type": "markdown", 1274 | "metadata": {}, 1275 | "source": [ 1276 | "Note how we controlled the printing of numbers: `d` is for integers, `f` is for floating point numbers. You can also use `e` for scientific notation." 1277 | ] 1278 | }, 1279 | { 1280 | "cell_type": "markdown", 1281 | "metadata": {}, 1282 | "source": [ 1283 | "## enumerate\n", 1284 | "\n", 1285 | "Another way to iterate over an array-type object where we get both index and element value is using enumerate." 1286 | ] 1287 | }, 1288 | { 1289 | "cell_type": "code", 1290 | "execution_count": 44, 1291 | "metadata": {}, 1292 | "outputs": [ 1293 | { 1294 | "name": "stdout", 1295 | "output_type": "stream", 1296 | "text": [ 1297 | "0 1.2\n", 1298 | "1 2.3\n", 1299 | "2 3.4\n", 1300 | "3 4.5\n", 1301 | "4 5.6\n" 1302 | ] 1303 | } 1304 | ], 1305 | "source": [ 1306 | "values = [1.2, 2.3, 3.4, 4.5, 5.6]\n", 1307 | "for i,val in enumerate(values):\n", 1308 | " print(i,\" \",val)" 1309 | ] 1310 | }, 1311 | { 1312 | "cell_type": "markdown", 1313 | "metadata": {}, 1314 | "source": [ 1315 | "## Swapping" 1316 | ] 1317 | }, 1318 | { 1319 | "cell_type": "code", 1320 | "execution_count": 3, 1321 | "metadata": {}, 1322 | "outputs": [ 1323 | { 1324 | "name": "stdout", 1325 | "output_type": "stream", 1326 | "text": [ 1327 | "Before: a = 1 , b = 2\n", 1328 | "After : a = 2 , b = 1\n" 1329 | ] 1330 | } 1331 | ], 1332 | "source": [ 1333 | "a, b = 1, 2\n", 1334 | "print('Before: a = ',a,', b = ',b)\n", 1335 | "tmp = a\n", 1336 | "a = b\n", 1337 | "b = tmp\n", 1338 | "print('After : a = ',a,', b = ',b)" 1339 | ] 1340 | }, 1341 | { 1342 | "cell_type": "markdown", 1343 | "metadata": {}, 1344 | "source": [ 1345 | "In Python, swapping can be done as" 1346 | ] 1347 | }, 1348 | { 1349 | "cell_type": "code", 1350 | "execution_count": 4, 1351 | "metadata": {}, 1352 | "outputs": [ 1353 | { 1354 | "name": "stdout", 1355 | "output_type": "stream", 1356 | "text": [ 1357 | "Before: a = 1 , b = 2\n", 1358 | "After : a = 2 , b = 1\n" 1359 | ] 1360 | } 1361 | ], 1362 | "source": [ 1363 | "a, b = 1, 2\n", 1364 | "print('Before: a = ',a,', b = ',b)\n", 1365 | "a, b = b, a\n", 1366 | "print('After : a = ',a,', b = ',b)" 1367 | ] 1368 | } 1369 | ], 1370 | "metadata": { 1371 | "kernelspec": { 1372 | "display_name": "Python 3 (ipykernel)", 1373 | "language": "python", 1374 | "name": "python3" 1375 | }, 1376 | "language_info": { 1377 | "codemirror_mode": { 1378 | "name": "ipython", 1379 | "version": 3 1380 | }, 1381 | "file_extension": ".py", 1382 | "mimetype": "text/x-python", 1383 | "name": "python", 1384 | "nbconvert_exporter": "python", 1385 | "pygments_lexer": "ipython3", 1386 | "version": "3.12.8" 1387 | }, 1388 | "toc": { 1389 | "base_numbering": 1, 1390 | "nav_menu": {}, 1391 | "number_sections": true, 1392 | "sideBar": true, 1393 | "skip_h1_title": false, 1394 | "title_cell": "Table of Contents", 1395 | "title_sidebar": "Contents", 1396 | "toc_cell": false, 1397 | "toc_position": {}, 1398 | "toc_section_display": true, 1399 | "toc_window_display": false 1400 | }, 1401 | "vscode": { 1402 | "interpreter": { 1403 | "hash": "c6e4e9f98eb68ad3b7c296f83d20e6de614cb42e90992a65aa266555a3137d0d" 1404 | } 1405 | } 1406 | }, 1407 | "nbformat": 4, 1408 | "nbformat_minor": 4 1409 | } 1410 | -------------------------------------------------------------------------------- /02_numpy.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Numpy" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "$\\newcommand{\\re}{\\mathbb{R}}$\n", 15 | "[Numpy](https://numpy.org/doc/stable/user/index.html) provides many useful types and methods to perform numerical computations including vectors, matrices and linear algebra.\n", 16 | "\n", 17 | "First import the numpy module." 18 | ] 19 | }, 20 | { 21 | "cell_type": "code", 22 | "execution_count": 1, 23 | "metadata": {}, 24 | "outputs": [], 25 | "source": [ 26 | "import numpy" 27 | ] 28 | }, 29 | { 30 | "cell_type": "markdown", 31 | "metadata": {}, 32 | "source": [ 33 | "You only need to do this once, usually at the beginning of your code.\n", 34 | "\n", 35 | "To access methods, etc. inside this module, use dot operator." 36 | ] 37 | }, 38 | { 39 | "cell_type": "code", 40 | "execution_count": 2, 41 | "metadata": {}, 42 | "outputs": [ 43 | { 44 | "name": "stdout", 45 | "output_type": "stream", 46 | "text": [ 47 | "3.141592653589793\n", 48 | "1.0\n" 49 | ] 50 | } 51 | ], 52 | "source": [ 53 | "print(numpy.pi)\n", 54 | "print(numpy.sin(numpy.pi/2))" 55 | ] 56 | }, 57 | { 58 | "cell_type": "markdown", 59 | "metadata": {}, 60 | "source": [ 61 | " It is common practice to import numpy like this." 62 | ] 63 | }, 64 | { 65 | "cell_type": "code", 66 | "execution_count": 3, 67 | "metadata": {}, 68 | "outputs": [], 69 | "source": [ 70 | "import numpy as np" 71 | ] 72 | }, 73 | { 74 | "cell_type": "markdown", 75 | "metadata": {}, 76 | "source": [ 77 | "Note that ```np``` acts as an alias or short-hand for ```numpy```." 78 | ] 79 | }, 80 | { 81 | "cell_type": "code", 82 | "execution_count": 4, 83 | "metadata": {}, 84 | "outputs": [ 85 | { 86 | "name": "stdout", 87 | "output_type": "stream", 88 | "text": [ 89 | "3.141592653589793\n", 90 | "1.0\n" 91 | ] 92 | } 93 | ], 94 | "source": [ 95 | "print(np.pi)\n", 96 | "print(np.sin(np.pi/2))" 97 | ] 98 | }, 99 | { 100 | "cell_type": "markdown", 101 | "metadata": {}, 102 | "source": [ 103 | "## 1-d [arrays](https://numpy.org/doc/stable/reference/generated/numpy.array.html)" 104 | ] 105 | }, 106 | { 107 | "cell_type": "markdown", 108 | "metadata": {}, 109 | "source": [ 110 | "Create an array of zeros" 111 | ] 112 | }, 113 | { 114 | "cell_type": "code", 115 | "execution_count": 5, 116 | "metadata": {}, 117 | "outputs": [ 118 | { 119 | "name": "stdout", 120 | "output_type": "stream", 121 | "text": [ 122 | "[0. 0. 0. 0. 0.]\n" 123 | ] 124 | } 125 | ], 126 | "source": [ 127 | "x = np.zeros(5)\n", 128 | "print(x)" 129 | ] 130 | }, 131 | { 132 | "cell_type": "markdown", 133 | "metadata": {}, 134 | "source": [ 135 | "These one dimensional arrays are of type ```ndarray```" 136 | ] 137 | }, 138 | { 139 | "cell_type": "code", 140 | "execution_count": 6, 141 | "metadata": {}, 142 | "outputs": [ 143 | { 144 | "data": { 145 | "text/plain": [ 146 | "numpy.ndarray" 147 | ] 148 | }, 149 | "execution_count": 6, 150 | "metadata": {}, 151 | "output_type": "execute_result" 152 | } 153 | ], 154 | "source": [ 155 | "type(x)" 156 | ] 157 | }, 158 | { 159 | "cell_type": "markdown", 160 | "metadata": {}, 161 | "source": [ 162 | "Create an array of ones" 163 | ] 164 | }, 165 | { 166 | "cell_type": "code", 167 | "execution_count": 7, 168 | "metadata": {}, 169 | "outputs": [ 170 | { 171 | "name": "stdout", 172 | "output_type": "stream", 173 | "text": [ 174 | "[1. 1. 1. 1. 1.]\n" 175 | ] 176 | } 177 | ], 178 | "source": [ 179 | "x = np.ones(5)\n", 180 | "print(x)" 181 | ] 182 | }, 183 | { 184 | "cell_type": "markdown", 185 | "metadata": {}, 186 | "source": [ 187 | "Create and add two arrays" 188 | ] 189 | }, 190 | { 191 | "cell_type": "code", 192 | "execution_count": 8, 193 | "metadata": {}, 194 | "outputs": [ 195 | { 196 | "name": "stdout", 197 | "output_type": "stream", 198 | "text": [ 199 | "[5. 7. 9.]\n" 200 | ] 201 | } 202 | ], 203 | "source": [ 204 | "x = np.array([1.0, 2.0, 3.0])\n", 205 | "y = np.array([4.0, 5.0, 6.0])\n", 206 | "z = x + y\n", 207 | "print(z)" 208 | ] 209 | }, 210 | { 211 | "cell_type": "markdown", 212 | "metadata": {}, 213 | "source": [ 214 | "Get the size of array" 215 | ] 216 | }, 217 | { 218 | "cell_type": "code", 219 | "execution_count": 9, 220 | "metadata": {}, 221 | "outputs": [ 222 | { 223 | "name": "stdout", 224 | "output_type": "stream", 225 | "text": [ 226 | "3\n", 227 | "3\n" 228 | ] 229 | } 230 | ], 231 | "source": [ 232 | "print(len(x))\n", 233 | "print(x.size)" 234 | ] 235 | }, 236 | { 237 | "cell_type": "markdown", 238 | "metadata": {}, 239 | "source": [ 240 | "Get the shape of an array" 241 | ] 242 | }, 243 | { 244 | "cell_type": "code", 245 | "execution_count": 10, 246 | "metadata": {}, 247 | "outputs": [ 248 | { 249 | "name": "stdout", 250 | "output_type": "stream", 251 | "text": [ 252 | "(3,)\n" 253 | ] 254 | } 255 | ], 256 | "source": [ 257 | "print(x.shape)" 258 | ] 259 | }, 260 | { 261 | "cell_type": "markdown", 262 | "metadata": {}, 263 | "source": [ 264 | "We see that these are arrays of reals by default. We can specify the type" 265 | ] 266 | }, 267 | { 268 | "cell_type": "code", 269 | "execution_count": 11, 270 | "metadata": {}, 271 | "outputs": [ 272 | { 273 | "name": "stdout", 274 | "output_type": "stream", 275 | "text": [ 276 | "[0 0 0 0 0]\n" 277 | ] 278 | } 279 | ], 280 | "source": [ 281 | "a = np.zeros(5, dtype=int)\n", 282 | "print(a)" 283 | ] 284 | }, 285 | { 286 | "cell_type": "markdown", 287 | "metadata": {}, 288 | "source": [ 289 | "## [linspace](https://numpy.org/doc/stable/reference/generated/numpy.linspace.html)" 290 | ] 291 | }, 292 | { 293 | "cell_type": "markdown", 294 | "metadata": {}, 295 | "source": [ 296 | "This behaves same way as Matlab's [linspace](https://mathworks.com/help/matlab/ref/linspace.html) function.\n", 297 | "\n", 298 | "Generate 10 uniformly spaced numbers in [1,10]" 299 | ] 300 | }, 301 | { 302 | "cell_type": "code", 303 | "execution_count": 12, 304 | "metadata": {}, 305 | "outputs": [ 306 | { 307 | "name": "stdout", 308 | "output_type": "stream", 309 | "text": [ 310 | "[ 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.]\n" 311 | ] 312 | } 313 | ], 314 | "source": [ 315 | "x = np.linspace(1,10,10)\n", 316 | "print(x)" 317 | ] 318 | }, 319 | { 320 | "cell_type": "markdown", 321 | "metadata": {}, 322 | "source": [ 323 | "Note that this includes the end points 1 and 10. The output of linspace is an ```ndarray``` of floats." 324 | ] 325 | }, 326 | { 327 | "cell_type": "code", 328 | "execution_count": 13, 329 | "metadata": {}, 330 | "outputs": [ 331 | { 332 | "data": { 333 | "text/plain": [ 334 | "numpy.ndarray" 335 | ] 336 | }, 337 | "execution_count": 13, 338 | "metadata": {}, 339 | "output_type": "execute_result" 340 | } 341 | ], 342 | "source": [ 343 | "type(x)" 344 | ] 345 | }, 346 | { 347 | "cell_type": "markdown", 348 | "metadata": {}, 349 | "source": [ 350 | "`x = linspace(a,b,n)` is such that `x` is an array of `n` elements\n", 351 | "\n", 352 | "```\n", 353 | "x[i] = a + i*h, i=0,1,2,...,n-1, h = (b-a)/(n-1)\n", 354 | "```\n", 355 | " \n", 356 | "so that\n", 357 | " \n", 358 | "```\n", 359 | "x[0] = a, x[n-1] = x[-1] = b\n", 360 | "```\n", 361 | "\n", 362 | "Note that we get last element of array using `x[-1]`; similarly, the last but one is given by `x[-2]`, etc." 363 | ] 364 | }, 365 | { 366 | "cell_type": "markdown", 367 | "metadata": {}, 368 | "source": [ 369 | "## [arange](https://numpy.org/doc/stable/reference/generated/numpy.arange.html)" 370 | ] 371 | }, 372 | { 373 | "cell_type": "code", 374 | "execution_count": 14, 375 | "metadata": {}, 376 | "outputs": [ 377 | { 378 | "name": "stdout", 379 | "output_type": "stream", 380 | "text": [ 381 | "[1 2 3 4 5 6 7 8 9]\n", 382 | "\n" 383 | ] 384 | } 385 | ], 386 | "source": [ 387 | "x = np.arange(1,10)\n", 388 | "print(x)\n", 389 | "print(type(x))" 390 | ] 391 | }, 392 | { 393 | "cell_type": "markdown", 394 | "metadata": {}, 395 | "source": [ 396 | "For $m < n$, `arange(m,n)` returns\n", 397 | "\n", 398 | "$$\n", 399 | "m, m+1, \\ldots, n-1\n", 400 | "$$\n", 401 | "\n", 402 | "Note the last value $n$ is not included. \n", 403 | "\n", 404 | "We can specify a step size" 405 | ] 406 | }, 407 | { 408 | "cell_type": "code", 409 | "execution_count": 15, 410 | "metadata": {}, 411 | "outputs": [ 412 | { 413 | "name": "stdout", 414 | "output_type": "stream", 415 | "text": [ 416 | "[1 3 5 7 9]\n" 417 | ] 418 | } 419 | ], 420 | "source": [ 421 | "x = np.arange(1,10,2)\n", 422 | "print(x)" 423 | ] 424 | }, 425 | { 426 | "cell_type": "markdown", 427 | "metadata": {}, 428 | "source": [ 429 | "If the arguments are float, the returned value is also float." 430 | ] 431 | }, 432 | { 433 | "cell_type": "code", 434 | "execution_count": 16, 435 | "metadata": {}, 436 | "outputs": [ 437 | { 438 | "name": "stdout", 439 | "output_type": "stream", 440 | "text": [ 441 | "[1. 2. 3. 4. 5. 6. 7. 8. 9.]\n" 442 | ] 443 | } 444 | ], 445 | "source": [ 446 | "x = np.arange(1.0,10.0)\n", 447 | "print(x)" 448 | ] 449 | }, 450 | { 451 | "cell_type": "code", 452 | "execution_count": 17, 453 | "metadata": {}, 454 | "outputs": [ 455 | { 456 | "name": "stdout", 457 | "output_type": "stream", 458 | "text": [ 459 | "[0. 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9]\n" 460 | ] 461 | } 462 | ], 463 | "source": [ 464 | "x = np.arange(0,1,0.1)\n", 465 | "print(x)" 466 | ] 467 | }, 468 | { 469 | "cell_type": "markdown", 470 | "metadata": {}, 471 | "source": [ 472 | "## Beware of pitfalls - 1\n", 473 | "\n", 474 | "Create an array of ones." 475 | ] 476 | }, 477 | { 478 | "cell_type": "code", 479 | "execution_count": 18, 480 | "metadata": {}, 481 | "outputs": [ 482 | { 483 | "name": "stdout", 484 | "output_type": "stream", 485 | "text": [ 486 | "[1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]\n" 487 | ] 488 | } 489 | ], 490 | "source": [ 491 | "x = np.ones(10)\n", 492 | "print(x)" 493 | ] 494 | }, 495 | { 496 | "cell_type": "markdown", 497 | "metadata": {}, 498 | "source": [ 499 | "Maybe we want set all elements to zero, so we might try this" 500 | ] 501 | }, 502 | { 503 | "cell_type": "code", 504 | "execution_count": 19, 505 | "metadata": {}, 506 | "outputs": [ 507 | { 508 | "name": "stdout", 509 | "output_type": "stream", 510 | "text": [ 511 | "0.0\n" 512 | ] 513 | } 514 | ], 515 | "source": [ 516 | "x = 0.0\n", 517 | "print(x)" 518 | ] 519 | }, 520 | { 521 | "cell_type": "markdown", 522 | "metadata": {}, 523 | "source": [ 524 | "```x``` has changed from an array to a scalar !!! In Python, the type of a variable is determined by what we assign to it. The correct way to set zeroes is this." 525 | ] 526 | }, 527 | { 528 | "cell_type": "code", 529 | "execution_count": 20, 530 | "metadata": {}, 531 | "outputs": [ 532 | { 533 | "name": "stdout", 534 | "output_type": "stream", 535 | "text": [ 536 | "[1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]\n", 537 | "[0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]\n" 538 | ] 539 | } 540 | ], 541 | "source": [ 542 | "x = np.ones(10)\n", 543 | "print(x)\n", 544 | "x[:] = 0.0\n", 545 | "print(x)" 546 | ] 547 | }, 548 | { 549 | "cell_type": "markdown", 550 | "metadata": {}, 551 | "source": [ 552 | "## Beware of pitfalls - 2" 553 | ] 554 | }, 555 | { 556 | "cell_type": "code", 557 | "execution_count": 21, 558 | "metadata": {}, 559 | "outputs": [ 560 | { 561 | "name": "stdout", 562 | "output_type": "stream", 563 | "text": [ 564 | "x = [0. 0. 0. 0. 0.]\n", 565 | "y = [0. 0. 0. 0. 0.]\n" 566 | ] 567 | } 568 | ], 569 | "source": [ 570 | "x = np.ones(5)\n", 571 | "y = x\n", 572 | "x[:] = 0.0\n", 573 | "print('x = ', x)\n", 574 | "print('y = ', y)" 575 | ] 576 | }, 577 | { 578 | "cell_type": "markdown", 579 | "metadata": {}, 580 | "source": [ 581 | "Why did ```y``` change ? This happened because when we do\n", 582 | "\n", 583 | "```\n", 584 | "y = x\n", 585 | "```\n", 586 | "\n", 587 | "then `y` is just a pointer to `x`, so that changing `x` changes `y` also. If we want ```y``` to be an independent copy of ```x``` then do this" 588 | ] 589 | }, 590 | { 591 | "cell_type": "code", 592 | "execution_count": 22, 593 | "metadata": {}, 594 | "outputs": [ 595 | { 596 | "name": "stdout", 597 | "output_type": "stream", 598 | "text": [ 599 | "x = [0. 0. 0. 0. 0.]\n", 600 | "y = [1. 1. 1. 1. 1.]\n" 601 | ] 602 | } 603 | ], 604 | "source": [ 605 | "x = np.ones(5)\n", 606 | "y = x.copy() # or y = np.copy(x)\n", 607 | "x[:] = 0.0\n", 608 | "print('x = ', x)\n", 609 | "print('y = ', y)" 610 | ] 611 | }, 612 | { 613 | "cell_type": "markdown", 614 | "metadata": {}, 615 | "source": [ 616 | "## 2-d [arrays](https://numpy.org/doc/stable/reference/generated/numpy.array.html)" 617 | ] 618 | }, 619 | { 620 | "cell_type": "markdown", 621 | "metadata": {}, 622 | "source": [ 623 | "2-d arrays can be considered as matrices, though Numpy has a separate [matrix](https://numpy.org/doc/stable/reference/generated/numpy.matrix.html) class.\n", 624 | "\n", 625 | "Create an array of zeros" 626 | ] 627 | }, 628 | { 629 | "cell_type": "code", 630 | "execution_count": 23, 631 | "metadata": {}, 632 | "outputs": [ 633 | { 634 | "name": "stdout", 635 | "output_type": "stream", 636 | "text": [ 637 | "[[0. 0. 0. 0. 0.]\n", 638 | " [0. 0. 0. 0. 0.]\n", 639 | " [0. 0. 0. 0. 0.]\n", 640 | " [0. 0. 0. 0. 0.]\n", 641 | " [0. 0. 0. 0. 0.]]\n" 642 | ] 643 | } 644 | ], 645 | "source": [ 646 | "A = np.zeros((5,5))\n", 647 | "print(A)" 648 | ] 649 | }, 650 | { 651 | "cell_type": "markdown", 652 | "metadata": {}, 653 | "source": [ 654 | "The size must be specified as a tuple or list.\n", 655 | "\n", 656 | "We can access the elements by two indices `A[i,j]`: here `i` is the row index and `j` is the column index.\n", 657 | "\n", 658 | "```\n", 659 | " -----------j-------->\n", 660 | " | [[0. 0. 0. 0. 0.]\n", 661 | " | [0. 0. 0. 0. 0.]\n", 662 | " i [0. 0. 0. 0. 0.]\n", 663 | " | [0. 0. 0. 0. 0.]\n", 664 | " v [0. 0. 0. 0. 0.]]\n", 665 | "```\n", 666 | "\n", 667 | "The top, left element is `A[0,0]`.\n", 668 | "\n", 669 | "We can modify the elements of an array." 670 | ] 671 | }, 672 | { 673 | "cell_type": "code", 674 | "execution_count": 24, 675 | "metadata": {}, 676 | "outputs": [ 677 | { 678 | "name": "stdout", 679 | "output_type": "stream", 680 | "text": [ 681 | "[[0. 0. 0. 0. 0.]\n", 682 | " [0. 1. 0. 0. 0.]\n", 683 | " [0. 0. 0. 0. 0.]\n", 684 | " [0. 0. 0. 0. 0.]\n", 685 | " [0. 0. 0. 0. 0.]]\n" 686 | ] 687 | } 688 | ], 689 | "source": [ 690 | "A[1,1] = 1.0\n", 691 | "print(A)" 692 | ] 693 | }, 694 | { 695 | "cell_type": "markdown", 696 | "metadata": {}, 697 | "source": [ 698 | "Create an array of ones" 699 | ] 700 | }, 701 | { 702 | "cell_type": "code", 703 | "execution_count": 25, 704 | "metadata": {}, 705 | "outputs": [ 706 | { 707 | "name": "stdout", 708 | "output_type": "stream", 709 | "text": [ 710 | "[[1. 1. 1.]\n", 711 | " [1. 1. 1.]]\n" 712 | ] 713 | } 714 | ], 715 | "source": [ 716 | "A = np.ones((2,3))\n", 717 | "print(A)" 718 | ] 719 | }, 720 | { 721 | "cell_type": "markdown", 722 | "metadata": {}, 723 | "source": [ 724 | "Create identity matrix" 725 | ] 726 | }, 727 | { 728 | "cell_type": "code", 729 | "execution_count": 26, 730 | "metadata": {}, 731 | "outputs": [ 732 | { 733 | "name": "stdout", 734 | "output_type": "stream", 735 | "text": [ 736 | "[[1. 0. 0. 0. 0.]\n", 737 | " [0. 1. 0. 0. 0.]\n", 738 | " [0. 0. 1. 0. 0.]\n", 739 | " [0. 0. 0. 1. 0.]\n", 740 | " [0. 0. 0. 0. 1.]]\n" 741 | ] 742 | } 743 | ], 744 | "source": [ 745 | "A = np.eye(5)\n", 746 | "print(A)" 747 | ] 748 | }, 749 | { 750 | "cell_type": "markdown", 751 | "metadata": {}, 752 | "source": [ 753 | "Create an array by specifying its elements" 754 | ] 755 | }, 756 | { 757 | "cell_type": "code", 758 | "execution_count": 27, 759 | "metadata": {}, 760 | "outputs": [ 761 | { 762 | "name": "stdout", 763 | "output_type": "stream", 764 | "text": [ 765 | "[[1. 2.]\n", 766 | " [3. 4.]]\n" 767 | ] 768 | } 769 | ], 770 | "source": [ 771 | "A = np.array([[1.0, 2.0], \n", 772 | " [3.0, 4.0]])\n", 773 | "print(A)" 774 | ] 775 | }, 776 | { 777 | "cell_type": "markdown", 778 | "metadata": {}, 779 | "source": [ 780 | "Create a random array and inspect its shape" 781 | ] 782 | }, 783 | { 784 | "cell_type": "code", 785 | "execution_count": 28, 786 | "metadata": {}, 787 | "outputs": [ 788 | { 789 | "name": "stdout", 790 | "output_type": "stream", 791 | "text": [ 792 | "[[0.89240244 0.01102157 0.28536729]\n", 793 | " [0.18283483 0.31998222 0.83111649]]\n", 794 | "A.size = 6\n", 795 | "A.shape = (2, 3)\n", 796 | "A.shape[0] = 2 (number of rows)\n", 797 | "A.shape[1] = 3 (number of columns)\n" 798 | ] 799 | } 800 | ], 801 | "source": [ 802 | "m, n = 2, 3\n", 803 | "A = np.random.rand(m,n)\n", 804 | "print(A)\n", 805 | "print('A.size =',A.size)\n", 806 | "print('A.shape =',A.shape)\n", 807 | "print('A.shape[0] =',A.shape[0],' (number of rows)')\n", 808 | "print('A.shape[1] =',A.shape[1],' (number of columns)')" 809 | ] 810 | }, 811 | { 812 | "cell_type": "markdown", 813 | "metadata": {}, 814 | "source": [ 815 | "To print the elements of an array, we need two for loops, one over rows and another over the columns." 816 | ] 817 | }, 818 | { 819 | "cell_type": "code", 820 | "execution_count": 29, 821 | "metadata": {}, 822 | "outputs": [ 823 | { 824 | "name": "stdout", 825 | "output_type": "stream", 826 | "text": [ 827 | "0 0 0.892402443100909\n", 828 | "0 1 0.011021569236399187\n", 829 | "0 2 0.28536728733369776\n", 830 | "1 0 0.18283482545437424\n", 831 | "1 1 0.3199822225675184\n", 832 | "1 2 0.8311164902890094\n" 833 | ] 834 | } 835 | ], 836 | "source": [ 837 | "for i in range(m): # loop over rows\n", 838 | " for j in range(n): # loop over columns\n", 839 | " print(i,j,A[i,j])" 840 | ] 841 | }, 842 | { 843 | "cell_type": "markdown", 844 | "metadata": {}, 845 | "source": [ 846 | "To transpose a 2-d array" 847 | ] 848 | }, 849 | { 850 | "cell_type": "code", 851 | "execution_count": 30, 852 | "metadata": {}, 853 | "outputs": [ 854 | { 855 | "name": "stdout", 856 | "output_type": "stream", 857 | "text": [ 858 | "A =\n", 859 | "[[1 2]\n", 860 | " [3 4]]\n", 861 | "B =\n", 862 | "[[1 3]\n", 863 | " [2 4]]\n" 864 | ] 865 | } 866 | ], 867 | "source": [ 868 | "A = np.array([[1,2],[3,4]])\n", 869 | "print(\"A =\"); print(A)\n", 870 | "B = A.T\n", 871 | "print(\"B =\"); print(B)" 872 | ] 873 | }, 874 | { 875 | "cell_type": "markdown", 876 | "metadata": {}, 877 | "source": [ 878 | "## Diagonal matrix\n", 879 | "\n", 880 | "Create\n", 881 | "\n", 882 | "$$\n", 883 | "A = \\begin{bmatrix}\n", 884 | "1 & 0 & 0 & 0 \\\\\n", 885 | "0 & 2 & 0 & 0 \\\\\n", 886 | "0 & 0 & 3 & 0 \\\\\n", 887 | "0 & 0 & 0 & 4 \\end{bmatrix}\n", 888 | "$$" 889 | ] 890 | }, 891 | { 892 | "cell_type": "code", 893 | "execution_count": 31, 894 | "metadata": {}, 895 | "outputs": [ 896 | { 897 | "name": "stdout", 898 | "output_type": "stream", 899 | "text": [ 900 | "[[1 0 0 0]\n", 901 | " [0 2 0 0]\n", 902 | " [0 0 3 0]\n", 903 | " [0 0 0 4]]\n" 904 | ] 905 | } 906 | ], 907 | "source": [ 908 | "a = np.array([1,2,3,4]) # diagonal elements\n", 909 | "A = np.diag(a)\n", 910 | "print(A)" 911 | ] 912 | }, 913 | { 914 | "cell_type": "markdown", 915 | "metadata": {}, 916 | "source": [ 917 | "Create $n \\times n$ tri-diagonal matrix" 918 | ] 919 | }, 920 | { 921 | "cell_type": "code", 922 | "execution_count": 32, 923 | "metadata": {}, 924 | "outputs": [ 925 | { 926 | "name": "stdout", 927 | "output_type": "stream", 928 | "text": [ 929 | "[[ 4 -1 0 0]\n", 930 | " [ 1 5 -2 0]\n", 931 | " [ 0 2 6 -3]\n", 932 | " [ 0 0 3 7]]\n" 933 | ] 934 | } 935 | ], 936 | "source": [ 937 | "a = np.array([1,2,3]) # sub-diagonal : length = n-1\n", 938 | "b = np.array([4,5,6,7]) # main diagonal : length = n\n", 939 | "c = np.array([-1,-2,-3]) # super-diagonal: length = n-1\n", 940 | "A = np.diag(a,-1) + np.diag(b,0) + np.diag(c,+1)\n", 941 | "print(A)" 942 | ] 943 | }, 944 | { 945 | "cell_type": "markdown", 946 | "metadata": {}, 947 | "source": [ 948 | "## empty_like, etc.\n", 949 | "\n", 950 | "Sometimes we have an existing array and we want to create a new array of the same shape and type, but without initializing its elements." 951 | ] 952 | }, 953 | { 954 | "cell_type": "code", 955 | "execution_count": 33, 956 | "metadata": {}, 957 | "outputs": [ 958 | { 959 | "name": "stdout", 960 | "output_type": "stream", 961 | "text": [ 962 | "(2, 3) (2, 3)\n" 963 | ] 964 | } 965 | ], 966 | "source": [ 967 | "A = np.random.rand(2,3)\n", 968 | "B = np.empty_like(A)\n", 969 | "print(A.shape,B.shape)" 970 | ] 971 | }, 972 | { 973 | "cell_type": "code", 974 | "execution_count": 34, 975 | "metadata": {}, 976 | "outputs": [ 977 | { 978 | "name": "stdout", 979 | "output_type": "stream", 980 | "text": [ 981 | "[[0. 0. 0.]\n", 982 | " [0. 0. 0.]]\n" 983 | ] 984 | } 985 | ], 986 | "source": [ 987 | "C = np.zeros_like(A)\n", 988 | "print(C)" 989 | ] 990 | }, 991 | { 992 | "cell_type": "code", 993 | "execution_count": 35, 994 | "metadata": {}, 995 | "outputs": [ 996 | { 997 | "name": "stdout", 998 | "output_type": "stream", 999 | "text": [ 1000 | "[[1. 1. 1.]\n", 1001 | " [1. 1. 1.]]\n" 1002 | ] 1003 | } 1004 | ], 1005 | "source": [ 1006 | "D = np.ones_like(A)\n", 1007 | "print(D)" 1008 | ] 1009 | }, 1010 | { 1011 | "cell_type": "markdown", 1012 | "metadata": {}, 1013 | "source": [ 1014 | "## 1-D array is neither row nor column vector" 1015 | ] 1016 | }, 1017 | { 1018 | "cell_type": "code", 1019 | "execution_count": 36, 1020 | "metadata": {}, 1021 | "outputs": [ 1022 | { 1023 | "name": "stdout", 1024 | "output_type": "stream", 1025 | "text": [ 1026 | "(3,) [1 2 3]\n", 1027 | "(3,) [1 2 3]\n" 1028 | ] 1029 | } 1030 | ], 1031 | "source": [ 1032 | "x = np.array([1,2,3])\n", 1033 | "print(x.shape, x)\n", 1034 | "y = x.T\n", 1035 | "print(y.shape, y)" 1036 | ] 1037 | }, 1038 | { 1039 | "cell_type": "markdown", 1040 | "metadata": {}, 1041 | "source": [ 1042 | "Create a row vector" 1043 | ] 1044 | }, 1045 | { 1046 | "cell_type": "code", 1047 | "execution_count": 37, 1048 | "metadata": {}, 1049 | "outputs": [ 1050 | { 1051 | "name": "stdout", 1052 | "output_type": "stream", 1053 | "text": [ 1054 | "x.shape = (1, 3)\n", 1055 | "[[1 2 3]]\n", 1056 | "y.shape = (3, 1)\n", 1057 | "[[1]\n", 1058 | " [2]\n", 1059 | " [3]]\n" 1060 | ] 1061 | } 1062 | ], 1063 | "source": [ 1064 | "x = np.array([[1,2,3]]) # row vector\n", 1065 | "print('x.shape =',x.shape)\n", 1066 | "print(x)\n", 1067 | "y = x.T\n", 1068 | "print('y.shape =',y.shape)\n", 1069 | "print(y)" 1070 | ] 1071 | }, 1072 | { 1073 | "cell_type": "markdown", 1074 | "metadata": {}, 1075 | "source": [ 1076 | "Create a column vector" 1077 | ] 1078 | }, 1079 | { 1080 | "cell_type": "code", 1081 | "execution_count": 38, 1082 | "metadata": { 1083 | "scrolled": true 1084 | }, 1085 | "outputs": [ 1086 | { 1087 | "name": "stdout", 1088 | "output_type": "stream", 1089 | "text": [ 1090 | "x.shape = (3, 1)\n", 1091 | "[[1]\n", 1092 | " [2]\n", 1093 | " [3]]\n", 1094 | "y.shape = (1, 3)\n", 1095 | "[[1 2 3]]\n" 1096 | ] 1097 | } 1098 | ], 1099 | "source": [ 1100 | "x = np.array([[1],\n", 1101 | " [2],\n", 1102 | " [3]]) # column vector\n", 1103 | "print('x.shape =',x.shape)\n", 1104 | "print(x)\n", 1105 | "y = x.T\n", 1106 | "print('y.shape =',y.shape)\n", 1107 | "print(y)" 1108 | ] 1109 | }, 1110 | { 1111 | "cell_type": "markdown", 1112 | "metadata": {}, 1113 | "source": [ 1114 | "Functions like `zeros` and `ones` can return row/column vector rather than array." 1115 | ] 1116 | }, 1117 | { 1118 | "cell_type": "code", 1119 | "execution_count": 39, 1120 | "metadata": { 1121 | "scrolled": true 1122 | }, 1123 | "outputs": [ 1124 | { 1125 | "name": "stdout", 1126 | "output_type": "stream", 1127 | "text": [ 1128 | "x =\n", 1129 | "[[1.]\n", 1130 | " [1.]\n", 1131 | " [1.]]\n", 1132 | "y =\n", 1133 | "[[1. 1. 1.]]\n" 1134 | ] 1135 | } 1136 | ], 1137 | "source": [ 1138 | "x = np.ones((3,1)) # column vector\n", 1139 | "print('x ='); print(x)\n", 1140 | "y = np.ones((1,3)) # row vector\n", 1141 | "print('y ='); print(y)" 1142 | ] 1143 | }, 1144 | { 1145 | "cell_type": "markdown", 1146 | "metadata": {}, 1147 | "source": [ 1148 | "Row/column vectors are like row/column matrix. We have to use two indices to access the elements of such row/column vectors.\n", 1149 | "\n", 1150 | "Here we access elements of a column vector." 1151 | ] 1152 | }, 1153 | { 1154 | "cell_type": "code", 1155 | "execution_count": 40, 1156 | "metadata": {}, 1157 | "outputs": [ 1158 | { 1159 | "name": "stdout", 1160 | "output_type": "stream", 1161 | "text": [ 1162 | "1.0\n", 1163 | "1.0\n", 1164 | "1.0\n" 1165 | ] 1166 | } 1167 | ], 1168 | "source": [ 1169 | "print(x[0][0]) # or x[0,0] \n", 1170 | "print(x[1][0])\n", 1171 | "print(x[2][0])" 1172 | ] 1173 | }, 1174 | { 1175 | "cell_type": "markdown", 1176 | "metadata": {}, 1177 | "source": [ 1178 | "`x[0]` gives an array for the first row." 1179 | ] 1180 | }, 1181 | { 1182 | "cell_type": "code", 1183 | "execution_count": 41, 1184 | "metadata": {}, 1185 | "outputs": [ 1186 | { 1187 | "name": "stdout", 1188 | "output_type": "stream", 1189 | "text": [ 1190 | "First row of x = [1.] \n", 1191 | "Element in first row = 1.0 \n" 1192 | ] 1193 | } 1194 | ], 1195 | "source": [ 1196 | "print('First row of x =',x[0], type(x[0]))\n", 1197 | "print('Element in first row =',x[0][0], type(x[0][0]))" 1198 | ] 1199 | }, 1200 | { 1201 | "cell_type": "markdown", 1202 | "metadata": {}, 1203 | "source": [ 1204 | "## Accessing portions of arrays\n", 1205 | "Array of 10 elements\n", 1206 | "\n", 1207 | "| x[0] | x[1] | x[2] | x[3] | x[4] | x[5] | x[6] | x[7] | x[8] | x[9] |\n", 1208 | "|:----:|:----:|:----:|:----:|:----:|:----:|:----:|:----:|:----:|:----:|\n", 1209 | "| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |\n", 1210 | "|x[-10]| x[-9]| x[-8]| x[-7]| x[-6]| x[-5]| x[-4]| x[-3]| x[-2]|x[-1] |\n" 1211 | ] 1212 | }, 1213 | { 1214 | "cell_type": "code", 1215 | "execution_count": 42, 1216 | "metadata": {}, 1217 | "outputs": [ 1218 | { 1219 | "name": "stdout", 1220 | "output_type": "stream", 1221 | "text": [ 1222 | "[0. 1. 2. 3. 4. 5. 6. 7. 8. 9.]\n" 1223 | ] 1224 | } 1225 | ], 1226 | "source": [ 1227 | "x = np.linspace(0,9,10)\n", 1228 | "print(x)" 1229 | ] 1230 | }, 1231 | { 1232 | "cell_type": "markdown", 1233 | "metadata": {}, 1234 | "source": [ 1235 | "Get elements ```x[2],...,x[5]```" 1236 | ] 1237 | }, 1238 | { 1239 | "cell_type": "code", 1240 | "execution_count": 43, 1241 | "metadata": {}, 1242 | "outputs": [ 1243 | { 1244 | "name": "stdout", 1245 | "output_type": "stream", 1246 | "text": [ 1247 | "[2. 3. 4. 5.]\n" 1248 | ] 1249 | } 1250 | ], 1251 | "source": [ 1252 | "print(x[2:6])" 1253 | ] 1254 | }, 1255 | { 1256 | "cell_type": "markdown", 1257 | "metadata": {}, 1258 | "source": [ 1259 | "Hence ```x[m:n]``` gives the elements ```x[m],x[m+1],...,x[n-1]```.\n", 1260 | "\n", 1261 | "Get elements from ```x[5]``` upto the last element" 1262 | ] 1263 | }, 1264 | { 1265 | "cell_type": "code", 1266 | "execution_count": 44, 1267 | "metadata": {}, 1268 | "outputs": [ 1269 | { 1270 | "name": "stdout", 1271 | "output_type": "stream", 1272 | "text": [ 1273 | "[5. 6. 7. 8. 9.]\n" 1274 | ] 1275 | } 1276 | ], 1277 | "source": [ 1278 | "print(x[5:])" 1279 | ] 1280 | }, 1281 | { 1282 | "cell_type": "markdown", 1283 | "metadata": {}, 1284 | "source": [ 1285 | "Get the last element" 1286 | ] 1287 | }, 1288 | { 1289 | "cell_type": "code", 1290 | "execution_count": 45, 1291 | "metadata": {}, 1292 | "outputs": [ 1293 | { 1294 | "name": "stdout", 1295 | "output_type": "stream", 1296 | "text": [ 1297 | "9.0\n" 1298 | ] 1299 | } 1300 | ], 1301 | "source": [ 1302 | "print(x[-1])" 1303 | ] 1304 | }, 1305 | { 1306 | "cell_type": "markdown", 1307 | "metadata": {}, 1308 | "source": [ 1309 | "Get element ```x[5]``` upto last but one element" 1310 | ] 1311 | }, 1312 | { 1313 | "cell_type": "code", 1314 | "execution_count": 46, 1315 | "metadata": {}, 1316 | "outputs": [ 1317 | { 1318 | "name": "stdout", 1319 | "output_type": "stream", 1320 | "text": [ 1321 | "[5. 6. 7. 8.]\n" 1322 | ] 1323 | } 1324 | ], 1325 | "source": [ 1326 | "print(x[5:-1])" 1327 | ] 1328 | }, 1329 | { 1330 | "cell_type": "markdown", 1331 | "metadata": {}, 1332 | "source": [ 1333 | "Access every alternate element of array starting from beginning `x[0]`" 1334 | ] 1335 | }, 1336 | { 1337 | "cell_type": "code", 1338 | "execution_count": 47, 1339 | "metadata": {}, 1340 | "outputs": [ 1341 | { 1342 | "name": "stdout", 1343 | "output_type": "stream", 1344 | "text": [ 1345 | "[0. 2. 4. 6. 8.]\n" 1346 | ] 1347 | } 1348 | ], 1349 | "source": [ 1350 | "print(x[0::2])" 1351 | ] 1352 | }, 1353 | { 1354 | "cell_type": "markdown", 1355 | "metadata": {}, 1356 | "source": [ 1357 | "and starting from `x[1]`" 1358 | ] 1359 | }, 1360 | { 1361 | "cell_type": "code", 1362 | "execution_count": 48, 1363 | "metadata": {}, 1364 | "outputs": [ 1365 | { 1366 | "name": "stdout", 1367 | "output_type": "stream", 1368 | "text": [ 1369 | "[1. 3. 5. 7. 9.]\n" 1370 | ] 1371 | } 1372 | ], 1373 | "source": [ 1374 | "print(x[1::2])" 1375 | ] 1376 | }, 1377 | { 1378 | "cell_type": "markdown", 1379 | "metadata": {}, 1380 | "source": [ 1381 | "These operations work on multi dimensional arrays also." 1382 | ] 1383 | }, 1384 | { 1385 | "cell_type": "code", 1386 | "execution_count": 49, 1387 | "metadata": {}, 1388 | "outputs": [ 1389 | { 1390 | "name": "stdout", 1391 | "output_type": "stream", 1392 | "text": [ 1393 | "[[0.12959794 0.66961518 0.16943047 0.08736698]\n", 1394 | " [0.37692085 0.15571653 0.78377556 0.83416156]\n", 1395 | " [0.86019997 0.14520107 0.90728314 0.81171741]]\n" 1396 | ] 1397 | } 1398 | ], 1399 | "source": [ 1400 | "A = np.random.rand(3,4)\n", 1401 | "print(A)" 1402 | ] 1403 | }, 1404 | { 1405 | "cell_type": "code", 1406 | "execution_count": 50, 1407 | "metadata": {}, 1408 | "outputs": [ 1409 | { 1410 | "name": "stdout", 1411 | "output_type": "stream", 1412 | "text": [ 1413 | "[0.12959794 0.66961518 0.16943047 0.08736698]\n" 1414 | ] 1415 | } 1416 | ], 1417 | "source": [ 1418 | "print(A[0,:]) # 0'th row" 1419 | ] 1420 | }, 1421 | { 1422 | "cell_type": "code", 1423 | "execution_count": 51, 1424 | "metadata": {}, 1425 | "outputs": [ 1426 | { 1427 | "name": "stdout", 1428 | "output_type": "stream", 1429 | "text": [ 1430 | "[0.12959794 0.37692085 0.86019997]\n" 1431 | ] 1432 | } 1433 | ], 1434 | "source": [ 1435 | "print(A[:,0]) # 0'th column" 1436 | ] 1437 | }, 1438 | { 1439 | "cell_type": "code", 1440 | "execution_count": 52, 1441 | "metadata": {}, 1442 | "outputs": [ 1443 | { 1444 | "name": "stdout", 1445 | "output_type": "stream", 1446 | "text": [ 1447 | "[[0.12959794 0.66961518 0.16943047]\n", 1448 | " [0.37692085 0.15571653 0.78377556]]\n" 1449 | ] 1450 | } 1451 | ], 1452 | "source": [ 1453 | "print(A[0:2,0:3]) # print submatrix" 1454 | ] 1455 | }, 1456 | { 1457 | "cell_type": "code", 1458 | "execution_count": 53, 1459 | "metadata": {}, 1460 | "outputs": [ 1461 | { 1462 | "name": "stdout", 1463 | "output_type": "stream", 1464 | "text": [ 1465 | "[[0. 0. 0. 0. ]\n", 1466 | " [0.37692085 0.15571653 0.78377556 0.83416156]\n", 1467 | " [0.86019997 0.14520107 0.90728314 0.81171741]]\n" 1468 | ] 1469 | } 1470 | ], 1471 | "source": [ 1472 | "A[0,:] = 0.0 # zero out zeroth row\n", 1473 | "print(A)" 1474 | ] 1475 | }, 1476 | { 1477 | "cell_type": "markdown", 1478 | "metadata": {}, 1479 | "source": [ 1480 | "## Arithmetic operations on arrays" 1481 | ] 1482 | }, 1483 | { 1484 | "cell_type": "markdown", 1485 | "metadata": {}, 1486 | "source": [ 1487 | "Some arithmetic operations act element-wise" 1488 | ] 1489 | }, 1490 | { 1491 | "cell_type": "code", 1492 | "execution_count": 54, 1493 | "metadata": {}, 1494 | "outputs": [ 1495 | { 1496 | "name": "stdout", 1497 | "output_type": "stream", 1498 | "text": [ 1499 | "[ 4. 10. 18.]\n" 1500 | ] 1501 | } 1502 | ], 1503 | "source": [ 1504 | "x = np.array([1.0, 2.0, 3.0])\n", 1505 | "y = np.array([4.0, 5.0, 6.0])\n", 1506 | "print(x*y) # multiply" 1507 | ] 1508 | }, 1509 | { 1510 | "cell_type": "code", 1511 | "execution_count": 55, 1512 | "metadata": {}, 1513 | "outputs": [ 1514 | { 1515 | "name": "stdout", 1516 | "output_type": "stream", 1517 | "text": [ 1518 | "[0.25 0.4 0.5 ]\n" 1519 | ] 1520 | } 1521 | ], 1522 | "source": [ 1523 | "print(x/y) # divide" 1524 | ] 1525 | }, 1526 | { 1527 | "cell_type": "code", 1528 | "execution_count": 56, 1529 | "metadata": {}, 1530 | "outputs": [ 1531 | { 1532 | "name": "stdout", 1533 | "output_type": "stream", 1534 | "text": [ 1535 | "[ 4. 25. 216.]\n" 1536 | ] 1537 | } 1538 | ], 1539 | "source": [ 1540 | "print(y**x) # exponentiation" 1541 | ] 1542 | }, 1543 | { 1544 | "cell_type": "code", 1545 | "execution_count": 57, 1546 | "metadata": {}, 1547 | "outputs": [ 1548 | { 1549 | "name": "stdout", 1550 | "output_type": "stream", 1551 | "text": [ 1552 | "[[1. 2. 3.]\n", 1553 | " [1. 2. 3.]\n", 1554 | " [1. 2. 3.]]\n" 1555 | ] 1556 | } 1557 | ], 1558 | "source": [ 1559 | "A = np.ones((3,3))\n", 1560 | "print(A*x)" 1561 | ] 1562 | }, 1563 | { 1564 | "cell_type": "markdown", 1565 | "metadata": {}, 1566 | "source": [ 1567 | "If ```A``` and ```x``` are arrays, then ```A*x``` does not give matrix-vector product. For that use ```dot```" 1568 | ] 1569 | }, 1570 | { 1571 | "cell_type": "code", 1572 | "execution_count": 58, 1573 | "metadata": {}, 1574 | "outputs": [ 1575 | { 1576 | "name": "stdout", 1577 | "output_type": "stream", 1578 | "text": [ 1579 | "[6. 6. 6.]\n" 1580 | ] 1581 | } 1582 | ], 1583 | "source": [ 1584 | "print(A.dot(x))" 1585 | ] 1586 | }, 1587 | { 1588 | "cell_type": "markdown", 1589 | "metadata": {}, 1590 | "source": [ 1591 | "or equivalently" 1592 | ] 1593 | }, 1594 | { 1595 | "cell_type": "code", 1596 | "execution_count": 59, 1597 | "metadata": {}, 1598 | "outputs": [ 1599 | { 1600 | "name": "stdout", 1601 | "output_type": "stream", 1602 | "text": [ 1603 | "[6. 6. 6.]\n" 1604 | ] 1605 | } 1606 | ], 1607 | "source": [ 1608 | "print(np.dot(A,x))" 1609 | ] 1610 | }, 1611 | { 1612 | "cell_type": "markdown", 1613 | "metadata": {}, 1614 | "source": [ 1615 | "In Python3 versions, we can use `@` to achieve matrix operations" 1616 | ] 1617 | }, 1618 | { 1619 | "cell_type": "code", 1620 | "execution_count": 60, 1621 | "metadata": {}, 1622 | "outputs": [ 1623 | { 1624 | "name": "stdout", 1625 | "output_type": "stream", 1626 | "text": [ 1627 | "[6. 6. 6.]\n" 1628 | ] 1629 | } 1630 | ], 1631 | "source": [ 1632 | "print(A@x)" 1633 | ] 1634 | }, 1635 | { 1636 | "cell_type": "markdown", 1637 | "metadata": {}, 1638 | "source": [ 1639 | "We can of course do matrix-matrix products using ```dot``` or ```@```" 1640 | ] 1641 | }, 1642 | { 1643 | "cell_type": "code", 1644 | "execution_count": 61, 1645 | "metadata": {}, 1646 | "outputs": [ 1647 | { 1648 | "name": "stdout", 1649 | "output_type": "stream", 1650 | "text": [ 1651 | "A =\n", 1652 | " [[1. 1. 1.]\n", 1653 | " [1. 1. 1.]\n", 1654 | " [1. 1. 1.]]\n", 1655 | "B =\n", 1656 | " [[2. 2. 2.]\n", 1657 | " [2. 2. 2.]\n", 1658 | " [2. 2. 2.]]\n", 1659 | "A*B =\n", 1660 | " [[6. 6. 6.]\n", 1661 | " [6. 6. 6.]\n", 1662 | " [6. 6. 6.]]\n" 1663 | ] 1664 | } 1665 | ], 1666 | "source": [ 1667 | "A = np.ones((3,3))\n", 1668 | "B = 2*A\n", 1669 | "print('A =\\n',A)\n", 1670 | "print('B =\\n',B)\n", 1671 | "print('A*B =\\n',A@B)" 1672 | ] 1673 | }, 1674 | { 1675 | "cell_type": "markdown", 1676 | "metadata": {}, 1677 | "source": [ 1678 | "On vectors, `@` performs dot product, i.e., `x@y = dot(x,y)`" 1679 | ] 1680 | }, 1681 | { 1682 | "cell_type": "code", 1683 | "execution_count": 62, 1684 | "metadata": {}, 1685 | "outputs": [ 1686 | { 1687 | "name": "stdout", 1688 | "output_type": "stream", 1689 | "text": [ 1690 | "9\n" 1691 | ] 1692 | } 1693 | ], 1694 | "source": [ 1695 | "x = np.array([1,1,1])\n", 1696 | "y = np.array([2,3,4])\n", 1697 | "print(x@y)" 1698 | ] 1699 | }, 1700 | { 1701 | "cell_type": "markdown", 1702 | "metadata": {}, 1703 | "source": [ 1704 | "## Some matrix/vector functions" 1705 | ] 1706 | }, 1707 | { 1708 | "cell_type": "code", 1709 | "execution_count": 63, 1710 | "metadata": {}, 1711 | "outputs": [ 1712 | { 1713 | "name": "stdout", 1714 | "output_type": "stream", 1715 | "text": [ 1716 | "min = -3\n", 1717 | "max = 3\n", 1718 | "abs min = 0\n", 1719 | "abs max = 3\n", 1720 | "sum = 0\n", 1721 | "dot = 28\n", 1722 | "dot = 28\n" 1723 | ] 1724 | } 1725 | ], 1726 | "source": [ 1727 | "x = np.array([-3,-2,-1,0,1,2,3])\n", 1728 | "print('min = ',np.min(x))\n", 1729 | "print('max = ',np.max(x))\n", 1730 | "print('abs min = ',np.abs(x).min()) # np.min(np.abs(x))\n", 1731 | "print('abs max = ',np.abs(x).max()) # np.max(np.abs(x))\n", 1732 | "print('sum = ',np.sum(x))\n", 1733 | "print('dot = ',np.dot(x,x)) \n", 1734 | "print('dot = ',np.sum(x*x))" 1735 | ] 1736 | }, 1737 | { 1738 | "cell_type": "markdown", 1739 | "metadata": {}, 1740 | "source": [ 1741 | "Note that `np.sum(x*x)` gives\n", 1742 | "\n", 1743 | "$$\n", 1744 | "\\sum_{i=0}^{n-1} x_i^2\n", 1745 | "$$\n", 1746 | "\n", 1747 | "We can compute vector norms using [numpy.linalg.norm](https://numpy.org/doc/stable/reference/generated/numpy.linalg.norm.html) (also see [scipy.linalg.norm](https://docs.scipy.org/doc/scipy/reference/generated/scipy.linalg.norm.html))" 1748 | ] 1749 | }, 1750 | { 1751 | "cell_type": "code", 1752 | "execution_count": 64, 1753 | "metadata": {}, 1754 | "outputs": [ 1755 | { 1756 | "name": "stdout", 1757 | "output_type": "stream", 1758 | "text": [ 1759 | "5.291502622129181\n", 1760 | "5.291502622129181\n", 1761 | "12.0\n", 1762 | "3.0\n" 1763 | ] 1764 | } 1765 | ], 1766 | "source": [ 1767 | "from numpy.linalg import norm\n", 1768 | "print(norm(x)) # L2 norm\n", 1769 | "print(norm(x,2)) # L2 norm\n", 1770 | "print(norm(x,1)) # L1 norm\n", 1771 | "print(norm(x,np.inf)) # Linf norm" 1772 | ] 1773 | }, 1774 | { 1775 | "cell_type": "markdown", 1776 | "metadata": {}, 1777 | "source": [ 1778 | "or import the `linalg` module and use methods inside it." 1779 | ] 1780 | }, 1781 | { 1782 | "cell_type": "code", 1783 | "execution_count": 65, 1784 | "metadata": {}, 1785 | "outputs": [ 1786 | { 1787 | "name": "stdout", 1788 | "output_type": "stream", 1789 | "text": [ 1790 | "5.291502622129181\n", 1791 | "5.291502622129181\n", 1792 | "12.0\n", 1793 | "3.0\n" 1794 | ] 1795 | } 1796 | ], 1797 | "source": [ 1798 | "import numpy.linalg as la\n", 1799 | "print(la.norm(x)) # L2 norm\n", 1800 | "print(la.norm(x,2)) # L2 norm\n", 1801 | "print(la.norm(x,1)) # L1 norm\n", 1802 | "print(la.norm(x,np.inf)) # Linf norm" 1803 | ] 1804 | }, 1805 | { 1806 | "cell_type": "markdown", 1807 | "metadata": {}, 1808 | "source": [ 1809 | "These methods work on 2-d arrays treated as matrices." 1810 | ] 1811 | }, 1812 | { 1813 | "cell_type": "code", 1814 | "execution_count": 66, 1815 | "metadata": {}, 1816 | "outputs": [ 1817 | { 1818 | "name": "stdout", 1819 | "output_type": "stream", 1820 | "text": [ 1821 | "[[ 0.17485102 -0.8575162 -0.20701543]\n", 1822 | " [ 0.71819432 -0.05317152 0.96908932]\n", 1823 | " [-0.881519 0.96853918 0.82358206]]\n" 1824 | ] 1825 | } 1826 | ], 1827 | "source": [ 1828 | "A = 2*np.random.rand(3,3) - 1\n", 1829 | "print(A)" 1830 | ] 1831 | }, 1832 | { 1833 | "cell_type": "code", 1834 | "execution_count": 67, 1835 | "metadata": {}, 1836 | "outputs": [ 1837 | { 1838 | "name": "stdout", 1839 | "output_type": "stream", 1840 | "text": [ 1841 | "min = -0.8815189958181449\n", 1842 | "max = 0.9690893220640329\n", 1843 | "abs min = 0.05317152133344938\n", 1844 | "abs max = 0.9690893220640329\n", 1845 | "sum = 1.6550337486101392\n", 1846 | "Frob norm = 2.1586935856265157\n", 1847 | "L1 norm = 1.9996868183314138\n", 1848 | "L2 norm = 1.7350159135966798\n", 1849 | "Linf norm = 2.6736402331840123\n" 1850 | ] 1851 | } 1852 | ], 1853 | "source": [ 1854 | "print('min = ',np.min(A))\n", 1855 | "print('max = ',np.max(A))\n", 1856 | "print('abs min = ',np.abs(A).min()) # np.min(np.abs(x))\n", 1857 | "print('abs max = ',np.abs(A).max()) # np.max(np.abs(x))\n", 1858 | "print('sum = ',np.sum(A))\n", 1859 | "print('Frob norm = ',la.norm(A)) # Frobenius norm\n", 1860 | "print('L1 norm = ',la.norm(A,1)) # L1 norm\n", 1861 | "print('L2 norm = ',la.norm(A,2)) # L2 norm\n", 1862 | "print('Linf norm = ',la.norm(A,np.inf)) # Linf norm" 1863 | ] 1864 | }, 1865 | { 1866 | "cell_type": "markdown", 1867 | "metadata": {}, 1868 | "source": [ 1869 | "## Example: Matrix-vector product" 1870 | ] 1871 | }, 1872 | { 1873 | "cell_type": "markdown", 1874 | "metadata": {}, 1875 | "source": [ 1876 | "Let\n", 1877 | "\n", 1878 | "$$\n", 1879 | "x \\in \\re^n, \\qquad A \\in \\re^{m \\times n}, \\qquad y = A x \\in \\re^m\n", 1880 | "$$\n", 1881 | "\n", 1882 | "We can compute this element-wise\n", 1883 | "\n", 1884 | "$$\n", 1885 | "y_i = \\sum_{j=0}^{n-1} A_{ij} x_j, \\qquad 0 \\le i \\le m-1\n", 1886 | "$$" 1887 | ] 1888 | }, 1889 | { 1890 | "cell_type": "code", 1891 | "execution_count": 68, 1892 | "metadata": {}, 1893 | "outputs": [], 1894 | "source": [ 1895 | "m, n = 5, 10\n", 1896 | "x = np.random.rand(n)\n", 1897 | "A = np.random.rand(m,n)\n", 1898 | "y = np.zeros(m) # Important to set to zero\n", 1899 | "assert A.shape[1] == len(x) and len(y) == A.shape[0]\n", 1900 | "for i in range(m):\n", 1901 | " for j in range(n):\n", 1902 | " y[i] += A[i,j]*x[j]" 1903 | ] 1904 | }, 1905 | { 1906 | "cell_type": "markdown", 1907 | "metadata": {}, 1908 | "source": [ 1909 | "We can verify that our result is correct by computing $\\| y - A x\\|_\\infty$" 1910 | ] 1911 | }, 1912 | { 1913 | "cell_type": "code", 1914 | "execution_count": 69, 1915 | "metadata": {}, 1916 | "outputs": [ 1917 | { 1918 | "name": "stdout", 1919 | "output_type": "stream", 1920 | "text": [ 1921 | "2.220446049250313e-16\n" 1922 | ] 1923 | } 1924 | ], 1925 | "source": [ 1926 | "print(np.linalg.norm(y-A@x, np.inf))" 1927 | ] 1928 | }, 1929 | { 1930 | "cell_type": "markdown", 1931 | "metadata": {}, 1932 | "source": [ 1933 | "We can also compute the product column-wise. Let\n", 1934 | "\n", 1935 | "$$\n", 1936 | "A_{:,j} = \\textrm{j'th column of A} \\in \\re^m\n", 1937 | "$$\n", 1938 | "\n", 1939 | "Then the matrix-vector product can also be written as\n", 1940 | "\n", 1941 | "$$\n", 1942 | "y = \\sum_{j=0}^{n-1} A_{:,j} x_j\n", 1943 | "$$\n", 1944 | "\n", 1945 | "**Warning**: This may have inefficient memory access since by default, numpy arrays have column-major ordering, see below." 1946 | ] 1947 | }, 1948 | { 1949 | "cell_type": "code", 1950 | "execution_count": 70, 1951 | "metadata": {}, 1952 | "outputs": [ 1953 | { 1954 | "name": "stdout", 1955 | "output_type": "stream", 1956 | "text": [ 1957 | "2.220446049250313e-16\n" 1958 | ] 1959 | } 1960 | ], 1961 | "source": [ 1962 | "y[:] = 0.0\n", 1963 | "for j in range(n):\n", 1964 | " y += A[:,j]*x[j]\n", 1965 | "\n", 1966 | "# Now check the result\n", 1967 | "print(np.linalg.norm(y-A@x, np.inf))" 1968 | ] 1969 | }, 1970 | { 1971 | "cell_type": "markdown", 1972 | "metadata": {}, 1973 | "source": [ 1974 | "## Example: Matrix-Matrix product" 1975 | ] 1976 | }, 1977 | { 1978 | "cell_type": "markdown", 1979 | "metadata": {}, 1980 | "source": [ 1981 | "If $A \\in \\re^{m\\times n}$ and $B \\in \\re^{n \\times p}$ then $C = AB \\in \\re^{m \\times p}$ is given by\n", 1982 | "\n", 1983 | "$$\n", 1984 | "C_{ij} = \\sum_{k=0}^{n-1} A_{ik} B_{kj}, \\qquad 0 \\le i \\le m-1, \\quad 0 \\le j \\le p-1\n", 1985 | "$$" 1986 | ] 1987 | }, 1988 | { 1989 | "cell_type": "code", 1990 | "execution_count": 71, 1991 | "metadata": {}, 1992 | "outputs": [], 1993 | "source": [ 1994 | "m,n,p = 10,8,6\n", 1995 | "A = np.random.rand(m,n)\n", 1996 | "B = np.random.rand(n,p)\n", 1997 | "C = np.zeros((m,p))\n", 1998 | "assert A.shape[1] == B.shape[0]\n", 1999 | "for i in range(m):\n", 2000 | " for j in range(p):\n", 2001 | " for k in range(n):\n", 2002 | " C[i,j] += A[i,k]*B[k,j]" 2003 | ] 2004 | }, 2005 | { 2006 | "cell_type": "markdown", 2007 | "metadata": {}, 2008 | "source": [ 2009 | "Let us verify the result is correct by computing\n", 2010 | "\n", 2011 | "$$\n", 2012 | "|C-AB|_\\infty = \\max_{i,j} |C_{ij} - (AB)_{ij}|\n", 2013 | "$$\n", 2014 | "\n", 2015 | "using `@` operator" 2016 | ] 2017 | }, 2018 | { 2019 | "cell_type": "code", 2020 | "execution_count": 72, 2021 | "metadata": {}, 2022 | "outputs": [ 2023 | { 2024 | "name": "stdout", 2025 | "output_type": "stream", 2026 | "text": [ 2027 | "4.440892098500626e-16\n" 2028 | ] 2029 | } 2030 | ], 2031 | "source": [ 2032 | "print(np.abs(C - A@B).max())" 2033 | ] 2034 | }, 2035 | { 2036 | "cell_type": "markdown", 2037 | "metadata": {}, 2038 | "source": [ 2039 | "Another view-point is the following\n", 2040 | "\n", 2041 | "$$\n", 2042 | "C_{ij} = (\\textrm{i'th row of A}) \\cdot (\\textrm{j'th column of B})\n", 2043 | "$$" 2044 | ] 2045 | }, 2046 | { 2047 | "cell_type": "code", 2048 | "execution_count": 73, 2049 | "metadata": { 2050 | "scrolled": true 2051 | }, 2052 | "outputs": [ 2053 | { 2054 | "name": "stdout", 2055 | "output_type": "stream", 2056 | "text": [ 2057 | "0.0\n" 2058 | ] 2059 | } 2060 | ], 2061 | "source": [ 2062 | "for i in range(m):\n", 2063 | " for j in range(p):\n", 2064 | " C[i,j] = A[i,:] @ B[:,j]\n", 2065 | "\n", 2066 | "# Now check the result\n", 2067 | "print(np.abs(C - A@B).max())" 2068 | ] 2069 | }, 2070 | { 2071 | "cell_type": "markdown", 2072 | "metadata": {}, 2073 | "source": [ 2074 | "## Outer product of two vectors\n", 2075 | "\n", 2076 | "Given $a \\in \\re^m$ and $b \\in \\re^n$, both considered as column vectors, their outer product\n", 2077 | "\n", 2078 | "$$\n", 2079 | "A = a b^\\top = \n", 2080 | "\\begin{bmatrix} \n", 2081 | "| \\\\\n", 2082 | "a \\\\\n", 2083 | "|\n", 2084 | "\\end{bmatrix} \n", 2085 | "\\begin{bmatrix}\n", 2086 | "- b^\\top -\n", 2087 | "\\end{bmatrix}\n", 2088 | "=\n", 2089 | "\\begin{bmatrix} \n", 2090 | "| & | & & | \\\\\n", 2091 | "a b_0 & a b_1 & \\ldots & a b_{n-1} \\\\\n", 2092 | "| & | & & | \n", 2093 | "\\end{bmatrix} \\in \\re^{m \\times n}\n", 2094 | "$$\n", 2095 | "\n", 2096 | "is an $m \\times n$ matrix with elements\n", 2097 | "\n", 2098 | "$$\n", 2099 | "A_{ij} = a_i b_j, \\qquad 0 \\le i \\le m-1, \\quad 0 \\le j \\le n-1\n", 2100 | "$$" 2101 | ] 2102 | }, 2103 | { 2104 | "cell_type": "code", 2105 | "execution_count": 74, 2106 | "metadata": {}, 2107 | "outputs": [ 2108 | { 2109 | "name": "stdout", 2110 | "output_type": "stream", 2111 | "text": [ 2112 | "A.shape = (3, 2)\n", 2113 | "A = \n", 2114 | " [[1 2]\n", 2115 | " [2 4]\n", 2116 | " [3 6]]\n" 2117 | ] 2118 | } 2119 | ], 2120 | "source": [ 2121 | "a = np.array([1,2,3])\n", 2122 | "b = np.array([1,2])\n", 2123 | "A = np.outer(a,b)\n", 2124 | "print('A.shape = ', A.shape)\n", 2125 | "print('A = \\n', A)" 2126 | ] 2127 | }, 2128 | { 2129 | "cell_type": "markdown", 2130 | "metadata": {}, 2131 | "source": [ 2132 | "## Math functions\n", 2133 | "\n", 2134 | "Numpy provides standard functions like `sin`, `cos`, `log`, etc. which can act on arrays in an element-by-element manner. This is not the case for functions in `math` module, which can only take scalar arguments." 2135 | ] 2136 | }, 2137 | { 2138 | "cell_type": "code", 2139 | "execution_count": 75, 2140 | "metadata": {}, 2141 | "outputs": [ 2142 | { 2143 | "name": "stdout", 2144 | "output_type": "stream", 2145 | "text": [ 2146 | "x = [0. 1.57079633 3.14159265 4.71238898 6.28318531]\n", 2147 | "y = [ 0.0000000e+00 1.0000000e+00 1.2246468e-16 -1.0000000e+00\n", 2148 | " -2.4492936e-16]\n" 2149 | ] 2150 | } 2151 | ], 2152 | "source": [ 2153 | "x = np.linspace(0.0, 2.0*np.pi, 5)\n", 2154 | "y = np.sin(x)\n", 2155 | "print('x =',x)\n", 2156 | "print('y =',y)" 2157 | ] 2158 | }, 2159 | { 2160 | "cell_type": "code", 2161 | "execution_count": 76, 2162 | "metadata": {}, 2163 | "outputs": [ 2164 | { 2165 | "name": "stdout", 2166 | "output_type": "stream", 2167 | "text": [ 2168 | "A =\n", 2169 | " [[0.87028937 0.40512342 0.770125 0.21924173 0.43899112]\n", 2170 | " [0.37848775 0.01685 0.72877089 0.76928039 0.87471029]\n", 2171 | " [0.25881596 0.24314473 0.27993099 0.93839618 0.00623875]\n", 2172 | " [0.89917847 0.76956031 0.34401654 0.01238547 0.38253625]\n", 2173 | " [0.4812954 0.84170611 0.99184085 0.4893441 0.54421624]]\n", 2174 | "Y =\n", 2175 | " [[0.7645155 0.3941322 0.69622497 0.21748956 0.42502646]\n", 2176 | " [0.36951568 0.0168492 0.66595323 0.69561844 0.76735777]\n", 2177 | " [0.25593613 0.24075604 0.27628933 0.80661115 0.00623871]\n", 2178 | " [0.78281597 0.69581951 0.337271 0.01238516 0.3732746 ]\n", 2179 | " [0.4629278 0.7457808 0.83703462 0.47004706 0.51774772]]\n" 2180 | ] 2181 | } 2182 | ], 2183 | "source": [ 2184 | "A = np.random.rand(5,5) # 5x5 matrix\n", 2185 | "Y = np.sin(A)\n", 2186 | "print('A =\\n',A)\n", 2187 | "print('Y =\\n',Y)" 2188 | ] 2189 | }, 2190 | { 2191 | "cell_type": "markdown", 2192 | "metadata": {}, 2193 | "source": [ 2194 | "## Memory ordering in arrays*\n", 2195 | "By default, the ordering is same as in C/C++, the inner-most index is the fastest running one. For example, if we have an array of size (2,3), they are stored in memory in this order\n", 2196 | "\n", 2197 | "```\n", 2198 | "a[0,0], a[0,1], a[0,2], a[1,0], a[1,1], a[1,2]\n", 2199 | "```\n", 2200 | "\n", 2201 | "i.e.,\n", 2202 | "\n", 2203 | "```\n", 2204 | "a[0,0] --> a[0,1] --> a[0,2]\n", 2205 | " |\n", 2206 | " |----------<----------|\n", 2207 | " |\n", 2208 | "a[1,0] --> a[1,1] --> a[1,2]\n", 2209 | "```" 2210 | ] 2211 | }, 2212 | { 2213 | "cell_type": "code", 2214 | "execution_count": 77, 2215 | "metadata": {}, 2216 | "outputs": [ 2217 | { 2218 | "name": "stdout", 2219 | "output_type": "stream", 2220 | "text": [ 2221 | "Row contiguous = True\n", 2222 | "Col contiguous = False\n" 2223 | ] 2224 | }, 2225 | { 2226 | "data": { 2227 | "text/plain": [ 2228 | " C_CONTIGUOUS : True\n", 2229 | " F_CONTIGUOUS : False\n", 2230 | " OWNDATA : True\n", 2231 | " WRITEABLE : True\n", 2232 | " ALIGNED : True\n", 2233 | " WRITEBACKIFCOPY : False" 2234 | ] 2235 | }, 2236 | "execution_count": 77, 2237 | "metadata": {}, 2238 | "output_type": "execute_result" 2239 | } 2240 | ], 2241 | "source": [ 2242 | "a = np.array([[1,2,3], [4,5,6]])\n", 2243 | "print('Row contiguous =', a[0,:].data.contiguous)\n", 2244 | "print('Col contiguous =', a[:,0].data.contiguous)\n", 2245 | "a.flags" 2246 | ] 2247 | }, 2248 | { 2249 | "cell_type": "markdown", 2250 | "metadata": {}, 2251 | "source": [ 2252 | "To get fortran style ordering, where the outer-most index is the fastest running one, which corresponds to the following layout in memory\n", 2253 | "\n", 2254 | "```\n", 2255 | "a[0,0], a[1,0], a[0,1], a[1,1], a[0,2], a[1,2]\n", 2256 | "```\n", 2257 | "\n", 2258 | "i.e.,\n", 2259 | "\n", 2260 | "```\n", 2261 | "a[0,0] -- a[0,1] -- a[0,2]\n", 2262 | " | | | | | \n", 2263 | " v ^ v ^ v\n", 2264 | " | | | | |\n", 2265 | "a[1,0] -- a[1,1] -- a[1,2]\n", 2266 | "```\n", 2267 | "\n", 2268 | "create like this" 2269 | ] 2270 | }, 2271 | { 2272 | "cell_type": "code", 2273 | "execution_count": 78, 2274 | "metadata": {}, 2275 | "outputs": [ 2276 | { 2277 | "name": "stdout", 2278 | "output_type": "stream", 2279 | "text": [ 2280 | "Row contiguous = False\n", 2281 | "Col contiguous = True\n" 2282 | ] 2283 | }, 2284 | { 2285 | "data": { 2286 | "text/plain": [ 2287 | " C_CONTIGUOUS : False\n", 2288 | " F_CONTIGUOUS : True\n", 2289 | " OWNDATA : True\n", 2290 | " WRITEABLE : True\n", 2291 | " ALIGNED : True\n", 2292 | " WRITEBACKIFCOPY : False" 2293 | ] 2294 | }, 2295 | "execution_count": 78, 2296 | "metadata": {}, 2297 | "output_type": "execute_result" 2298 | } 2299 | ], 2300 | "source": [ 2301 | "b = np.array([[1,2,3], [4,5,6]], order='F')\n", 2302 | "print('Row contiguous =', b[0,:].data.contiguous)\n", 2303 | "print('Col contiguous =', b[:,0].data.contiguous)\n", 2304 | "b.flags" 2305 | ] 2306 | }, 2307 | { 2308 | "cell_type": "markdown", 2309 | "metadata": {}, 2310 | "source": [ 2311 | "## Tensor product array: meshgrid" 2312 | ] 2313 | }, 2314 | { 2315 | "cell_type": "code", 2316 | "execution_count": 79, 2317 | "metadata": {}, 2318 | "outputs": [ 2319 | { 2320 | "name": "stdout", 2321 | "output_type": "stream", 2322 | "text": [ 2323 | "len(x) = 4\n", 2324 | "len(y) = 3\n", 2325 | "shape X= (3, 4)\n", 2326 | "shape Y= (3, 4)\n", 2327 | "x = [0. 1. 2. 3.]\n", 2328 | "y = [0. 1. 2.]\n", 2329 | "X = \n", 2330 | "[[0. 1. 2. 3.]\n", 2331 | " [0. 1. 2. 3.]\n", 2332 | " [0. 1. 2. 3.]]\n", 2333 | "Y = \n", 2334 | "[[0. 0. 0. 0.]\n", 2335 | " [1. 1. 1. 1.]\n", 2336 | " [2. 2. 2. 2.]]\n" 2337 | ] 2338 | } 2339 | ], 2340 | "source": [ 2341 | "x = np.linspace(0,3,4)\n", 2342 | "y = np.linspace(0,2,3)\n", 2343 | "X, Y = np.meshgrid(x,y)\n", 2344 | "print('len(x) = ',len(x))\n", 2345 | "print('len(y) = ',len(y))\n", 2346 | "print('shape X= ',X.shape)\n", 2347 | "print('shape Y= ',Y.shape)\n", 2348 | "print('x = ', x)\n", 2349 | "print('y = ', y)\n", 2350 | "print('X = '); print(X)\n", 2351 | "print('Y = '); print(Y)" 2352 | ] 2353 | }, 2354 | { 2355 | "cell_type": "markdown", 2356 | "metadata": {}, 2357 | "source": [ 2358 | "If $x \\in \\re^m$ and $y \\in \\re^n$, then the output of `meshgrid(x,y)` is arranged like this\n", 2359 | "\n", 2360 | "$$\n", 2361 | "X[i,j] = x[j], \\qquad\n", 2362 | "Y[i,j] = y[i], \\qquad 0 \\le i \\le n-1, \\quad 0 \\le j \\le m-1\n", 2363 | "$$\n", 2364 | "\n", 2365 | "If we want the following arrangement\n", 2366 | "\n", 2367 | "$$\n", 2368 | "X[i,j] = x[i], \\qquad\n", 2369 | "Y[i,j] = y[j], \\qquad 0 \\le i \\le m-1, \\quad 0 \\le j \\le n-1\n", 2370 | "$$\n", 2371 | "\n", 2372 | "we have to do the following" 2373 | ] 2374 | }, 2375 | { 2376 | "cell_type": "code", 2377 | "execution_count": 80, 2378 | "metadata": {}, 2379 | "outputs": [ 2380 | { 2381 | "name": "stdout", 2382 | "output_type": "stream", 2383 | "text": [ 2384 | "len(x) = 4\n", 2385 | "len(y) = 3\n", 2386 | "shape X= (4, 3)\n", 2387 | "shape Y= (4, 3)\n" 2388 | ] 2389 | } 2390 | ], 2391 | "source": [ 2392 | "X, Y = np.meshgrid(x,y,indexing='ij')\n", 2393 | "print('len(x) = ',len(x))\n", 2394 | "print('len(y) = ',len(y))\n", 2395 | "print('shape X= ',X.shape)\n", 2396 | "print('shape Y= ',Y.shape)" 2397 | ] 2398 | }, 2399 | { 2400 | "cell_type": "markdown", 2401 | "metadata": {}, 2402 | "source": [ 2403 | "The second form is useful when working with finite difference schemes on Cartesian grids, where we want to use `i` index running along x-axis and `j` index running along y-axis." 2404 | ] 2405 | }, 2406 | { 2407 | "cell_type": "markdown", 2408 | "metadata": {}, 2409 | "source": [ 2410 | "## Reshaping arrays" 2411 | ] 2412 | }, 2413 | { 2414 | "cell_type": "code", 2415 | "execution_count": 81, 2416 | "metadata": {}, 2417 | "outputs": [ 2418 | { 2419 | "name": "stdout", 2420 | "output_type": "stream", 2421 | "text": [ 2422 | "[[1 2 3]\n", 2423 | " [4 5 6]]\n" 2424 | ] 2425 | } 2426 | ], 2427 | "source": [ 2428 | "A = np.array([[1,2,3],\n", 2429 | " [4,5,6]])\n", 2430 | "print(A)" 2431 | ] 2432 | }, 2433 | { 2434 | "cell_type": "code", 2435 | "execution_count": 82, 2436 | "metadata": {}, 2437 | "outputs": [ 2438 | { 2439 | "name": "stdout", 2440 | "output_type": "stream", 2441 | "text": [ 2442 | "[1 2 3 4 5 6]\n" 2443 | ] 2444 | } 2445 | ], 2446 | "source": [ 2447 | "B = np.reshape(A,2*3,order='C')\n", 2448 | "print(B)" 2449 | ] 2450 | }, 2451 | { 2452 | "cell_type": "code", 2453 | "execution_count": 83, 2454 | "metadata": {}, 2455 | "outputs": [ 2456 | { 2457 | "name": "stdout", 2458 | "output_type": "stream", 2459 | "text": [ 2460 | "[[1 2 3]\n", 2461 | " [4 5 6]]\n" 2462 | ] 2463 | } 2464 | ], 2465 | "source": [ 2466 | "A1 = np.reshape(B,(2,3),order='C')\n", 2467 | "print(A1)" 2468 | ] 2469 | }, 2470 | { 2471 | "cell_type": "code", 2472 | "execution_count": 84, 2473 | "metadata": {}, 2474 | "outputs": [ 2475 | { 2476 | "name": "stdout", 2477 | "output_type": "stream", 2478 | "text": [ 2479 | "[1 4 2 5 3 6]\n" 2480 | ] 2481 | } 2482 | ], 2483 | "source": [ 2484 | "C = np.reshape(A,2*3,order='F')\n", 2485 | "print(C)" 2486 | ] 2487 | }, 2488 | { 2489 | "cell_type": "code", 2490 | "execution_count": 85, 2491 | "metadata": {}, 2492 | "outputs": [ 2493 | { 2494 | "name": "stdout", 2495 | "output_type": "stream", 2496 | "text": [ 2497 | "[[1 2 3]\n", 2498 | " [4 5 6]]\n" 2499 | ] 2500 | } 2501 | ], 2502 | "source": [ 2503 | "A2 = np.reshape(C,(2,3),order='F')\n", 2504 | "print(A2)" 2505 | ] 2506 | }, 2507 | { 2508 | "cell_type": "markdown", 2509 | "metadata": {}, 2510 | "source": [ 2511 | "## [roll](https://numpy.org/doc/stable/reference/generated/numpy.roll.html) function: working with periodic arrays" 2512 | ] 2513 | }, 2514 | { 2515 | "cell_type": "code", 2516 | "execution_count": 86, 2517 | "metadata": {}, 2518 | "outputs": [ 2519 | { 2520 | "name": "stdout", 2521 | "output_type": "stream", 2522 | "text": [ 2523 | "[ 1 2 3 4 5 6 7 8 9 10]\n" 2524 | ] 2525 | } 2526 | ], 2527 | "source": [ 2528 | "v = np.arange(1,11)\n", 2529 | "print(v)" 2530 | ] 2531 | }, 2532 | { 2533 | "cell_type": "markdown", 2534 | "metadata": {}, 2535 | "source": [ 2536 | "Shift array by one index to left and wrap it from right side." 2537 | ] 2538 | }, 2539 | { 2540 | "cell_type": "code", 2541 | "execution_count": 87, 2542 | "metadata": {}, 2543 | "outputs": [ 2544 | { 2545 | "name": "stdout", 2546 | "output_type": "stream", 2547 | "text": [ 2548 | "[ 2 3 4 5 6 7 8 9 10 1]\n" 2549 | ] 2550 | } 2551 | ], 2552 | "source": [ 2553 | "print(np.roll(v,-1))" 2554 | ] 2555 | }, 2556 | { 2557 | "cell_type": "markdown", 2558 | "metadata": {}, 2559 | "source": [ 2560 | "Shift array by one index to right and wrap it from left side." 2561 | ] 2562 | }, 2563 | { 2564 | "cell_type": "code", 2565 | "execution_count": 88, 2566 | "metadata": {}, 2567 | "outputs": [ 2568 | { 2569 | "name": "stdout", 2570 | "output_type": "stream", 2571 | "text": [ 2572 | "[10 1 2 3 4 5 6 7 8 9]\n" 2573 | ] 2574 | } 2575 | ], 2576 | "source": [ 2577 | "print(np.roll(v,1))" 2578 | ] 2579 | }, 2580 | { 2581 | "cell_type": "markdown", 2582 | "metadata": {}, 2583 | "source": [ 2584 | "**Example**: Compute $v'(x)$ for \n", 2585 | "\n", 2586 | "$$\n", 2587 | "v(x) = \\sin(x), \\qquad x \\in [0,2\\pi]\n", 2588 | "$$\n", 2589 | "\n", 2590 | "using periodicity and central difference scheme\n", 2591 | "\n", 2592 | "$$\n", 2593 | "w_j = \\frac{v_{j+1} - v_{j-1}}{2h}, \\qquad 0 \\le j \\le N-1\n", 2594 | "$$\n", 2595 | "\n", 2596 | "on the grid\n", 2597 | "\n", 2598 | "$$\n", 2599 | "x_j = j h, \\qquad 0 \\le j \\le N-1, \\qquad h = \\frac{2\\pi}{N}\n", 2600 | "$$\n", 2601 | "\n", 2602 | "Note that $x_0 = 0$ and the last grid point $x_{N-1} = 2\\pi -h$. We should not include both $x=0$ and $x=2\\pi$ in the grid." 2603 | ] 2604 | }, 2605 | { 2606 | "cell_type": "code", 2607 | "execution_count": 89, 2608 | "metadata": {}, 2609 | "outputs": [ 2610 | { 2611 | "name": "stdout", 2612 | "output_type": "stream", 2613 | "text": [ 2614 | "Error in FD = 0.000657843760160759\n" 2615 | ] 2616 | } 2617 | ], 2618 | "source": [ 2619 | "N = 100\n", 2620 | "h = 2*np.pi/N\n", 2621 | "x = h * np.arange(N)\n", 2622 | "v = np.sin(x)\n", 2623 | "w = (np.roll(v,-1) - np.roll(v,1))/(2*h) # central finite difference\n", 2624 | "error = np.abs(w - np.cos(x)).max()\n", 2625 | "print(\"Error in FD = \", error)" 2626 | ] 2627 | }, 2628 | { 2629 | "cell_type": "markdown", 2630 | "metadata": {}, 2631 | "source": [ 2632 | "## Writing and reading files\n", 2633 | "Write an array to file" 2634 | ] 2635 | }, 2636 | { 2637 | "cell_type": "code", 2638 | "execution_count": 90, 2639 | "metadata": {}, 2640 | "outputs": [ 2641 | { 2642 | "name": "stdout", 2643 | "output_type": "stream", 2644 | "text": [ 2645 | "[[0.20186549 0.61744876 0.94779963]\n", 2646 | " [0.88815202 0.96999723 0.35392894]\n", 2647 | " [0.50862625 0.666285 0.46223677]]\n" 2648 | ] 2649 | } 2650 | ], 2651 | "source": [ 2652 | "A = np.random.rand(3,3)\n", 2653 | "print(A)\n", 2654 | "np.savetxt('A.txt',A)" 2655 | ] 2656 | }, 2657 | { 2658 | "cell_type": "markdown", 2659 | "metadata": {}, 2660 | "source": [ 2661 | "Check the contents of the file in your terminal\n", 2662 | "```\n", 2663 | "cat A.txt\n", 2664 | "```\n", 2665 | "We can also print it from within the notebook" 2666 | ] 2667 | }, 2668 | { 2669 | "cell_type": "code", 2670 | "execution_count": 91, 2671 | "metadata": {}, 2672 | "outputs": [ 2673 | { 2674 | "name": "stdout", 2675 | "output_type": "stream", 2676 | "text": [ 2677 | "2.018654884751622802e-01 6.174487591847054313e-01 9.477996299840885097e-01\n", 2678 | "8.881520245390911450e-01 9.699972259858081758e-01 3.539289418628871475e-01\n", 2679 | "5.086262496650897358e-01 6.662849978271079276e-01 4.622367690886420855e-01\n" 2680 | ] 2681 | } 2682 | ], 2683 | "source": [ 2684 | "!cat A.txt" 2685 | ] 2686 | }, 2687 | { 2688 | "cell_type": "markdown", 2689 | "metadata": {}, 2690 | "source": [ 2691 | "Write two 1-D arrays as columns into file" 2692 | ] 2693 | }, 2694 | { 2695 | "cell_type": "code", 2696 | "execution_count": 92, 2697 | "metadata": {}, 2698 | "outputs": [ 2699 | { 2700 | "name": "stdout", 2701 | "output_type": "stream", 2702 | "text": [ 2703 | "1.000000000000000000e+00 2.000000000000000000e+00\n", 2704 | "2.000000000000000000e+00 4.000000000000000000e+00\n", 2705 | "3.000000000000000000e+00 6.000000000000000000e+00\n", 2706 | "4.000000000000000000e+00 8.000000000000000000e+00\n" 2707 | ] 2708 | } 2709 | ], 2710 | "source": [ 2711 | "x = np.array([1.0,2.0,3.0,4.0])\n", 2712 | "y = np.array([2.0,4.0,6.0,8.0])\n", 2713 | "np.savetxt('data.txt',np.column_stack([x,y]))\n", 2714 | "!cat data.txt" 2715 | ] 2716 | }, 2717 | { 2718 | "cell_type": "markdown", 2719 | "metadata": {}, 2720 | "source": [ 2721 | "We can control the number of decimals saved, and use scientific notation" 2722 | ] 2723 | }, 2724 | { 2725 | "cell_type": "code", 2726 | "execution_count": 93, 2727 | "metadata": {}, 2728 | "outputs": [ 2729 | { 2730 | "name": "stdout", 2731 | "output_type": "stream", 2732 | "text": [ 2733 | "1.0000e+00 2.0000e+00\n", 2734 | "2.0000e+00 4.0000e+00\n", 2735 | "3.0000e+00 6.0000e+00\n", 2736 | "4.0000e+00 8.0000e+00\n" 2737 | ] 2738 | } 2739 | ], 2740 | "source": [ 2741 | "np.savetxt('data.txt',np.column_stack([x,y]),fmt='%8.4e')\n", 2742 | "!cat data.txt" 2743 | ] 2744 | }, 2745 | { 2746 | "cell_type": "markdown", 2747 | "metadata": {}, 2748 | "source": [ 2749 | "We can read an existing file like this" 2750 | ] 2751 | }, 2752 | { 2753 | "cell_type": "code", 2754 | "execution_count": 94, 2755 | "metadata": {}, 2756 | "outputs": [ 2757 | { 2758 | "name": "stdout", 2759 | "output_type": "stream", 2760 | "text": [ 2761 | "Shape d = (4, 2)\n", 2762 | "x = [1. 2. 3. 4.]\n", 2763 | "y = [2. 4. 6. 8.]\n" 2764 | ] 2765 | } 2766 | ], 2767 | "source": [ 2768 | "d = np.loadtxt('data.txt')\n", 2769 | "print('Shape d =', d.shape)\n", 2770 | "x1 = d[:,0]\n", 2771 | "y1 = d[:,1]\n", 2772 | "print('x =',x1)\n", 2773 | "print('y =',y1)" 2774 | ] 2775 | }, 2776 | { 2777 | "cell_type": "markdown", 2778 | "metadata": {}, 2779 | "source": [ 2780 | "## Measuring time\n", 2781 | "\n", 2782 | "Loops are slow in Python and it is good to avoid them. The following example shows how to time code execution.\n", 2783 | "\n", 2784 | "Create some random matrices" 2785 | ] 2786 | }, 2787 | { 2788 | "cell_type": "code", 2789 | "execution_count": 95, 2790 | "metadata": {}, 2791 | "outputs": [], 2792 | "source": [ 2793 | "m = 1000\n", 2794 | "A = np.random.random((m,m))\n", 2795 | "B = np.random.random((m,m))" 2796 | ] 2797 | }, 2798 | { 2799 | "cell_type": "markdown", 2800 | "metadata": {}, 2801 | "source": [ 2802 | "First we add two matrices with an explicit for loop." 2803 | ] 2804 | }, 2805 | { 2806 | "cell_type": "code", 2807 | "execution_count": null, 2808 | "metadata": {}, 2809 | "outputs": [], 2810 | "source": [ 2811 | "%%timeit -r10 -n10\n", 2812 | "C = np.empty_like(A)\n", 2813 | "for i in range(m):\n", 2814 | " for j in range(m):\n", 2815 | " C[i,j] = A[i,j] + B[i,j]" 2816 | ] 2817 | }, 2818 | { 2819 | "cell_type": "markdown", 2820 | "metadata": {}, 2821 | "source": [ 2822 | "Now we use the + operator." 2823 | ] 2824 | }, 2825 | { 2826 | "cell_type": "code", 2827 | "execution_count": null, 2828 | "metadata": {}, 2829 | "outputs": [], 2830 | "source": [ 2831 | "%%timeit -r10 -n10\n", 2832 | "C = A + B" 2833 | ] 2834 | }, 2835 | { 2836 | "cell_type": "markdown", 2837 | "metadata": {}, 2838 | "source": [ 2839 | "The loop version is significantly slower." 2840 | ] 2841 | } 2842 | ], 2843 | "metadata": { 2844 | "kernelspec": { 2845 | "display_name": "Python 3 (ipykernel)", 2846 | "language": "python", 2847 | "name": "python3" 2848 | }, 2849 | "language_info": { 2850 | "codemirror_mode": { 2851 | "name": "ipython", 2852 | "version": 3 2853 | }, 2854 | "file_extension": ".py", 2855 | "mimetype": "text/x-python", 2856 | "name": "python", 2857 | "nbconvert_exporter": "python", 2858 | "pygments_lexer": "ipython3", 2859 | "version": "3.12.8" 2860 | }, 2861 | "vscode": { 2862 | "interpreter": { 2863 | "hash": "c6e4e9f98eb68ad3b7c296f83d20e6de614cb42e90992a65aa266555a3137d0d" 2864 | } 2865 | } 2866 | }, 2867 | "nbformat": 4, 2868 | "nbformat_minor": 4 2869 | } 2870 | -------------------------------------------------------------------------------- /03_functions.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Functions" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "$\\newcommand{\\re}{\\mathbb{R}}$\n", 15 | "\n", 16 | "A function is something which takes some input arguments and returns one or more output values. These are called ```def``` in Python, short for definition. They have following structure\n", 17 | "```\n", 18 | "def functionname(arg1,arg2,arg3):\n", 19 | " DO SOME COMPUTATION\n", 20 | " return result\n", 21 | "```\n", 22 | "The body of the function must be indented.\n", 23 | "\n", 24 | "Whenever some piece of computation is to be repeated many times, it is best to put it inside a function. This avoids code duplication, which minimizes errors and makes it easy to maintain your code." 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "execution_count": 34, 30 | "metadata": {}, 31 | "outputs": [], 32 | "source": [ 33 | "import numpy as np" 34 | ] 35 | }, 36 | { 37 | "cell_type": "markdown", 38 | "metadata": {}, 39 | "source": [ 40 | "## Sum two vectors\n", 41 | "\n", 42 | "For $x, y \\in \\re^n$, compute $z \\in \\re^n$ by\n", 43 | "\n", 44 | "$$\n", 45 | "z_i = x_i + y_i, \\qquad 0 \\le i \\le n-1\n", 46 | "$$" 47 | ] 48 | }, 49 | { 50 | "cell_type": "code", 51 | "execution_count": 35, 52 | "metadata": {}, 53 | "outputs": [], 54 | "source": [ 55 | "def sum1(x,y):\n", 56 | " z = np.empty_like(x)\n", 57 | " for i in range(len(x)):\n", 58 | " z[i] = x[i] + y[i]\n", 59 | " return z" 60 | ] 61 | }, 62 | { 63 | "cell_type": "markdown", 64 | "metadata": {}, 65 | "source": [ 66 | "Now we can use this function." 67 | ] 68 | }, 69 | { 70 | "cell_type": "code", 71 | "execution_count": 36, 72 | "metadata": {}, 73 | "outputs": [ 74 | { 75 | "name": "stdout", 76 | "output_type": "stream", 77 | "text": [ 78 | "[3. 3. 3. 3. 3.]\n", 79 | "[0. 0. 0. 0. 0.]\n" 80 | ] 81 | } 82 | ], 83 | "source": [ 84 | "n = 5\n", 85 | "x = np.ones(n)\n", 86 | "y = 2*x\n", 87 | "z = sum1(x,y)\n", 88 | "print(z)\n", 89 | "print(z - (x + y))" 90 | ] 91 | }, 92 | { 93 | "cell_type": "markdown", 94 | "metadata": {}, 95 | "source": [ 96 | "## Check your inputs" 97 | ] 98 | }, 99 | { 100 | "cell_type": "markdown", 101 | "metadata": {}, 102 | "source": [ 103 | "We can add two vectors only if they are of same size. It is always a good practice to check that your inputs are consistent. We will also use [enumerate](https://docs.python.org/library/functions.html#enumerate) and [zip](https://docs.python.org/library/functions.html#zip)." 104 | ] 105 | }, 106 | { 107 | "cell_type": "code", 108 | "execution_count": 37, 109 | "metadata": {}, 110 | "outputs": [], 111 | "source": [ 112 | "def sum2(x,y):\n", 113 | " assert len(x) == len(y)\n", 114 | " z = np.empty_like(x)\n", 115 | " for i,(a,b) in enumerate(zip(x,y)):\n", 116 | " z[i] = a + b\n", 117 | " return z" 118 | ] 119 | }, 120 | { 121 | "cell_type": "markdown", 122 | "metadata": {}, 123 | "source": [ 124 | "First test on same inputs as before." 125 | ] 126 | }, 127 | { 128 | "cell_type": "code", 129 | "execution_count": 38, 130 | "metadata": {}, 131 | "outputs": [ 132 | { 133 | "name": "stdout", 134 | "output_type": "stream", 135 | "text": [ 136 | "[3. 3. 3. 3. 3.]\n", 137 | "[0. 0. 0. 0. 0.]\n" 138 | ] 139 | } 140 | ], 141 | "source": [ 142 | "z = sum2(x,y)\n", 143 | "print(z)\n", 144 | "print(z - (x + y))" 145 | ] 146 | }, 147 | { 148 | "cell_type": "markdown", 149 | "metadata": {}, 150 | "source": [ 151 | "If you try to run the following code, it will give an error.\n", 152 | "\n", 153 | "```\n", 154 | "n = 5\n", 155 | "x = np.ones(n)\n", 156 | "y = np.ones(n+1)\n", 157 | "z = sum2(x,y)\n", 158 | "```" 159 | ] 160 | }, 161 | { 162 | "cell_type": "markdown", 163 | "metadata": {}, 164 | "source": [ 165 | "## Minimum value of an array\n", 166 | "\n", 167 | "Given $x \\in \\re^n$, compute\n", 168 | "\n", 169 | "$$\n", 170 | "m = \\min_{0 \\le i \\le n-1} x_i\n", 171 | "$$" 172 | ] 173 | }, 174 | { 175 | "cell_type": "code", 176 | "execution_count": 39, 177 | "metadata": {}, 178 | "outputs": [], 179 | "source": [ 180 | "def minval(x):\n", 181 | " val = x[0]\n", 182 | " for v in x:\n", 183 | " if v < val:\n", 184 | " val = v\n", 185 | " return val" 186 | ] 187 | }, 188 | { 189 | "cell_type": "markdown", 190 | "metadata": {}, 191 | "source": [ 192 | "Test on some random array." 193 | ] 194 | }, 195 | { 196 | "cell_type": "code", 197 | "execution_count": 40, 198 | "metadata": {}, 199 | "outputs": [ 200 | { 201 | "name": "stdout", 202 | "output_type": "stream", 203 | "text": [ 204 | "x = \n", 205 | " [0.56952692 0.45413289 0.74771823 0.87510616 0.84367195 0.00983037\n", 206 | " 0.86834298 0.23403788 0.14703669 0.53805294]\n", 207 | "Minimum = 0.0098303666528603\n", 208 | "Numpy = 0.0098303666528603\n" 209 | ] 210 | } 211 | ], 212 | "source": [ 213 | "x = np.random.rand(10)\n", 214 | "mval = minval(x)\n", 215 | "print('x = \\n', x)\n", 216 | "print('Minimum = ',mval)\n", 217 | "print('Numpy = ', x.min())" 218 | ] 219 | }, 220 | { 221 | "cell_type": "markdown", 222 | "metadata": {}, 223 | "source": [ 224 | "## Min and max of an array\n", 225 | "\n", 226 | "Given $x \\in \\re^n$, compute\n", 227 | "\n", 228 | "$$\n", 229 | "m = \\min_{0 \\le i \\le n-1} x_i, \\qquad\n", 230 | "M = \\max_{0 \\le i \\le n-1} x_i\n", 231 | "$$" 232 | ] 233 | }, 234 | { 235 | "cell_type": "code", 236 | "execution_count": 41, 237 | "metadata": {}, 238 | "outputs": [], 239 | "source": [ 240 | "def minmax(x):\n", 241 | " min_val = x[0]\n", 242 | " max_val = x[0]\n", 243 | " for v in x:\n", 244 | " if v < min_val:\n", 245 | " min_val = v\n", 246 | " if v > max_val:\n", 247 | " max_val = v\n", 248 | " return min_val, max_val" 249 | ] 250 | }, 251 | { 252 | "cell_type": "markdown", 253 | "metadata": {}, 254 | "source": [ 255 | "The type of returned object is `tuple`." 256 | ] 257 | }, 258 | { 259 | "cell_type": "code", 260 | "execution_count": 42, 261 | "metadata": {}, 262 | "outputs": [ 263 | { 264 | "name": "stdout", 265 | "output_type": "stream", 266 | "text": [ 267 | "[0.49440445 0.96844055 0.87774249 0.61157192 0.29238153]\n", 268 | "Minimum = 0.29238152818674534 0.29238152818674534\n", 269 | "Maximum = 0.9684405476373608 0.9684405476373608\n" 270 | ] 271 | } 272 | ], 273 | "source": [ 274 | "x = np.random.rand(5)\n", 275 | "min_val, max_val = minmax(x)\n", 276 | "print(x)\n", 277 | "print('Minimum =',min_val,x.min())\n", 278 | "print('Maximum =',max_val,x.max())" 279 | ] 280 | }, 281 | { 282 | "cell_type": "markdown", 283 | "metadata": {}, 284 | "source": [ 285 | "## lambda: for simple functions\n", 286 | "\n", 287 | "If the function definition is simple we can define them using lambda\n", 288 | "\n", 289 | "$$\n", 290 | "f(x) = \\sin(2\\pi x)\n", 291 | "$$" 292 | ] 293 | }, 294 | { 295 | "cell_type": "code", 296 | "execution_count": 43, 297 | "metadata": {}, 298 | "outputs": [ 299 | { 300 | "name": "stdout", 301 | "output_type": "stream", 302 | "text": [ 303 | "Minimum = -0.9998741276738751\n", 304 | "Maximum = 0.9998741276738751\n" 305 | ] 306 | } 307 | ], 308 | "source": [ 309 | "f = lambda x: np.sin(2*np.pi*x)\n", 310 | "x = np.linspace(0.0, 1.0, 100)\n", 311 | "y = f(x)\n", 312 | "min_val, max_val = minmax(y)\n", 313 | "print('Minimum =',min_val)\n", 314 | "print('Maximum =',max_val)" 315 | ] 316 | }, 317 | { 318 | "cell_type": "markdown", 319 | "metadata": {}, 320 | "source": [ 321 | "We can define lambda's with more than one argument." 322 | ] 323 | }, 324 | { 325 | "cell_type": "code", 326 | "execution_count": 44, 327 | "metadata": {}, 328 | "outputs": [ 329 | { 330 | "name": "stdout", 331 | "output_type": "stream", 332 | "text": [ 333 | "-0.2938926261462344\n" 334 | ] 335 | } 336 | ], 337 | "source": [ 338 | "g = lambda x,y: np.sin(2*np.pi*x) * np.cos(2*np.pi*y)\n", 339 | "z = g(1.2, 2.3)\n", 340 | "print(z)" 341 | ] 342 | }, 343 | { 344 | "cell_type": "markdown", 345 | "metadata": {}, 346 | "source": [ 347 | "## Variables inside functions are local" 348 | ] 349 | }, 350 | { 351 | "cell_type": "code", 352 | "execution_count": 45, 353 | "metadata": {}, 354 | "outputs": [], 355 | "source": [ 356 | "def fun1(x):\n", 357 | " a = 1\n", 358 | " print(x + a)\n", 359 | "\n", 360 | "def fun2(x):\n", 361 | " a = 2\n", 362 | " print(x + a)\n", 363 | "\n", 364 | "def fun3(x):\n", 365 | " print(x + a)" 366 | ] 367 | }, 368 | { 369 | "cell_type": "markdown", 370 | "metadata": {}, 371 | "source": [ 372 | "The variable `a` inside these functions are local variables and have different values." 373 | ] 374 | }, 375 | { 376 | "cell_type": "code", 377 | "execution_count": 46, 378 | "metadata": {}, 379 | "outputs": [ 380 | { 381 | "name": "stdout", 382 | "output_type": "stream", 383 | "text": [ 384 | "2\n", 385 | "3\n" 386 | ] 387 | }, 388 | { 389 | "ename": "NameError", 390 | "evalue": "name 'a' is not defined", 391 | "output_type": "error", 392 | "traceback": [ 393 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 394 | "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", 395 | "Cell \u001b[0;32mIn[46], line 3\u001b[0m\n\u001b[1;32m 1\u001b[0m fun1(\u001b[38;5;241m1\u001b[39m)\n\u001b[1;32m 2\u001b[0m fun2(\u001b[38;5;241m1\u001b[39m)\n\u001b[0;32m----> 3\u001b[0m \u001b[43mfun3\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m)\u001b[49m\n", 396 | "Cell \u001b[0;32mIn[45], line 10\u001b[0m, in \u001b[0;36mfun3\u001b[0;34m(x)\u001b[0m\n\u001b[1;32m 9\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mfun3\u001b[39m(x):\n\u001b[0;32m---> 10\u001b[0m \u001b[38;5;28mprint\u001b[39m(x \u001b[38;5;241m+\u001b[39m \u001b[43ma\u001b[49m)\n", 397 | "\u001b[0;31mNameError\u001b[0m: name 'a' is not defined" 398 | ] 399 | } 400 | ], 401 | "source": [ 402 | "fun1(1)\n", 403 | "fun2(1)\n", 404 | "fun3(1)" 405 | ] 406 | }, 407 | { 408 | "cell_type": "markdown", 409 | "metadata": {}, 410 | "source": [ 411 | "Variable `a` is not visible in `fun3` since it is a local variable in `fun1` and `fun2`.\n", 412 | "\n", 413 | "## Beware of global variables" 414 | ] 415 | }, 416 | { 417 | "cell_type": "code", 418 | "execution_count": 47, 419 | "metadata": {}, 420 | "outputs": [], 421 | "source": [ 422 | "p = 1.234 # Global variable, visible inside all functions.\n", 423 | "\n", 424 | "def fun4(x):\n", 425 | " p = 1.0 # Local variable of same name\n", 426 | " print(x + p)\n", 427 | "\n", 428 | "def fun5(x):\n", 429 | " print(x + p) # Here the global variable p is used" 430 | ] 431 | }, 432 | { 433 | "cell_type": "markdown", 434 | "metadata": {}, 435 | "source": [ 436 | "The variable `p = 1.234` which is declared outside the functions is a global variable." 437 | ] 438 | }, 439 | { 440 | "cell_type": "code", 441 | "execution_count": 48, 442 | "metadata": {}, 443 | "outputs": [ 444 | { 445 | "name": "stdout", 446 | "output_type": "stream", 447 | "text": [ 448 | "2.0\n", 449 | "2.234\n" 450 | ] 451 | } 452 | ], 453 | "source": [ 454 | "fun4(1.0)\n", 455 | "fun5(1.0)" 456 | ] 457 | }, 458 | { 459 | "cell_type": "markdown", 460 | "metadata": {}, 461 | "source": [ 462 | "The variable `p = 1.0` is a local variable in `fun4`; this is ok, you can have a local and global variable of the same name, they have independent existence. But in `fun5`, the global variable `p = 1.234` is used since there is no local variable of the same name. If you wanted to use the global variable, then it is fine, but if you forgot to declare `p` inside `fun5`, then you have a bug, and it can be difficult to detect.\n", 463 | "\n", 464 | "You have to be very careful with global variables. If you forget to declare some variable inside a function, and a global variable with the same name exists, then your program will run but likely give wrong answers. We should ideally never use global variables, but they are rampant in jupyter notebooks. To avoid global variables, you have to declare ALL variables inside functions and not declare anything in the global scope. It is good practice not to rely on global variables, but instead write [pure functions](https://en.wikipedia.org/wiki/Pure_function)." 465 | ] 466 | }, 467 | { 468 | "cell_type": "markdown", 469 | "metadata": {}, 470 | "source": [ 471 | "## Pass a function as argument to other functions" 472 | ] 473 | }, 474 | { 475 | "cell_type": "code", 476 | "execution_count": 49, 477 | "metadata": {}, 478 | "outputs": [], 479 | "source": [ 480 | "def sin(x):\n", 481 | " return np.sin(x)\n", 482 | " \n", 483 | "def cos(x):\n", 484 | " return np.cos(x)\n", 485 | " \n", 486 | "def run(x, f):\n", 487 | " print(f(x))" 488 | ] 489 | }, 490 | { 491 | "cell_type": "code", 492 | "execution_count": 50, 493 | "metadata": {}, 494 | "outputs": [ 495 | { 496 | "name": "stdout", 497 | "output_type": "stream", 498 | "text": [ 499 | "1.0\n", 500 | "6.123233995736766e-17\n" 501 | ] 502 | } 503 | ], 504 | "source": [ 505 | "x = np.pi/2\n", 506 | "run(x, sin)\n", 507 | "run(x, cos)" 508 | ] 509 | } 510 | ], 511 | "metadata": { 512 | "kernelspec": { 513 | "display_name": "Python 3 (ipykernel)", 514 | "language": "python", 515 | "name": "python3" 516 | }, 517 | "language_info": { 518 | "codemirror_mode": { 519 | "name": "ipython", 520 | "version": 3 521 | }, 522 | "file_extension": ".py", 523 | "mimetype": "text/x-python", 524 | "name": "python", 525 | "nbconvert_exporter": "python", 526 | "pygments_lexer": "ipython3", 527 | "version": "3.12.8" 528 | }, 529 | "vscode": { 530 | "interpreter": { 531 | "hash": "c6e4e9f98eb68ad3b7c296f83d20e6de614cb42e90992a65aa266555a3137d0d" 532 | } 533 | } 534 | }, 535 | "nbformat": 4, 536 | "nbformat_minor": 4 537 | } 538 | -------------------------------------------------------------------------------- /06_scipy.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Scipy\n", 8 | "\n", 9 | "[Scipy](https://docs.scipy.org/doc/scipy/tutorial/general.html) provides many more computational algorithms and is built on Numpy." 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": 1, 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "%config InlineBackend.figure_format = 'svg'\n", 19 | "import numpy as np\n", 20 | "import matplotlib.pyplot as plt\n", 21 | "import scipy.linalg as la" 22 | ] 23 | }, 24 | { 25 | "cell_type": "markdown", 26 | "metadata": {}, 27 | "source": [ 28 | "## Use LU decomposition to solve $Ax=b$" 29 | ] 30 | }, 31 | { 32 | "cell_type": "markdown", 33 | "metadata": {}, 34 | "source": [ 35 | "Create a random $5 \\times 5$ matrix" 36 | ] 37 | }, 38 | { 39 | "cell_type": "code", 40 | "execution_count": 2, 41 | "metadata": {}, 42 | "outputs": [ 43 | { 44 | "name": "stdout", 45 | "output_type": "stream", 46 | "text": [ 47 | "[[0.29145244 0.35884437 0.55784979 0.46054394 0.32163474]\n", 48 | " [0.84136821 0.83746299 0.24546883 0.5487101 0.67319653]\n", 49 | " [0.26649574 0.57778323 0.48906678 0.22667758 0.06552584]\n", 50 | " [0.96896256 0.83054189 0.37846023 0.02328101 0.5339853 ]\n", 51 | " [0.42419362 0.16210889 0.44353171 0.55697708 0.9857654 ]]\n" 52 | ] 53 | } 54 | ], 55 | "source": [ 56 | "n = 5\n", 57 | "A = np.random.rand(n,n)\n", 58 | "print(A)" 59 | ] 60 | }, 61 | { 62 | "cell_type": "markdown", 63 | "metadata": {}, 64 | "source": [ 65 | "Compute its LU factorization with pivoting using [scipy.linalg.lu_factor](https://docs.scipy.org/doc/scipy/reference/generated/scipy.linalg.lu_factor.html)" 66 | ] 67 | }, 68 | { 69 | "cell_type": "code", 70 | "execution_count": 3, 71 | "metadata": {}, 72 | "outputs": [], 73 | "source": [ 74 | "lu,piv = la.lu_factor(A)" 75 | ] 76 | }, 77 | { 78 | "cell_type": "markdown", 79 | "metadata": {}, 80 | "source": [ 81 | "Another option is to use [scipy.linalg.lu](https://docs.scipy.org/doc/scipy/reference/generated/scipy.linalg.lu.html) which returns different arguments.\n", 82 | "\n", 83 | "Create a right hand side vector" 84 | ] 85 | }, 86 | { 87 | "cell_type": "code", 88 | "execution_count": 4, 89 | "metadata": {}, 90 | "outputs": [], 91 | "source": [ 92 | "b = np.random.rand(n)" 93 | ] 94 | }, 95 | { 96 | "cell_type": "markdown", 97 | "metadata": {}, 98 | "source": [ 99 | "Solve $A x = b$" 100 | ] 101 | }, 102 | { 103 | "cell_type": "code", 104 | "execution_count": 5, 105 | "metadata": {}, 106 | "outputs": [ 107 | { 108 | "name": "stdout", 109 | "output_type": "stream", 110 | "text": [ 111 | "[ 0.80575593 -0.8105171 1.30349815 -0.95036498 0.71113587]\n" 112 | ] 113 | } 114 | ], 115 | "source": [ 116 | "x = la.lu_solve((lu,piv),b)\n", 117 | "print(x)" 118 | ] 119 | }, 120 | { 121 | "cell_type": "markdown", 122 | "metadata": {}, 123 | "source": [ 124 | "Check that $x$ solves the problem by computing $Ax-b$" 125 | ] 126 | }, 127 | { 128 | "cell_type": "code", 129 | "execution_count": 6, 130 | "metadata": {}, 131 | "outputs": [ 132 | { 133 | "name": "stdout", 134 | "output_type": "stream", 135 | "text": [ 136 | "[-5.55111512e-17 0.00000000e+00 -5.55111512e-17 -1.11022302e-16\n", 137 | " -1.11022302e-16]\n" 138 | ] 139 | } 140 | ], 141 | "source": [ 142 | "print(A@x-b)" 143 | ] 144 | }, 145 | { 146 | "cell_type": "markdown", 147 | "metadata": {}, 148 | "source": [ 149 | "If we do not want the LU decomposition, we can directly solve, using [scipy.linalg.solve](https://docs.scipy.org/doc/scipy/reference/generated/scipy.linalg.solve.html)" 150 | ] 151 | }, 152 | { 153 | "cell_type": "code", 154 | "execution_count": 7, 155 | "metadata": {}, 156 | "outputs": [ 157 | { 158 | "name": "stdout", 159 | "output_type": "stream", 160 | "text": [ 161 | "[ 0.80575593 -0.8105171 1.30349815 -0.95036498 0.71113587]\n" 162 | ] 163 | } 164 | ], 165 | "source": [ 166 | "y = la.solve(A,b)\n", 167 | "print(y)" 168 | ] 169 | }, 170 | { 171 | "cell_type": "markdown", 172 | "metadata": {}, 173 | "source": [ 174 | "**Note**: There are similar methods in Numpy, see [numpy.linalg.solve](https://numpy.org/doc/stable/reference/generated/numpy.linalg.solve.html)." 175 | ] 176 | }, 177 | { 178 | "cell_type": "markdown", 179 | "metadata": {}, 180 | "source": [ 181 | "## Sparse matrix" 182 | ] 183 | }, 184 | { 185 | "cell_type": "markdown", 186 | "metadata": {}, 187 | "source": [ 188 | "Scipy provides methods that can work on sparse matrices, see [scipy.sparse.linalg](https://docs.scipy.org/doc/scipy/reference/sparse.linalg.html)\n", 189 | "\n", 190 | "Sparse matrix formats are provided by\n", 191 | "\n", 192 | " * [csc_matrix](https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.csc_matrix.html)\n", 193 | " * [csr_matrix](https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.csr_matrix.html)\n", 194 | " * [coo_matrix](https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.coo_matrix.html)\n", 195 | " \n", 196 | " csc_matrix stores the entries column-wise." 197 | ] 198 | }, 199 | { 200 | "cell_type": "code", 201 | "execution_count": 8, 202 | "metadata": {}, 203 | "outputs": [ 204 | { 205 | "name": "stdout", 206 | "output_type": "stream", 207 | "text": [ 208 | "\n", 210 | " Coords\tValues\n", 211 | " (0, 0)\t3.0\n", 212 | " (1, 0)\t1.0\n", 213 | " (0, 1)\t2.0\n", 214 | " (1, 1)\t-1.0\n", 215 | " (2, 1)\t5.0\n", 216 | " (2, 2)\t1.0\n", 217 | "[[ 3. 2. 0.]\n", 218 | " [ 1. -1. 0.]\n", 219 | " [ 0. 5. 1.]]\n" 220 | ] 221 | } 222 | ], 223 | "source": [ 224 | "from scipy.sparse import csc_matrix, csr_matrix\n", 225 | "A = csc_matrix([[3, 2, 0], \n", 226 | " [1, -1, 0], \n", 227 | " [0, 5, 1]], dtype=float)\n", 228 | "print(A)\n", 229 | "print(A.todense())" 230 | ] 231 | }, 232 | { 233 | "cell_type": "markdown", 234 | "metadata": {}, 235 | "source": [ 236 | "csr_matrix stores them row-wise." 237 | ] 238 | }, 239 | { 240 | "cell_type": "code", 241 | "execution_count": 9, 242 | "metadata": {}, 243 | "outputs": [ 244 | { 245 | "name": "stdout", 246 | "output_type": "stream", 247 | "text": [ 248 | "\n", 250 | " Coords\tValues\n", 251 | " (0, 0)\t3.0\n", 252 | " (0, 1)\t2.0\n", 253 | " (1, 0)\t1.0\n", 254 | " (1, 1)\t-1.0\n", 255 | " (2, 1)\t5.0\n", 256 | " (2, 2)\t1.0\n", 257 | "[[ 3. 2. 0.]\n", 258 | " [ 1. -1. 0.]\n", 259 | " [ 0. 5. 1.]]\n" 260 | ] 261 | } 262 | ], 263 | "source": [ 264 | "A = csr_matrix([[3, 2, 0], \n", 265 | " [1, -1, 0], \n", 266 | " [0, 5, 1]], dtype=float)\n", 267 | "print(A)\n", 268 | "print(A.todense())" 269 | ] 270 | }, 271 | { 272 | "cell_type": "markdown", 273 | "metadata": {}, 274 | "source": [ 275 | "We can construct sparse matrix by giving indices and values of non-zero entries. Indices not specified are assumed to be zero and need not be stored." 276 | ] 277 | }, 278 | { 279 | "cell_type": "code", 280 | "execution_count": 10, 281 | "metadata": {}, 282 | "outputs": [ 283 | { 284 | "name": "stdout", 285 | "output_type": "stream", 286 | "text": [ 287 | "\n", 289 | " Coords\tValues\n", 290 | " (0, 0)\t3.0\n", 291 | " (1, 0)\t1.0\n", 292 | " (0, 1)\t2.0\n", 293 | " (1, 1)\t-1.0\n", 294 | " (2, 1)\t5.0\n", 295 | " (2, 2)\t1.0\n", 296 | "[[ 3. 2. 0.]\n", 297 | " [ 1. -1. 0.]\n", 298 | " [ 0. 5. 1.]]\n" 299 | ] 300 | } 301 | ], 302 | "source": [ 303 | "row = np.array([0, 0, 1, 1, 2, 2])\n", 304 | "col = np.array([0, 1, 0, 1, 1, 2])\n", 305 | "data = np.array([3.0, 2.0, 1.0, -1.0, 5.0, 1.0])\n", 306 | "A = csc_matrix((data, (row, col)), shape=(3, 3))\n", 307 | "print(A)\n", 308 | "print(A.todense())" 309 | ] 310 | }, 311 | { 312 | "cell_type": "markdown", 313 | "metadata": {}, 314 | "source": [ 315 | "## Curve fitting\n", 316 | "\n", 317 | "Suppose we are given some data set \n", 318 | "\n", 319 | "$$\n", 320 | "(x_i,y_i), \\qquad i=0,1,...,n-1\n", 321 | "$$\n", 322 | "\n", 323 | "and we suspect there is a linear relation ship between them\n", 324 | "\n", 325 | "$$\n", 326 | "y = a + b x\n", 327 | "$$\n", 328 | "\n", 329 | "But possibly the data also has some noise. Let us generate such a data set." 330 | ] 331 | }, 332 | { 333 | "cell_type": "code", 334 | "execution_count": 11, 335 | "metadata": {}, 336 | "outputs": [ 337 | { 338 | "data": { 339 | "image/svg+xml": [ 340 | "\n", 341 | "\n", 343 | "\n", 344 | " \n", 345 | " \n", 346 | " \n", 347 | " \n", 348 | " 2025-01-05T14:50:43.805237\n", 349 | " image/svg+xml\n", 350 | " \n", 351 | " \n", 352 | " Matplotlib v3.10.0, https://matplotlib.org/\n", 353 | " \n", 354 | " \n", 355 | " \n", 356 | " \n", 357 | " \n", 358 | " \n", 359 | " \n", 360 | " \n", 361 | " \n", 362 | " \n", 363 | " \n", 369 | " \n", 370 | " \n", 371 | " \n", 372 | " \n", 378 | " \n", 379 | " \n", 380 | " \n", 381 | " \n", 382 | " \n", 383 | " \n", 386 | " \n", 387 | " \n", 388 | " \n", 389 | " \n", 390 | " \n", 391 | " \n", 392 | " \n", 393 | " \n", 394 | " \n", 395 | " \n", 416 | " \n", 427 | " \n", 428 | " \n", 429 | " \n", 430 | " \n", 431 | " \n", 432 | " \n", 433 | " \n", 434 | " \n", 435 | " \n", 436 | " \n", 437 | " \n", 438 | " \n", 439 | " \n", 440 | " \n", 441 | " \n", 442 | " \n", 443 | " \n", 444 | " \n", 469 | " \n", 470 | " \n", 471 | " \n", 472 | " \n", 473 | " \n", 474 | " \n", 475 | " \n", 476 | " \n", 477 | " \n", 478 | " \n", 479 | " \n", 480 | " \n", 481 | " \n", 482 | " \n", 483 | " \n", 484 | " \n", 485 | " \n", 486 | " \n", 509 | " \n", 510 | " \n", 511 | " \n", 512 | " \n", 513 | " \n", 514 | " \n", 515 | " \n", 516 | " \n", 517 | " \n", 518 | " \n", 519 | " \n", 520 | " \n", 521 | " \n", 522 | " \n", 523 | " \n", 524 | " \n", 525 | " \n", 526 | " \n", 557 | " \n", 558 | " \n", 559 | " \n", 560 | " \n", 561 | " \n", 562 | " \n", 563 | " \n", 564 | " \n", 565 | " \n", 566 | " \n", 567 | " \n", 568 | " \n", 569 | " \n", 570 | " \n", 571 | " \n", 572 | " \n", 573 | " \n", 574 | " \n", 613 | " \n", 614 | " \n", 615 | " \n", 616 | " \n", 617 | " \n", 618 | " \n", 619 | " \n", 620 | " \n", 621 | " \n", 622 | " \n", 623 | " \n", 624 | " \n", 625 | " \n", 626 | " \n", 627 | " \n", 628 | " \n", 629 | " \n", 630 | " \n", 644 | " \n", 645 | " \n", 646 | " \n", 647 | " \n", 648 | " \n", 649 | " \n", 650 | " \n", 651 | " \n", 652 | " \n", 653 | " \n", 654 | " \n", 655 | " \n", 656 | " \n", 659 | " \n", 660 | " \n", 661 | " \n", 662 | " \n", 663 | " \n", 664 | " \n", 665 | " \n", 666 | " \n", 667 | " \n", 668 | " \n", 669 | " \n", 670 | " \n", 671 | " \n", 672 | " \n", 673 | " \n", 674 | " \n", 675 | " \n", 676 | " \n", 677 | " \n", 678 | " \n", 679 | " \n", 680 | " \n", 681 | " \n", 682 | " \n", 683 | " \n", 710 | " \n", 711 | " \n", 712 | " \n", 713 | " \n", 714 | " \n", 715 | " \n", 716 | " \n", 717 | " \n", 718 | " \n", 719 | " \n", 720 | " \n", 721 | " \n", 722 | " \n", 723 | " \n", 724 | " \n", 725 | " \n", 726 | " \n", 727 | " \n", 728 | " \n", 729 | " \n", 730 | " \n", 731 | " \n", 732 | " \n", 733 | " \n", 734 | " \n", 735 | " \n", 736 | " \n", 737 | " \n", 738 | " \n", 739 | " \n", 740 | " \n", 741 | " \n", 742 | " \n", 743 | " \n", 744 | " \n", 745 | " \n", 746 | " \n", 747 | " \n", 748 | " \n", 749 | " \n", 750 | " \n", 751 | " \n", 752 | " \n", 753 | " \n", 754 | " \n", 755 | " \n", 756 | " \n", 757 | " \n", 791 | " \n", 792 | " \n", 793 | " \n", 794 | " \n", 795 | " \n", 796 | " \n", 797 | " \n", 798 | " \n", 799 | " \n", 800 | " \n", 801 | " \n", 812 | " \n", 813 | " \n", 814 | " \n", 815 | " \n", 816 | " \n", 817 | " \n", 818 | " \n", 819 | " \n", 820 | " \n", 821 | " \n", 822 | " \n", 823 | " \n", 824 | " \n", 825 | " \n", 826 | " \n", 827 | " \n", 838 | " \n", 839 | " \n", 840 | " \n", 843 | " \n", 844 | " \n", 845 | " \n", 848 | " \n", 849 | " \n", 850 | " \n", 853 | " \n", 854 | " \n", 855 | " \n", 858 | " \n", 859 | " \n", 860 | " \n", 861 | " \n", 872 | " \n", 873 | " \n", 874 | " \n", 875 | " \n", 876 | " \n", 877 | " \n", 878 | " \n", 879 | " \n", 880 | " \n", 881 | " \n", 882 | " \n", 905 | " \n", 926 | " \n", 949 | " \n", 982 | " \n", 1010 | " \n", 1011 | " \n", 1034 | " \n", 1070 | " \n", 1093 | " \n", 1094 | " \n", 1095 | " \n", 1096 | " \n", 1097 | " \n", 1098 | " \n", 1099 | " \n", 1100 | " \n", 1101 | " \n", 1102 | " \n", 1103 | " \n", 1104 | " \n", 1105 | " \n", 1106 | " \n", 1107 | " \n", 1111 | " \n", 1112 | " \n", 1113 | " \n", 1114 | " \n", 1115 | " \n", 1116 | " \n", 1135 | " \n", 1159 | " \n", 1184 | " \n", 1209 | " \n", 1237 | " \n", 1266 | " \n", 1288 | " \n", 1289 | " \n", 1290 | " \n", 1291 | " \n", 1292 | " \n", 1293 | " \n", 1294 | " \n", 1295 | " \n", 1296 | " \n", 1297 | " \n", 1298 | " \n", 1299 | " \n", 1300 | " \n", 1301 | " \n", 1302 | " \n", 1303 | " \n", 1304 | " \n", 1305 | " \n", 1306 | " \n", 1307 | " \n", 1308 | " \n", 1309 | " \n", 1310 | " \n", 1311 | " \n", 1312 | "\n" 1313 | ], 1314 | "text/plain": [ 1315 | "
" 1316 | ] 1317 | }, 1318 | "metadata": {}, 1319 | "output_type": "display_data" 1320 | } 1321 | ], 1322 | "source": [ 1323 | "# Sample points\n", 1324 | "n = 10\n", 1325 | "x = np.linspace(0,1,n)\n", 1326 | "\n", 1327 | "# Exact data\n", 1328 | "a = 1.0\n", 1329 | "b = 2.0\n", 1330 | "ye = a + b*x\n", 1331 | "\n", 1332 | "# Add some noise\n", 1333 | "y = ye + 0.1*(2*np.random.rand(n)-1)\n", 1334 | "plt.plot(x,y,'o',label='Noisy Data')\n", 1335 | "plt.plot(x,ye,label='True function')\n", 1336 | "plt.legend();" 1337 | ] 1338 | }, 1339 | { 1340 | "cell_type": "markdown", 1341 | "metadata": {}, 1342 | "source": [ 1343 | "Define the function we want to fit. The first argument is the independent variable, and remaining are the parameters that we want to find." 1344 | ] 1345 | }, 1346 | { 1347 | "cell_type": "code", 1348 | "execution_count": 12, 1349 | "metadata": {}, 1350 | "outputs": [], 1351 | "source": [ 1352 | "def f(x,a,b):\n", 1353 | " return a + b*x" 1354 | ] 1355 | }, 1356 | { 1357 | "cell_type": "markdown", 1358 | "metadata": {}, 1359 | "source": [ 1360 | "We can use [curve_fit](https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.curve_fit.html) function from scipy to do the fitting." 1361 | ] 1362 | }, 1363 | { 1364 | "cell_type": "code", 1365 | "execution_count": null, 1366 | "metadata": {}, 1367 | "outputs": [], 1368 | "source": [ 1369 | "from scipy.optimize import curve_fit\n", 1370 | "popt, pcov = curve_fit(f, x, y)\n", 1371 | "print('Fitted parameters = ',*popt)\n", 1372 | "plt.plot(x,y,'o',label='Noisy Data')\n", 1373 | "plt.plot(x,f(x,*popt),label='Fitted function')\n", 1374 | "plt.plot(x,ye,label='True function')\n", 1375 | "plt.legend();" 1376 | ] 1377 | }, 1378 | { 1379 | "cell_type": "markdown", 1380 | "metadata": {}, 1381 | "source": [ 1382 | "We can also use the [polyfit](https://numpy.org/doc/stable/reference/generated/numpy.polyfit.html) function or [fit](https://numpy.org/doc/stable/reference/generated/numpy.polynomial.polynomial.Polynomial.fit.html#numpy.polynomial.polynomial.Polynomial.fit) function from numpy to do this. " 1383 | ] 1384 | }, 1385 | { 1386 | "cell_type": "code", 1387 | "execution_count": null, 1388 | "metadata": {}, 1389 | "outputs": [], 1390 | "source": [ 1391 | "c = np.polyfit(x, y, deg=1)\n", 1392 | "print('Polynomial coefficients = ',c)" 1393 | ] 1394 | }, 1395 | { 1396 | "cell_type": "markdown", 1397 | "metadata": {}, 1398 | "source": [ 1399 | "The polynomials coefficients are returned in $c$ in the following order\n", 1400 | "\n", 1401 | "$$\n", 1402 | "p(x) = c[0] * x^{deg} + c[1] * x^{deg-1} + \\ldots + c[-1]\n", 1403 | "$$" 1404 | ] 1405 | }, 1406 | { 1407 | "cell_type": "code", 1408 | "execution_count": null, 1409 | "metadata": {}, 1410 | "outputs": [], 1411 | "source": [ 1412 | "p = np.poly1d(c)\n", 1413 | "plt.plot(x,y,'o',label='Noisy Data')\n", 1414 | "plt.plot(x,p(x),label='Fitted function')\n", 1415 | "plt.plot(x,ye,label='True function')\n", 1416 | "plt.legend();" 1417 | ] 1418 | } 1419 | ], 1420 | "metadata": { 1421 | "kernelspec": { 1422 | "display_name": "Python 3 (ipykernel)", 1423 | "language": "python", 1424 | "name": "python3" 1425 | }, 1426 | "language_info": { 1427 | "codemirror_mode": { 1428 | "name": "ipython", 1429 | "version": 3 1430 | }, 1431 | "file_extension": ".py", 1432 | "mimetype": "text/x-python", 1433 | "name": "python", 1434 | "nbconvert_exporter": "python", 1435 | "pygments_lexer": "ipython3", 1436 | "version": "3.12.8" 1437 | }, 1438 | "toc": { 1439 | "base_numbering": 1, 1440 | "nav_menu": {}, 1441 | "number_sections": true, 1442 | "sideBar": true, 1443 | "skip_h1_title": false, 1444 | "title_cell": "Table of Contents", 1445 | "title_sidebar": "Contents", 1446 | "toc_cell": false, 1447 | "toc_position": {}, 1448 | "toc_section_display": true, 1449 | "toc_window_display": false 1450 | }, 1451 | "vscode": { 1452 | "interpreter": { 1453 | "hash": "c6e4e9f98eb68ad3b7c296f83d20e6de614cb42e90992a65aa266555a3137d0d" 1454 | } 1455 | } 1456 | }, 1457 | "nbformat": 4, 1458 | "nbformat_minor": 4 1459 | } 1460 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A short introduction to Python for computing 2 | 3 | ## nbviewer: Read the notebooks (cannot edit or run) 4 | 5 | * [Coding tips](http://nbviewer.jupyter.org/github/cpraveen/python/blob/master/00_tips.ipynb) 6 | * [Introduction](http://nbviewer.jupyter.org/github/cpraveen/python/blob/master/01_intro.ipynb) 7 | * [Numpy](http://nbviewer.jupyter.org/github/cpraveen/python/blob/master/02_numpy.ipynb) 8 | * [Functions](http://nbviewer.jupyter.org/github/cpraveen/python/blob/master/03_functions.ipynb) 9 | * [Matplotlib](http://nbviewer.jupyter.org/github/cpraveen/python/blob/master/04_matplotlib.ipynb) 10 | * [Sympy](http://nbviewer.jupyter.org/github/cpraveen/python/blob/master/05_sympy.ipynb) 11 | * [Scipy](http://nbviewer.jupyter.org/github/cpraveen/python/blob/master/06_scipy.ipynb) 12 | 13 | ## binder: Read/edit/run the notebooks 14 | 15 | Run the code in binder: [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/cpraveen/python/HEAD). When you first click on this link, it may take a few minutes to set up the environment with all required packages. Then you can edit and run the notebooks, but you cannot save them; but you can download the notebooks to your computer. 16 | 17 | ## colab: Read/edit/run the notebooks 18 | 19 | You can see a listing of all the notebooks on colab via this url 20 | 21 | https://colab.research.google.com/github/cpraveen/python 22 | 23 | or import the individual notebooks into colab using the following links 24 | 25 | * [Introduction](http://colab.research.google.com/github/cpraveen/python/blob/master/01_intro.ipynb) 26 | * [Numpy](http://colab.research.google.com/github/cpraveen/python/blob/master/02_numpy.ipynb) 27 | * [Functions](http://colab.research.google.com/github/cpraveen/python/blob/master/03_functions.ipynb) 28 | * [Matplotlib](http://colab.research.google.com/github/cpraveen/python/blob/master/04_matplotlib.ipynb) 29 | * [Sympy](http://colab.research.google.com/github/cpraveen/python/blob/master/05_sympy.ipynb) 30 | * [Scipy](http://colab.research.google.com/github/cpraveen/python/blob/master/06_scipy.ipynb) 31 | 32 | After importing into colab, you can edit and run the notebooks but the **changes you make will not be saved**. To save your changes, you must first make a copy of the notebook into your google drive by `File --> Save a copy in drive`. 33 | 34 | ## Other resources 35 | 36 | * [Python tutorial](https://docs.python.org/tutorial) 37 | * [NumPy Illustrated](http://medium.com/better-programming/numpy-illustrated-the-visual-guide-to-numpy-3b1d4976de1d) 38 | * [Scipy Lecture Notes](http://scipy-lectures.org) 39 | * [OOP in Python for Mathematicians](https://object-oriented-python.github.io) 40 | * Markdown syntax 41 | * [The Ultimate Markdown Guide](https://medium.com/analytics-vidhya/the-ultimate-markdown-guide-for-jupyter-notebook-d5e5abf728fd) 42 | * [Working with markdown cells](https://jupyter-notebook.readthedocs.io/en/stable/examples/Notebook/Working%20With%20Markdown%20Cells.html) 43 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | # Topics 2 | 3 | ## Web pages 4 | 5 | Understanding the FFT Algorithm 6 | https://jakevdp.github.io/blog/2013/08/28/understanding-the-fft/ 7 | 8 | N-body simulations 9 | https://loiseaujc.github.io/Scientific_Computing_on_a_Laptop/Physics/NBody/NBody.html 10 | 11 | ## Books 12 | 13 | Moin: Fundamentals of engineering numerical analysis 14 | codes 15 | http://numerics.stanford.edu/ta/index.html 16 | 17 | Langtangen 18 | A Primer on Scientific Programming with Python 19 | 20 | Linge and Langtangen 21 | Programming for Computations - Python 22 | 23 | Konstantinos Anagnostopoulos, Computational Physics 24 | http://www.physics.ntua.gr/konstant/ComputationalPhysics/ 25 | 26 | Stewart: Python for Scientists 27 | 28 | ## My codes 29 | 30 | See na_book/python for some problems 31 | 32 | ## Topics to do 33 | 34 | Finite difference method 35 | FDM for 1d BVP 36 | Tri-diag algorithm 37 | Gauss-Seidel and Gauss-Jacobi 38 | 39 | Lagrange interpolation 40 | 41 | Newton method for root finding 42 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | # Book settings 2 | # Learn more at https://jupyterbook.org/customize/config.html 3 | 4 | title: Python for Scientific Computing 5 | author: Praveen Chandrashekar 6 | copyright: "2025" 7 | logo: logo.png 8 | 9 | # Force re-execution of notebooks on each build. 10 | # See https://jupyterbook.org/content/execute.html 11 | execute: 12 | execute_notebooks: force 13 | 14 | # Define the name of the latex output file for PDF builds 15 | latex: 16 | latex_documents: 17 | targetname: book.tex 18 | 19 | # Add a bibtex file so that we can create citations 20 | #bibtex_bibfiles: 21 | # - references.bib 22 | 23 | # Information about where the book exists on the web 24 | repository: 25 | url: https://github.com/cpraveen/python # Online location of your book 26 | path_to_book: docs # Optional path to your book, relative to repository root 27 | branch: master # Which branch of the repository should be used when creating links (optional) 28 | 29 | # Add GitHub buttons to your book 30 | # See https://jupyterbook.org/customize/config.html#add-a-link-to-your-repository 31 | html: 32 | use_issues_button: true 33 | use_repository_button: true 34 | use_multitoc_numbering: true # Continuous numbering across parts/chapters 35 | home_page_in_navbar: true # to include home page in the left Navigation Bar 36 | 37 | sphinx: 38 | config: 39 | mathjax_path: https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js 40 | # extra_extensions: 41 | # - sphinx_exercise 42 | # - sphinx_proof 43 | 44 | parse: 45 | myst_enable_extensions: 46 | # don't forget to list any other extensions you want enabled, 47 | # including those that are enabled by default! 48 | - amsmath 49 | - dollarmath 50 | 51 | only_build_toc_files: true 52 | -------------------------------------------------------------------------------- /_toc.yml: -------------------------------------------------------------------------------- 1 | # Table of contents 2 | # Learn more at https://jupyterbook.org/customize/toc.html 3 | 4 | format: jb-book 5 | root: front 6 | chapters: 7 | - file: 00_tips.ipynb 8 | - file: 01_intro.ipynb 9 | - file: 02_numpy.ipynb 10 | - file: 03_functions.ipynb 11 | - file: 04_matplotlib.ipynb 12 | - file: 05_sympy.ipynb 13 | - file: 06_scipy.ipynb 14 | -------------------------------------------------------------------------------- /front.md: -------------------------------------------------------------------------------- 1 | # Python 2 | 3 | ## Run on your own computer (Recommended) 4 | 5 | You can get the notebooks and run them on your own computer 6 | 7 | ```shell 8 | git clone https://github.com/cpraveen/python 9 | cd python 10 | jupyter-lab 11 | ``` 12 | 13 | ## binder: Read/edit/run the notebooks 14 | 15 | Run the code in binder: [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/cpraveen/python/HEAD). When you first click on this link, it may take a few minutes to set up the environment with all required packages. Then you can edit and run the notebooks, but you cannot save them; but you can download the notebooks to your computer. 16 | 17 | ## colab: Read/edit/run the notebooks 18 | 19 | You can see a listing of all the notebooks on colab [![Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/cpraveen/python) 20 | 21 | or import the individual notebooks into colab using the following links 22 | 23 | * [Markdown,Latex](http://colab.research.google.com/github/cpraveen/python/blob/master/00_tips.ipynb) 24 | * [Introduction](http://colab.research.google.com/github/cpraveen/python/blob/master/01_intro.ipynb) 25 | * [Numpy](http://colab.research.google.com/github/cpraveen/python/blob/master/02_numpy.ipynb) 26 | * [Functions](http://colab.research.google.com/github/cpraveen/python/blob/master/03_functions.ipynb) 27 | * [Matplotlib](http://colab.research.google.com/github/cpraveen/python/blob/master/04_matplotlib.ipynb) 28 | * [Sympy](http://colab.research.google.com/github/cpraveen/python/blob/master/05_sympy.ipynb) 29 | * [Scipy](http://colab.research.google.com/github/cpraveen/python/blob/master/06_scipy.ipynb) 30 | 31 | After importing into colab, you can edit and run the notebooks but the **changes you make will not be saved**. To save your changes, you must first make a copy of the notebook into your google drive by `File --> Save a copy in drive`. 32 | 33 | ## Installing python 34 | 35 | To install Python on windows, see [Python on Windows](https://learn.microsoft.com/en-us/windows/python/beginners). After you install Python, open PowerShell and install other modules using pip 36 | 37 | ```shell 38 | pip install numpy scipy sympy matplotlib jupyterlab 39 | ``` 40 | 41 | A better option on windows is to first install [wsl](https://learn.microsoft.com/en-us/windows/wsl/install) and then install python inside wsl. 42 | 43 | On mac, I recommend using [homebrew](https://www.brew.sh) and then 44 | 45 | ```shell 46 | brew install miniforge 47 | conda update conda 48 | conda update --all 49 | conda install numpy scipy sympy matplotlib jupyterlab 50 | ``` 51 | 52 | On Linux also, you can first install [miniforge](https://github.com/conda-forge/miniforge/releases) and then the other modules as above. 53 | 54 | ## Other resources 55 | 56 | * [Python tutorial](https://docs.python.org/tutorial) 57 | * [NumPy Illustrated](http://medium.com/better-programming/numpy-illustrated-the-visual-guide-to-numpy-3b1d4976de1d) 58 | * [Scipy Lecture Notes](http://scipy-lectures.org) 59 | * [OOP in Python for Mathematicians](https://object-oriented-python.github.io) 60 | * Markdown syntax 61 | * [The Ultimate Markdown Guide](https://medium.com/analytics-vidhya/the-ultimate-markdown-guide-for-jupyter-notebook-d5e5abf728fd) 62 | * [Working with markdown cells](https://jupyter-notebook.readthedocs.io/en/stable/examples/Notebook/Working%20With%20Markdown%20Cells.html) 63 | 64 | ## Table of contents 65 | 66 | ```{tableofcontents} 67 | ``` 68 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cpraveen/python/5ad3826a09059a28982651aa9e577c00486aa94c/logo.png -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | numpy 2 | scipy 3 | matplotlib 4 | sympy 5 | --------------------------------------------------------------------------------