# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# # Examen Módulo 3 - Optimización. <font color=blue>Tipo de examen 1</font>.
# Lea cuidadosamente las siguientes **indicaciones** antes de comenzar el examen:
# - Para resolver el examen edite este mismo archivo y renómbrelo de la siguiente manera: *Examen3_ApellidoNombre*, donde *ApellidoNombre* corresponde a su apellido paterno con la inicial en mayúscula, seguido de su primer nombre con la inicial en mayúscula **sin acentos**. Por ejemplo, en mi caso el nombre del archivo sería *Examen3_JimenezEsteban*.
# - Resuelva los puntos en el espacio provisto. Si requiere agregar más celdas para código o escritura, hágalo.
# - Recuerde que también se está evaluando su capacidad de interpretar los resultados. Escriba sus interpretaciones/conclusiones en celdas utilizando *Markdown*.
# - El formato de presentación de todo el examen en general debe ser adecuado. Use tamaños de letra, colores, etiquetas, etcétera.
# - No se resuelven dudas de ningún tipo por los profesores de la asignatura. Por favor, absténgase de preguntar.
# - Revise bien el tipo de examen. Sólo se le calificará si realiza el tipo de examen asignado.

# ## Primer punto. Optimización de funciones escalares usando `sympy` (30 puntos).
#
# **Enunciado.** Calcular **las dimensiones** del rectángulo de área máxima que puede inscribirse dentro de un semicírculo de radio 2.
#
# Note que **las dimensiones** son base $b = 2x$ y altura $h = y$. Ver la siguiente figura.

import numpy as np
import matplotlib.pyplot as plt
# %matplotlib inline

# +
x = np.linspace(-2, 2, 100)
y = np.sqrt(4 - x**2)

xr = [-1.5, -1.5, 1.5, 1.5, -1.5]
yr = [0, np.sqrt(4 - 1.5**2), np.sqrt(4 - 1.5**2), 0, 0]

xx = [0, 1.5]
yx = [0, 0]

xy = [1.5, 1.5]
yy = [0, np.sqrt(4 - 1.5**2)]

plt.figure(figsize = (12, 6))
plt.plot(x, y, 'b', label = 'semicírculo')
plt.plot(xr, yr, 'r', label = 'rectángulo')
plt.plot(xx, yx, 'k')
plt.plot(xy, yy, 'g')
plt.text(0.7, 0.1, '$x$', fontsize = 16)
plt.text(1.6, 0.6, '$y$', fontsize = 16, color = 'g')
plt.legend(loc = 'best')
plt.show()
# -

# **Punto 1 (10 puntos).** Encuentre el área del rectángulo en función de la variable $x$, $A_R(x)$. También provea el dominio de la función para que tenga sentido.
#
# Realice este punto usando fórmulas en LaTeX, en celdas Markdown.

# **Solución punto 1.**

# Tenemos que el área del rectángulo es
#
# $$A_R=bh.$$
#
# Sin embargo, la base es $b=2x$, mientras que la altura es $h=y$. De manera que
#
# $$A_R=2xy.$$
#
# Como el punto $(x,y)$ se encuentra inscrito en el semicírculo, y se puede escribir en términos de x como
#
# $$y=\sqrt{4-x^2}.$$
#
# Reemplazando esto último en la fórmula del área, tenemos que el área del rectángulo en función de x es
#
# $$A_R=2x\sqrt{4-x^2}.$$
#
# Entonces, el dominio de la función es
#
# $$\text{Dom}_{A_R}=[0,2].$$
#

# **Punto 2 (10 puntos).** Usando `sympy` maximice la función $A_R(x)$ en su dominio.

# **Solución punto 2.**

#importamos la librería sympy
import sympy as sym
sym.init_printing(use_latex='mathjax')

#declaramos la variable simbólica x
sym.var('x')


#definimos la función
def AR(x):
    return 2*x*(4-x**2)**(1/2)


#derivamos funcion AR(X)
dAR = sym.diff(AR(x),x)
dAR

#Hallamos puntos críticos
xc = sym.solve(dAR,x)
xc

#evaluamos en extremos y puntos críticos
AR(0), AR(xc[1]), AR(2)

# El máximo de la función $A_R(x)$ en su dominio es $4$, y ocurre cuando $x=1.4142135623731$.$$

# **Punto 3 (10 puntos).** ¿Cuáles son las dimensiones $b$ y $h$ del rectángulo resultante?

# **Solución punto 3.**

# Las dimensiones del rectángulo resultante son:
# $$b=2x$$

b = 2*xc[1]
b

# $$h=y=\sqrt{4-x^2}$$

h=(4-xc[1]**2)**(1/2)
h

# ## Segundo punto. Programación lineal (35 puntos).

# **Enunciado.** Considere un restaurante que abre los siete días de la semana. Con base en la experiencia, el mínimo número de trabajadores necesarios en cada día de la semana es:

import pandas as pd

df = pd.DataFrame(columns=['Lunes', 'Martes', 'Miercoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'], index = ['Num_trabajadores'])
df.loc['Num_trabajadores', :] = [14, 13, 15, 16, 19, 18, 11]
df

# Cada trabajador trabaja cinco días consecutivos, y luego descansa dos, repitiendo este patrón indefinidamente. Se debe minimizar la cantidad de trabajadores totales en el restaurante.
#
# *Definición de variables*: enumeramos los días del uno al siete (Lunes - 1, Martes - 2, ..., Domingo - 7). Sea $x_i$ el número de trabajadores que empieza su turno de cinco días el día $i$.

# **Punto 1 (20 puntos).** Escriba la función a minimizar junto con las restricciones, explicando detalladamente cada paso (usando fórmulas en LaTeX, en celdas Markdown). Además escriba el problema en la forma 
# \begin{equation}
# \begin{array}{ll}
# \min_{\boldsymbol{x}} & \boldsymbol{c}^T\boldsymbol{x} \\
# \text{s. a. }        & \boldsymbol{A}_{eq}\boldsymbol{x}=\boldsymbol{b}_{eq} \\
#                      & \boldsymbol{A}\boldsymbol{x}\leq\boldsymbol{b},
# \end{array}
# \end{equation}
#
# proporcionando $\boldsymbol{c}$, $\boldsymbol{A}$ y $\boldsymbol{b}$ ($\boldsymbol{A}_{eq}$ y $\boldsymbol{b}_{eq}$, de ser necesario) como arreglos de `NumPy` (no es necesario escribir en LaTeX el problema en la forma indicada, solo proporcionar las matrices como arreglos de `NumPy`).

# **Solución punto 1.**

# Como se quiere minimizar el total de trabajadores, entonces el problema es
#
# $$\min_{x_1,x_2,\dots,x_7}x_1+x_2+\dots,+x_7.$$
#
# Además, por la tabla proporcionada arirba, las restricciones son:
#
# $$x_1+x_4+x_5+x_6+x_7\geq14$$
# $$x_1+x_2+x_5+x_6+x_7\geq13$$
# $$x_1+x_2+x_3+x_6+x_7\geq15$$
# $$x_1+x_2+x_3+x_4+x_7\geq16$$
# $$x_1+x_2+x_3+x_4+x_5\geq19$$
# $$x_2+x_3+x_4+x_5+x_6\geq18$$
# $$x_3+x_4+x_5+x_6+x_7\geq11$$
#
# Así se hace el menor o igual $\leq$
#
#

# Escriba acá las matrices como arreglos de Numpy
c = np.ones(7)
A = -np.array([[1,0,0,1,1,1],
               [1,1,0,0,1,1],
               [1,1,1,0,0,1],
               [1,1,1,1,0,0],
               [0,1,1,1,1,0],
               [0,0,1,1,1,1]])
b = -np.array([14,13,15,16,19,18,11])

# **Punto 2 (15 puntos).** Resuelva el problema utilizando la función `linprog`. ¿Cuántos trabajadores son necesarios en total?

import scipy.optimize as opt
trabajadores = opt.linprog(c, A_ub=A, b_ub=b)
trabajadores

# Son necesarios 22 trabajadores en total.



# *Conclusión*

# ## Tercer punto. Ajuste de curvas (35 puntos).
#
# **Enunciado**. El archivo `population_data.csv` contiene información histórica anual de México relativa a la población, nacimientos y muertes desde el año 1950 hasta el año 2015. La primer columna corresponde a los años, la segunda a la población, la tercera a los nacimientos y la última a los decesos.
#
# Tomado de: https://en.wikipedia.org/wiki/Demographics_of_Mexico.
#
# **Punto 1 (10 puntos).** Importar los datos en un DataFrame de pandas.

# **Solución punto 1.**

# +
# Solución acá
# -

#importar librería pandas
import pandas as pd

file_name = 'population_data.csv'
data = pd.read_csv(file_name, header=None)
data



# **Punto 2 (15 puntos).** Usando los años como variable independiente $x$ y la población como variable dependiente $y$, ajustar polinomios de grado 1 hasta grado 3.
#
# Mostrar en un solo gráfico los datos de población contra los años, y los polinomios ajustados.
#
# Graficar el error cuadrático acumulado contra el número de términos. ¿Cuál es el polinomio que mejor se ajusta?

# **Solución punto 2.**

x = data.iloc[:,0].values/1000
y = data.iloc[:,1].values/10000


def fun_obj(b, x, y, n):
    return np.sum((y-b.dot([x**i for i in range(n+1)]))**2)


b01 = np.zeros(2)
ajuste1 = opt.minimize(fun_obj, b01, args=(x,y,1))
b02 = np.zeros(3)
ajuste2 = opt.minimize(fun_obj, b02, args=(x,y,2))
b03 = np.zeros(4)
ajuste3 = opt.minimize(fun_obj, b03, args=(x,y,3))

ajuste1
ajuste2
ajuste3





# *Conclusión*

# Según la gráfica anterior, el polinomio que mejor se ajusta es el de segundo orden.

# **Punto 3 (10 puntos).** Con los polinomios ajustados en el punto anterior, estime la población en el año 2016 y compare con el dato real 127,5 millones.
#
# ¿Cuál polinomio estima mejor este dato? ¿Es el polinomio que mejor se ajusta? Concluya.

# **Solución punto 3.**





# *Conclusión*

# <script>
#   $(document).ready(function(){
#     $('div.prompt').hide();
#     $('div.back-to-top').hide();
#     $('nav#menubar').hide();
#     $('.breadcrumb').hide();
#     $('.hidden-print').hide();
#   });
# </script>
#
# <footer id="attribution" style="float:right; color:#808080; background:#fff;">
# Created with Jupyter by <NAME>.
# </footer>

StarcoderdataJupyterScriptsDedupFiltered