{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![](img/logocurso.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "nbpresent": {
     "id": "d9e822f9-0a52-43f2-90ef-e8fd6860aacc"
    }
   },
   "source": [
    "![](img/sesion5.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Introducción a Sympy\n",
    "\n",
    "Sympy es un paquete que añade a Python clases, objetos y métodos (nuevos tipos de datos) que permiten el tratamiento simbólico de expresiones matemáticas. Los tipos de datos que Python incorpora por defecto (int,float) y su sistema de gestión de variables permiten solamente un tratamiento numérico que no hace posible un correcto manejo de buena parte de los problemas matemáticos abstractos.\n",
    "\n",
    "<div style=\"background:rgb(200,150,150);\"><b>Números y precisión numérica</b></div>Con Python podemos realizar operaciones como $\\sqrt{8}$ pero los cálculos se apoyarán en la representación de los números involucrados mediante expresiones con una cantidad finita de decimales (float) lo que inevitablemente conduce a la pérdida de precisión y así los resultados que obtengamos no podrán jamás ser exactos y proporcionarán únicamente aproximaciones."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "8**(1/2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "En un sentido matemático estricto, afirmar que $\\sqrt{8}$=2.8284271247461903 es pura y simplemente falso ya que, en realidad $\\sqrt{8}$ es un número que tiene infinitos decimales no periódicos y no puede por tanto ser representado mediante un float que tendrá necesariamente una precisión limitada a lo sumo a 16 o 18 dígitos. Si deseamos mantener la exatitud completa de un cálculo debemos disponer de operaciones y tipos de números que sean capaces de trabajar con expresiones simbólicas sin necesidad de recurrir a cálculos con decimales. Esos nuevos tipos de números, esas nuevas clases que permiten el cálculo simbólico podemos encontrarlas en Sympy."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div style=\"background:rgb(200,150,150);\"><b>Variables simbólicas</b></div>En Python toda variable debe tener un valor asignado. No se permite entonces el manejo de variables simbólicas. Cuando en matemáticas utilizamos expresiones como $x^3-3x^2+2x+1$ se está implícitamente trabajando con un símbolo $x$ al que efectivamente llamamos variable pero que no tiene ningún valor concreto ya que deseamos obtener conclusiones válidas en general y no para posibles valores específicos de $x$. Las variables de Python no son válidas para recrear el comportamiento que tiene una variable matemática abstracta. Sin ese tipo de variables simbólicas no podremos abordar problemas propios del análisis o del álgebra como la resolución de ecuacones, cálculo de derivadas o integrales ni representar adecuadamente la mayoría de los objetos matemáticos. Nuevamente Sympy viene en nuestra ayuda incorporando un completo sistema para el manejo de símbolos, variables, funciones y ecuaciones."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Comenzar a usar Sympy\n",
    "\n",
    "Sympy es un paquete adicional que debe importarse antes de ser utilizado ya que incorpora clases que no están definidas en el lenguaje estándar de Python. En principio sería necesario descargar el paquete de la red y posteriormente instalarlo sin embargo Anaconda incluye Sympy entre la lista de paquetes que integra por defecto así que simplemente necesitaremos importarlo mediante:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sympy import *"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Numeros Sympy\n",
    "\n",
    "Sympy incorpora dos nuevas clases de números:\n",
    "* **Integer**: para números enteros.\n",
    "* **Rational**: para números racionales (fracciones de números enteros)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "log(S(6)/7)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-info\">Las tres reglas de exactitud de Sympy:\n",
    "<ol>\n",
    "<li>Las clases Integer y Rational son considerados números exactos y nunca se transformarán en un número con decimales (float) que es un número aproximado. En diversas situaciones para ajustarse a este criterio Sympy se verá obligado a dejar operaciones indicadas sin realizar.</li>\n",
    "<li>Las operaciones e instrucciones de Sympy, siguen la regla: si reciben datos exactos Integer y Rational el resultado se ofrecera también mediante datos exactos (sin utilizar float).</li>\n",
    "<li>Las operaciones e instrucciones de Sympy convertirán por defecto, siempre que sea posible, un número int the Python en un dato exacto Integer de Sympy.</li>\n",
    "</ol>\n",
    "</div>\n",
    "\n",
    "Es importante darse cuenta de que las clase int de Python sigue existiendo en las mismas condiciones y con el mismo comportamiento que antes de importar Sympy:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "log(3+5/7)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "La clase int de Python no está sometida a los mismos requisitos de exactitud que Integer o Rational de Sympy y es por ello que siempre ofrece un resultado aunque para obtenerlo tenga que recurrir a mostrarlo mediante un número aproximado, float."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Junto con Integer y Rational habremos importado las demás instrucciones y clases de Sympy que ahora podremos utilizar. Por ejemplo, sqrt (de **s**quare **r**oo**t**) es una instrucción de Sympy para el cálculo de la raíz cuadrada. Podemos ver cómo, para calcular $\\sqrt{8}$, ahora el tratamiento es diferente al que hace Python con sus operaciones estándar."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sqrt(8)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Aquí se han aplicado las tres reglas de exactitud de Sympy. 1) la instrucción sqrt convierte el int 8 en Integer(8), 2) y 3) puesto que se dispone de datos exactos, el resultado será exacto expresado mediante números Integer o Rational. La expresión que obtenemos está simplificada en el sentido de que deja dentro de la raiz el factor más pequeño posible. Lo importante aquí es que el orden de exactitud se preserva ya que ahora sí $\\sqrt{8}=2\\sqrt{2}$."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-info\">\n",
    "<ul>\n",
    "    <li>Para escribir el número $\\pi$ simplemente pondremos <b>pi</b>.</li>\n",
    "    <li>Para el número $e$ utilizaremos <b>E</b>.</li>\n",
    "</ul>\n",
    "    Tanto <b>pi</b> como <b>E</b> son considerados también datos exactos.\n",
    "</div>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-info\">\n",
    "Es posible forzar la evaluación de una operación para obtener un resultado con decimales mediante la instrucción <b>evalf()</b>. Podemos indicar además un orden de precisión n mediante <b>evalf(n)</b>.\n",
    "<br><br>\n",
    "De modo inverso, posemos utilizar la instrucción <b>simpify(expresion)</b> o simplemente <b>S(expresion)</b> para transformar expresion en un objeto de Sympy.\n",
    "<br><br>\n",
    "Cuando se aplica <b>simpify</b> o <b>S</b> a una cadena de texto se produce la conversión de todos los datos matemáticos a objetos Sympy. Ello es útil para transformar a objetos sympy todos los datos de expresiones largas o complejas.\n",
    "</div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pi.evalf(100)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Siguiendo las reglas de precisión de Python, esta operacion no se ejecutará ya que para expresar su resultado es\n",
    "# necesario un número con infinitos decimales y es imposible expresarlo con total exactitud mediante decimales. \n",
    "# La única manera de ofrecer un resultado con total precisión es dejar la expresión sin evaluar.\n",
    "\n",
    "pi+E**2+pi"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Podemos forzar la evaluación mediante decimales utilizando evalf\n",
    "\n",
    "(pi+E**2).evalf(50)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Por defecto Python utiliza sus tipos de números int y float para evaluar una expresión. Si no lo indicamos explícitamente,\n",
    "# se aplicarán las reglas correspondientes a estos tipos que implican la pérdida de precisión en los cálculos\n",
    "\n",
    "3+2/7"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Pero cuidado, Python es pertinaz:\n",
    "S(3)+S(2/7)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Ahora forzamos a que todos los datos de la expresión se transformen en objetos integer the Sympy:\n",
    "S(\"3+2/7\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Hubiera bastado con aplicar S() a alguno de los datos de la división o con utilizar rational:\n",
    "display(3+S(2)/7)\n",
    "display(3+Rational(2,7))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-info\">\n",
    "Si deseamos que los resultados se muestren empleando un formato mas visual utilizaremos\n",
    "    <div align=\"center\"><b>init_printing()</b></div>\n",
    "que fuerza a Sympy a conectar con el mejor sistema de impresión de expresiones disponible en el equipo.\n",
    "</div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "init_printing()\n",
    "S(\"(1+pi**2)/(sqrt(pi)+E**pi)\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Ejercicio 1\n",
    "\n",
    "Calcular $cos(1)$. Calcular $cos(1)$ con 100 decimales de precision."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Ejercicio 2\n",
    "\n",
    "Calcular $cos\\left(\\frac{1}{2}\\right)$. Calcular $cos\\left(\\frac{1}{2}\\right)$ con 100 decimales de precision."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Ejercicio 3\n",
    "Calcular el valor de $\\frac{e^2+\\frac{5}{2}}{\\pi^2+1}+\\cos\\left(\\frac{7}{2}\\right)$ con 50 decimales de precisión."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Símbolos Sympy\n",
    "\n",
    "Puesto que las variables Python no son adecuadas para trabajar con expresiones abstractas y por ello Sympy proporciona una nueva clase Symbol. Los objetos de la clase Symbol se comportan como variables sin valor asignado y pueden incluirse en expresiones matemáticas complejas y ecuaciones. La instrución symbols permite crear un objeto de la clase Symbol y asignarle un nombre. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Creamos un objeto Symbol cuyo nombre será \"x\" y lo asignamos a la variable Python x\n",
    "x,y,z=symbols(\"x,y,z\")\n",
    "\n",
    "# Podemos, como vemos, declarar varios símbolos con una sola instrucción\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ahora podemos utilizar y manipular fórmulas en las que intervienen estos tres símbolos"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "expr=(x**2+y)**2\n",
    "expr+x+x"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-info\">\n",
    "Sympy incorpora multitud de instrucciones para menejar expresiones abstractas que involucran símbolos:\n",
    "<ul>\n",
    "<li><b>simplify(expr)</b> o <b>expr.simplify()</b>: simplifica la expresión.</li>\n",
    "<li><b>expand(expr)</b> o <b>expr.expand()</b>: realiza las operaciones, productos y potencias, indicadas en la expresión.</li>\n",
    "<li><b>factor(expr)</b> o <b>expr.factor()</b>: realiza las factorización (polinomial, en principio) de la expresión.</li>\n",
    "<li><b>collect(expr,var)</b>: agrupa por coeficientes de la variable var.</li>\n",
    "<li><b>cancel(expr)</b>: simplifica fracciones.</li>\n",
    "<li><b>apart(expr)</b>: descompone una fracción en fracciones simples.</li>\n",
    "<li><b>together(expr)</b>: suma fracciones.</li>\n",
    "<li><b>numer(frac)</b>, <b>denom(frac)</b>: proporcionan, respectivamente, el numerador y denominador de la fracción <b>frac</b>.</li>\n",
    "<li><b>fraction(frac)</b>: proporcionan una lista con el numerador y denominador de <b>frac</b>.</li>\n",
    "</ul>\n",
    "</div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "simplify(sin(x)**2+cos(x)**2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "# Solamente realizan las simplificaciones que son ciertas para cualquier valor de x\n",
    "simplify(sqrt(x**2))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "((x+y)**2+(x-1)**2).expand()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "factor(x**3*y - 2*x**3 - x**2*y**2 + 4*x**2 + 2*x*y**2 - 3*x*y - 2*x - y**2 + 2*y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "collect(x**3*y - 2*x**3 - x**2*y**2 + 4*x**2 + 2*x*y**2 - 3*x*y - 2*x - y**2 + 2*y,x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "cancel((x**2-2*x+1)/(x**2-1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "apart((4*x-5)/(x**2-3*x+2))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "together(1/(x-1)+3/(x-2))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "numer(_),denom(_),fraction(_)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x=5\n",
    "cancel((x**2-2*x+1)/(x**2-1))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "<div class=\"alert alert-info\">Para sustituir un Simbolo de una expresión por un valor concreto empleamos la instrucción <b>subs</b>\n",
    "</div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# En la expresión que hemos definido antes sustituimos el símbolo x por un 1.\n",
    "x=symbols(\"x\")\n",
    "print(\"expr=\",expr)\n",
    "expr.subs(x,1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "# Podemos sistituir varios símbolos a un tiempo.\n",
    "expr.subs([(x,1),(y,2)])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "El comportamiento de las variables simbólicas en Sympy no es como en Mathematica. En primer lugar, las siguientes lineas ofreceran error:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "y=t**2+t+1\n",
    "t=1\n",
    "y"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Hay siempre que tener presente que en Python las variables deben tener algún valor antes de poder utilizadas."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "t=symbols(\"t\")\n",
    "y=t**2+t+1\n",
    "t=1\n",
    "y"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "### Ejercicio 4\n",
    "Simplificar la expresión $\\frac{x^5+x^4-2x^3-2x^2+x+1}{x^4-2x^2+1}$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Ejercicio 5\n",
    "Dar una fórmula para $(a+b)^3$, $(a+b+c)^2$ y $(a+b)^4$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Ejercicio 6\n",
    "Almacenar la expresión $\\frac{x^2\\cos(z)+\\pi xyz}{\\frac{x y}{2}+x^y}$ en una variable. Sustituir en la expresión para calcular el valor, con 50 decimales de precisión, que se obtiene para $x=k \\pi$, $y=1$, $z=1$ con $k=1,2,\\ldots,10$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Ejercicio 7\n",
    "Definir una función que proporcione el decimal numero n de $\\pi$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "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.9.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
