{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "eaa65a42-a9a7-4420-acb7-4fee6610fa5b",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import sympy as sm \n",
    "import matplotlib.pyplot as plt\n",
    "from scipy.integrate import odeint"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a78f18ca-7b95-4f82-b501-ef9f402ecbc7",
   "metadata": {},
   "source": [
    "Dane Sabo\n",
    "October 2nd, 2024\n",
    "\n",
    "# Problem 3.7.2 (Written)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "0af0982d-25ae-4a1d-82d3-262935ab1d81",
   "metadata": {},
   "outputs": [],
   "source": [
    "def linear_phase_portrait_info(A):\n",
    "    print('\\n Input Matrix:')\n",
    "    print(A)\n",
    "    \n",
    "    print('\\n Eigenvalues and Eigenvectors:')\n",
    "    print(np.linalg.eig(A).eigenvalues)\n",
    "    print(np.linalg.eig(A).eigenvectors)\n",
    "    \n",
    "    print('\\n Trace:')\n",
    "    print(np.linalg.trace(A))\n",
    "\n",
    "    print('\\n Determinant:')\n",
    "    print(np.linalg.det(A))"
   ]
  },
  {
   "attachments": {
    "d01691d8-a1bb-4800-b2a9-2aab1a5f87e1.png": {
     "image/png": "[encoded data, 82348 characters]"
    }
   },
   "cell_type": "markdown",
   "id": "bafdbc61-fba6-490b-8793-6b1820d6fbd4",
   "metadata": {},
   "source": [
    "Sketch phase portraits for the following linear systems:\n",
    "## $\\dot x = 0$, $\\dot y = x + 2y$\n",
    "![image.png](attachment:d01691d8-a1bb-4800-b2a9-2aab1a5f87e1.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "37b37e65-7ade-473e-82ff-6391c6c6fe1d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      " Input Matrix:\n",
      "[[0 0]\n",
      " [1 2]]\n",
      "\n",
      " Eigenvalues and Eigenvectors:\n",
      "[2. 0.]\n",
      "[[ 0.          0.89442719]\n",
      " [ 1.         -0.4472136 ]]\n",
      "\n",
      " Trace:\n",
      "2\n",
      "\n",
      " Determinant:\n",
      "0.0\n"
     ]
    }
   ],
   "source": [
    "A = np.array([[0,0],[1,2]])\n",
    "linear_phase_portrait_info(A)"
   ]
  },
  {
   "attachments": {
    "0899edc5-4cee-48b4-9c07-1cff2f5e8c21.png": {
     "image/png": "[encoded data, 75668 characters]"
    }
   },
   "cell_type": "markdown",
   "id": "966ca5a8-bcf4-4860-b923-f5cca9f6e1de",
   "metadata": {},
   "source": [
    "## $\\dot x = x+2y$, $\\dot y = 0$\n",
    "![image.png](attachment:0899edc5-4cee-48b4-9c07-1cff2f5e8c21.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "6e05a8d7-7bf6-4520-a3b6-0848d067b189",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      " Input Matrix:\n",
      "[[1 2]\n",
      " [0 0]]\n",
      "\n",
      " Eigenvalues and Eigenvectors:\n",
      "[1. 0.]\n",
      "[[ 1.         -0.89442719]\n",
      " [ 0.          0.4472136 ]]\n",
      "\n",
      " Trace:\n",
      "1\n",
      "\n",
      " Determinant:\n",
      "0.0\n"
     ]
    }
   ],
   "source": [
    "A = np.array([[1,2],[0,0]])\n",
    "linear_phase_portrait_info(A)"
   ]
  },
  {
   "attachments": {
    "5974ad1f-cbc4-453e-8054-bed45767ad1d.png": {
     "image/png": "[encoded data, 117804 characters]"
    }
   },
   "cell_type": "markdown",
   "id": "0179406c-daa5-47bf-a10f-126f1ffe92c4",
   "metadata": {},
   "source": [
    "## $\\dot x = 3x+4y$, $\\dot y = 4x - 3y$\n",
    "![image.png](attachment:5974ad1f-cbc4-453e-8054-bed45767ad1d.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "0c198580-fd00-43d8-aeb7-947c88f449c0",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      " Input Matrix:\n",
      "[[ 3  4]\n",
      " [ 4 -3]]\n",
      "\n",
      " Eigenvalues and Eigenvectors:\n",
      "[ 5. -5.]\n",
      "[[ 0.89442719 -0.4472136 ]\n",
      " [ 0.4472136   0.89442719]]\n",
      "\n",
      " Trace:\n",
      "0\n",
      "\n",
      " Determinant:\n",
      "-25.000000000000007\n"
     ]
    }
   ],
   "source": [
    "A = np.array([[3,4],[4,-3]])\n",
    "linear_phase_portrait_info(A)"
   ]
  },
  {
   "attachments": {
    "fb789093-43c3-4be4-bcbc-f005fd2d5dc9.png": {
     "image/png": "[encoded data, 105416 characters]"
    }
   },
   "cell_type": "markdown",
   "id": "a41e8548-555b-4701-bad7-9049cb395dec",
   "metadata": {},
   "source": [
    "## $\\dot x = 3x+y$, $\\dot y = -x + 3y$\n",
    "![image.png](attachment:fb789093-43c3-4be4-bcbc-f005fd2d5dc9.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "40cd3d5a-a712-4fab-94bb-8148d2fd61ad",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      " Input Matrix:\n",
      "[[ 3  1]\n",
      " [-1  3]]\n",
      "\n",
      " Eigenvalues and Eigenvectors:\n",
      "[3.+1.j 3.-1.j]\n",
      "[[0.70710678+0.j         0.70710678-0.j        ]\n",
      " [0.        +0.70710678j 0.        -0.70710678j]]\n",
      "\n",
      " Trace:\n",
      "6\n",
      "\n",
      " Determinant:\n",
      "10.000000000000002\n"
     ]
    }
   ],
   "source": [
    "A = np.array([[3,1],[-1,3]])\n",
    "linear_phase_portrait_info(A)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0b285873-d263-4b48-b792-a8ac6a1e48b3",
   "metadata": {},
   "source": [
    "# Problem 3.7.4 (Python)\n",
    "Plot the phase portraits for the following systems:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "34f3f9f8-8c8c-4e08-aad4-e019b8f992d6",
   "metadata": {},
   "outputs": [],
   "source": [
    "def phase_portrait(P, Q, ts = [1], ic = [1]):\n",
    "    \"\"\"\n",
    "    A function that takes in a P and Q as lambda functions, and plots some stuff with them\n",
    "    Parameters:\n",
    "    P: first differential equation as a lambda function of two variables\n",
    "    Q: Second differential equation as a lambda function of two variables\n",
    "    ts (OPTIONAL): A np.linspace of the time domain for trajectory solutions\n",
    "    ic (OPTIONAL): A np.linspace of initial spacial conditions\n",
    "\n",
    "    Returns:\n",
    "    None. It does print a graph though that is titled with the functions, includes a quiver plot, a trajectory sampling, and the critical points.\n",
    "    \"\"\"\n",
    "    #Create symbolic variables\n",
    "    x, y = sm.symbols('x,y')\n",
    "\n",
    "    #def differential equation\n",
    "    def dX_dt(X,t, args = (P,Q)):\n",
    "        return [P(X[0],X[1]), Q(X[0],X[1])]\n",
    "    \n",
    "    #Set P(x,y) = 0 and Q(x,y) = 0\n",
    "    Peqn = sm.Eq(P(x,y),0)\n",
    "    Qeqn = sm.Eq(Q(x,y),0)\n",
    "\n",
    "    #solve our equations for populations of species of x and y\n",
    "    criticalpoints = sm.solve((Peqn,Qeqn),x,y)\n",
    "    print('Critical Points:')\n",
    "    print(criticalpoints)\n",
    "\n",
    "    #Set up Time and Initial Condition Domains\n",
    "    ts = np.linspace(0,0.01,10) if ts[0] == 1 else ts\n",
    "    ic = np.linspace(-4, 4, 25) if ic[0] == 1 else ic\n",
    "    \n",
    "    #calculate a vectorfield\n",
    "    X,Y = np.mgrid[ic[0]:ic[-1]:20j,ic[0]:ic[-1]:20j]\n",
    "    u = P(X,Y)\n",
    "    v = Q(X,Y)\n",
    "    plt.quiver(X,Y,u,v,color = \"red\")\n",
    "   \n",
    "    #plot trajectories\n",
    "    plt.title(f'Phase Portrait for $\\\\dot x = $ {Peqn.lhs} and $\\\\dot y = $ {Qeqn.lhs}')\n",
    "    plt.xlabel('x'); plt.ylabel('y'); plt.grid('both')\n",
    "    plt.xlim((ic[0],ic[-1])); plt.ylim((ic[0],ic[-1]))\n",
    "    \n",
    "    for r in ic:\n",
    "        for s in ic:\n",
    "            X0 = [r,s]\n",
    "            Xs = odeint(dX_dt,X0,ts)\n",
    "            plt.plot(Xs[:,0],Xs[:,1], \"royalblue\",linewidth = 0.75)\n",
    "\n",
    "    for i in range(np.size(criticalpoints)//2):\n",
    "        #Do NOT print imaginary critical points\n",
    "        if sm.im(criticalpoints[i][0]) == 0 and sm.im(criticalpoints[i][1]) == 0:\n",
    "            plt.plot(criticalpoints[i][0],criticalpoints[i][1],\"yo\")\n",
    "            "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1b9e78d5-bf56-46af-b672-35290d33b788",
   "metadata": {},
   "source": [
    "## $\\dot x = y$, $\\dot y = x-y+x^3$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "21643903-10a1-47ca-b449-4dcb6a4819e7",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Critical Points:\n",
      "[(0, 0), (-I, 0), (I, 0)]\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 97688 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "P = lambda x, y: y\n",
    "Q = lambda x, y: x - y + x**3\n",
    "phase_portrait(P, Q, ic = np.linspace(-1, 1, 10))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c6c01322-669f-4bd4-8727-addd978c85e2",
   "metadata": {},
   "source": [
    "## $\\dot x = -2x-y+2$, $\\dot y = xy$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "cd100989-95c4-4d6e-87a2-23468c3e7d30",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Critical Points:\n",
      "[(0, 2), (1, 0)]\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 276960 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "P = lambda x, y: -2*x - y + 2\n",
    "Q = lambda x, y: x*y \n",
    "phase_portrait(P, Q, ts = np.linspace(0,0.1,10))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "91f924f6-1567-47c9-893a-93cbf5753b98",
   "metadata": {},
   "source": [
    "## $\\dot x = x^2- y^2$, $\\dot y = xy-1$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "d9c0e844-0458-4025-87a6-2b7f0332e8f5",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Critical Points:\n",
      "[(-1, -1), (1, 1), (-I, I), (I, -I)]\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 381272 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "P = lambda x, y: x**2 - y**2\n",
    "Q = lambda x, y: x*y - 1\n",
    "phase_portrait(P, Q, ts = np.linspace(0,0.2,10))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "312d3ea7-a2c1-4db3-9aef-d4882adba1f3",
   "metadata": {},
   "source": [
    "## $\\dot x = 2-x-y^2$, $\\dot y = -y(x^2 + y^2 -3x +1)$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "cfb3f6a8-fcf2-4669-a566-21ceea20b5ca",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Critical Points:\n",
      "[(1, -1), (1, 1), (2, 0), (3, -I), (3, I)]\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 143696 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "P = lambda x, y: 2 - x - y**2\n",
    "Q = lambda x, y: -y*(x**2 + y**2 - 3*x +1)\n",
    "phase_portrait(P, Q, ic = np.linspace(-2.5, 2.5, 10), ts = np.linspace(0,0.2,10))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "12ad95a7-06dd-45b9-8d48-4a7e0451422e",
   "metadata": {},
   "source": [
    "# Problem 3.7.5 (Written)\n",
    "Construct a nonlinear system that has four critical points: two saddle points, one stable focus, and one unstable focus."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "c9952ccd-c6f1-48e4-b017-901cbcbda30f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Critical Points:\n",
      "[(-1, -1), (-1, 1), (1, -1), (1, 1)]\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 593052 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "P = lambda x, y: y**2 - x**2\n",
    "Q = lambda x, y: x**2 + y**2 - 2\n",
    "phase_portrait(P, Q, ic = np.linspace(-5, 5, 50), ts = np.linspace(0,0.1,10))"
   ]
  },
  {
   "attachments": {
    "4daa77bd-5d29-4de6-9b1f-c7a041f4a1d9.png": {
     "image/png": "[encoded data, 233472 characters]"
    },
    "7925aa33-8674-4fa4-b3a6-8abbfca8d3d1.png": {
     "image/png": "[encoded data, 146860 characters]"
    },
    "a0dfefa6-e3d0-45f3-a202-e1efc5e05126.png": {
     "image/png": "[encoded data, 55268 characters]"
    },
    "e211a4e7-9648-4205-a310-a5fb97e455df.png": {
     "image/png": "[encoded data, 154756 characters]"
    }
   },
   "cell_type": "markdown",
   "id": "cf8225d4-cedb-4daa-a7b0-ef9b032c4c92",
   "metadata": {},
   "source": [
    "![image.png](attachment:4daa77bd-5d29-4de6-9b1f-c7a041f4a1d9.png)\n",
    "\n",
    "# Problem 3.7.6 (Written)\n",
    "A nonlinear capacitor-resistor electrical circuit can be modeled using the differential equations\n",
    "$$ \\dot x = y $$\n",
    "$$\\dot y = -x + x^3 - (a_0 + x)y$$\n",
    "where $a_0$ is a nonzero constant and $x(t)$ represents the current in the circuit at time t. Sketch phase portraits when $a_0 > 0$ and $a_0<0$ and give a physical interpretation of the results.\n",
    "\n",
    "![image.png](attachment:a0dfefa6-e3d0-45f3-a202-e1efc5e05126.png)\n",
    "![image.png](attachment:7925aa33-8674-4fa4-b3a6-8abbfca8d3d1.png)\n",
    "![image.png](attachment:e211a4e7-9648-4205-a310-a5fb97e455df.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "66d21987-bc58-4f31-af7b-94bcaf967921",
   "metadata": {},
   "source": [
    "# Problem 4.5.6 (Python)\n",
    "A predator-prey system may be modeled using the differential equations\n",
    "$$ \\dot x = x (1-y-\\epsilon x)$$\n",
    "$$ \\dot y = y (-1 + x - \\epsilon y)$$\n",
    "where $x(t)$ is the population of prey and $y(t)$ is the predator population size at time t, respectively. Classify the critical points for $\\epsilon>0$ and plot phase portraits for the different types of qualitative behavior. Interpret the results in physical terms"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "25d02f81-4f3e-4c3d-be5a-10cb44d4f674",
   "metadata": {},
   "source": [
    "| Critical Point | Type | \n",
    "|-------|------|\n",
    "|(0,0)| Saddle |\n",
    "|(1,0)| Stable Spiral |\n",
    "|(0,-1) | Unstable Spiral |"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6e91b45e-6c4c-4088-9b21-0d88f5b1b5d1",
   "metadata": {},
   "source": [
    "When $\\epsilon$ is positive, this means that a certain number of the species die off on their own over time. The positive $\\epsilon$ directly results in a negative feedback loop on number of individuals.\n",
    "\n",
    "You can see this in the top right quadrant, which is the only case that is physically possible with positive numbers of both predator and prey. Over time, all trajectories settle on (1,0), where there is a baseline number of prey but no predators remain."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "65bb6eb8-b1b0-48c5-a4e3-bda1fc1462b0",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Critical Points:\n",
      "[(0, -1), (0, 0), (1, 0)]\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 303420 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "epsilon = 1\n",
    "P = lambda x, y: x*(1-y-epsilon*x)\n",
    "Q = lambda x, y: y*(-1 + x- epsilon*y)\n",
    "phase_portrait(P, Q, ic = np.linspace(-1.51, 1.51, 35), ts = np.linspace(0,-0.1,5))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1f41074b-df48-45d4-ad2f-b8a420fa9277",
   "metadata": {},
   "source": [
    "When $\\epsilon$ is between -1 and 1, the two species have feedback on their own population that changes where equilibrium is, but a stable equilibrium point exists. When $\\epsilon$ is 0, the species are perfectly balanced and will travel around a stable center. Otherwise, the species have some damping introduced, and will converge to a stable spiral."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "8eabf65c-8f00-4602-b5da-328856a42b59",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Critical Points:\n",
      "[(0, 0), (1, 1)]\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 262128 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "epsilon = 0\n",
    "P = lambda x, y: x*(1-y-epsilon*x)\n",
    "Q = lambda x, y: y*(-1 + x- epsilon*y)\n",
    "phase_portrait(P, Q, ic = np.linspace(-1.51, 1.51, 35), ts = np.linspace(0,-0.1,5))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "aa854b6c-c9d3-4417-b8f6-06700f767b34",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Critical Points:\n",
      "[(0.0, -2.00000000000000), (0.0, 0.0), (1.20000000000000, 0.400000000000000), (2.00000000000000, 0.0)]\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 287112 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "epsilon = 0.5\n",
    "P = lambda x, y: x*(1-y-epsilon*x)\n",
    "Q = lambda x, y: y*(-1 + x- epsilon*y)\n",
    "phase_portrait(P, Q, ic = np.linspace(-1.51, 1.51, 35), ts = np.linspace(0,-0.1,5))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3a832de9-63eb-4e15-858e-9932d0f328cc",
   "metadata": {},
   "source": [
    "When $\\epsilon$ is -1 or less, there is actually positive feedback on species population. This is an unstable system, as we can see populations in the top right quadrant skyrocket."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "4e60b912-db35-483f-87b2-408f052076d0",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Critical Points:\n",
      "[(-1, 0), (0, 0), (0, 1)]\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 319036 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "epsilon = -1\n",
    "P = lambda x, y: x*(1-y-epsilon*x)\n",
    "Q = lambda x, y: y*(-1 + x- epsilon*y)\n",
    "phase_portrait(P, Q, ic = np.linspace(-1.51, 1.51, 35), ts = np.linspace(0,-0.1,15))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
