**Exercise set 2**
==============

>The goal of this exercise is to investigate Bayes theorem,
>and to use ANOVA to determine if a certain factor is indeed
>affecting the results of an experiment.

**Exercise 2.1**

A certain disease occurs randomly in the general population with a probability of $\tfrac{1}{10\,000}$.
A test has been developed for this disease which is $99\%$ correct, meaning here
that if a person has the disease, then the test will correctly be positive in $99\%$ of the cases.
If a person does not have the disease, the test will correctly be negative in $99\%$ of the cases.

**(a)**  Assume that we are testing for this disease in a population of $1\,000\,000$ people. How many
are expected to have the disease? How many are expected to not
have the disease? Further:

* (i)  How many people with the disease will have a positive test?

* (ii)  How many people with the disease will have a negative test?

* (iii)  How many people without the disease will have a positive test?

* (iv)  How many people without the disease will have a negative test?

Summarize your answers to the four points above in a table of the following
form:

|    |    ||Has the disease?|
|:---|:---|:---:|:---:|
|||Yes|No|
|**Test result**| Positive |||
|| Negative | ||

```python
# Your code here
```

**Your answer to question 2.1(a):** *Double click here*

**(b)**  Later in the course, when dealing with classification problems,
we will refer to this table as the "confusion matrix". This table
summarizes the types of errors we are making: the number of
false positives ("FP") and the number of
false negatives ("FN"). In addition, it shows us the number
of true positives
("TP") and the number of true negatives ("TN").
Identify the location of
these $4$ labels in the table above.
Using these labels, we can define different measures that tell us
something about the performance of the test. One example of such a
measure is the "precision" which is
defined as the ratio between the number of true positives and
the total number of positives:

\begin{equation}
\text{precision} = \frac{\text{TP}}{\text{TP} + \text{FP}}
\tag{1}\end{equation}

We can interpret the precision as the probability of having the
disease, given that the test was positive.
Calculate this probability, using the formula given above.
Do you have any comments about the size of
this probability?

```python
# Your code here
```

**Your answer to question 2.1(b):** *Double click here*

**(c)**  Use Bayes theorem to calculate the probability of
having the disease, given that a test was positive. Compare
this to the probability you found in the previous answer.

```python
# Your code here
```

**Your answer to question 2.1(c):** *Double click here*

**Exercise 2.2**

The fertilizer magnesium ammonium phosphate MgNH$_4$PO$_4$ is an effective
supplier for nutrients necessary for plant growth. In an experiment, you have
tested the effect of this fertilizer on the growth of Chrysanthemums by
measuring the height of the plants after growing them for four weeks.
You have considered $4$ different concentrations of the fertilizer (measured in g/bu)
and you have measured the mean height by growing $10$ plants per concentration.
The measured data is given in Table 1, and is
also given in the file [`Data/fertilizer.txt`](Data/fertilizer.txt).

|**50 g/bu** | **100 g/bu** | **200 g/bu** | **400 g/bu** |
|:---:|:---:|:---:|:---:|
|$13.2$ | $16.0$ | $ 7.8$ | $21.0$ |
|$12.4$ | $12.6$ | $14.4$ | $14.8$ |
|$12.8$ | $14.8$ | $20.0$ | $19.1$ |
|$17.2$ | $13.0$ | $15.8$ | $15.8$ |
|$13.0$ | $14.0$ | $17.0$ | $18.0$ |
|$14.0$ | $23.6$ | $27.0$ | $26.0$ |
|$14.2$ | $14.0$ | $19.6$ | $21.1$ |
|$21.6$ | $17.0$ | $18.0$ | $22.0$ |
|$15.0$ | $22.2$ | $20.2$ | $25.0$ |
|$20.0$ | $24.4$ | $23.2$ | $18.2$ |

**Table 1:** *Measured plant heights (in cm) as a function of the fertilizer concentration (in g/bu).*

**(a)**  Here, we will test the hypothesis that the mean height
of the plants is not affected by the amount of fertilizer. We
are going to test this with a specified significance level, $\alpha$.
What is the meaning of $\alpha$ in connection with a hypothesis test?

```python
# Your code here
```

**Your answer to question 2.2(a):** *Double click here*

**(b)**  To test the hypothesis, we will perform ANOVA. Before we do that,
it is a good idea to visualize the raw data. Create a suitable plot
of the raw data. Does it look like our hypothesis is correct?

```python
# Your code here
```

**Your answer to question 2.2(b):** *Double click here*

**(c)**  In connection with performing ANOVA, we need to calculate some
terms that measure the variance within groups and the variance
between groups.
Calculate these terms ($SST$, $SSA$, and $SSE$).

```python
# Your code here
```

**Your answer to question 2.2(c):** *Double click here*

**(d)**  Using the terms you calculated in the previous point, obtain
the two estimates for the variance:

* (i)  $s_1^2 = \frac{SSA}{k-1}$,

* (ii)  $s^2 = \frac{SSE}{k(n-1)}$,

and calculate the $f$-statistic: $f=s_1^2/s^2$.

```python
# Your code here
```

**Your answer to question 2.2(d):** *Double click here*

**(e)**  To perform the actual hypothesis test, we need the critical value
from the $F$-distribution. For a specified significance level, $\alpha$,
and with $3$ and $36$ degrees of freedom, we
label the critical value as $f_{\alpha}(3, 36)$. Check that I am using
the correct degrees of freedom here, consistent with the
raw data given in table 1.

```python
# Your code here
```

**Your answer to question 2.2(e):** *Double click here*

**(f)**  Critical $f$ values can be calculated from the distribution
function(With Python, this can be done with
`scipy.stats.f.ppf`
from the
[SciPy library](https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.f.html).)
or it can be found in statistical tables.(One such table can be found
[here on-line](https://www.itl.nist.gov/div898/handbook/eda/section3/eda3673.htm).)
For the significance levels $\alpha=0.05$ and $\alpha=0.10$, I have found the
following two values:

* (i)  $f_{\alpha = 0.05}(3, 36) = 2.866$

* (ii)  $f_{\alpha=0.10}(3, 36) = 2.243$

Check that these two values are correct.

```python
# Your code here
```

**Your answer to question 2.2(f):** *Double click here*

**(g)**  Based on the calculations you have done,
can you conclude on the $0.05$ level of significance that
different concentrations of the fertilizer affect the mean attained height
of the plants? What concentration, if any, appears to give the tallest plants?

```python
# Your code here
```

**Your answer to question 2.2(g):** *Double click here*

**(h)**  Would your conclusion change with a significance level of $0.10$?

```python
# Your code here
```

**Your answer to question 2.2(h):** *Double click here*

**(i)**  (Optional) Re-do this exercise, but use the [`anova_lm`](https://www.statsmodels.org/stable/generated/statsmodels.stats.anova.anova\_lm.html) method
from the Python package [`statsmodels`](https://www.statsmodels.org), or the
[`scipy.stats.f_oneway`](https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.f\_oneway.html) method from the Python package [`SciPy`](https://www.scipy.org/), to run ANOVA.

```python
# Your code here
```

**Your answer to question 2.2(i):** *Double click here*


+ This notebook is part of lecture 9 *Independence, basis and dimension* in the OCW MIT course 18.06 by Prof Gilbert Strang [1]
+ Created by me, Dr Juan H Klopper
    + Head of Acute Care Surgery
    + Groote Schuur Hospital
    + University Cape Town
    + Email me with your thoughts, comments, suggestions and corrections

Linear Algebra OCW MIT18.06 IPython notebook [2] study notes by Dr Juan H Klopper is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.

+ [1] OCW MIT 18.06
+ [2] Fernando Pérez, Brian E. Granger, IPython: A System for Interactive Scientific Computing, Computing in Science and Engineering, vol. 9, no. 3, pp. 21-29, May/June 2007, doi:10.1109/MCSE.2007.53. URL: http://ipython.org

```python
from IPython.core.display import HTML, Image
css_file = 'style.css'
HTML(open(css_file, 'r').read())
```

```python
#import numpy as np
from sympy import init_printing, Matrix, symbols
#import matplotlib.pyplot as plt
#import seaborn as sns
#from IPython.display import Image
from warnings import filterwarnings

init_printing(use_latex = 'mathjax') # Pretty Latex printing to the screen
#%matplotlib inline
filterwarnings('ignore')
```

# Independence
# Spanning
# Basis
# Dimension

## Independence

* Vectors are linearly independent if
    * No combination of these vectors results in the zero vector (except the zero combinations)
$$ { c }_{ 1 }{ x }_{ 1 }+{ c }_{ 2 }{ x }_{ 2 }+\dots +{ c }_{ n }{ x }_{ n }\neq 0,\quad { c }_{ i }\neq 0 $$
    * In 2-space, this means that they should noy be on the same line through the origin
    * In 3-space they should not be on the same line through the origin or on a plane through the origin
    * In higher-dimensional space they should not be on the same line through the origin or a hyperplane through the origin

* If they are independent by the constraints above, only a zero combination of them will results in zero
* If there are vectors in the nullspace (apart from the zero vector), then (there is a linear combination that will give zero and) then the vectors are not linearly independent

```python
A= Matrix([[1, 2, 4], [3, 1, 4]])
A
```

* Here we will have a rank of 2 (2 pivots) and 3 unknowns and 2 rows
* Thus, *r* = *m* (full row rank)
* We are left with *n* - *r* freen variable, i.e. 3 - 2 = 1 and will have one vector in the nullspace

```python
A.rref()
```

```python
A.nullspace()
```

### Another way to state independence

* Consider the columns of the matrix A as vectors v1, v2, ..., vn

* If *r* = *n* then the nullspace only contains the zero vector and the column vectors are linearly independent

## Spanning

* If we have a set of linearly independent vector that all their linear combinations (including zero) span a subspace ( in this instance a column space)

* We are particularly interested in a set of (column) vectors (in a matrix) that are linearly independent and span a subspace
* This leads us to the next topic, **basis**

## Basis

* A set of vectors (in a space *W*) with the properties
    * They are linearly independent
    * They span the space (linear combinations of them fill the space)

* Up until now we looked at columns in a matrix A
* It is more common in textbooks to look at a space first and ask about basis vectors, spanning vectors, dimension, etc

* So let's look at ℝ3
* The obvious set of basis vectors are
$$ \hat {i}, \quad \hat {j}, \quad \hat {k} $$

* What about
$$ \begin{bmatrix} 1 \\ 1 \\ 2 \end{bmatrix},\quad \begin{bmatrix} 2 \\ 2 \\ 5 \end{bmatrix} $$
* So, are they linearly independent and do they span ℝ3?|

```python
A = Matrix([[1, 2], [1, 2], [2, 5]])
A
```

* Here we will have *r* = 2, *n* = 2 and thus a (*n* - *r* = 0) zero nullspace

```python
A.nullspace()
```

```python
A.rref()
```

* For now, our intuition is that they will not span ℝ3
* This intuition is correct, because all their linear combinations will only fill a plane through the origin
* The zero combination does result in the zero vector, though, so they do fill a subspace of ℝ3
* Some textbooks refer to this as *V* = ℝn, with *W* a subspace of *V*

* If we added a column vector that is a linear combination of these, it will also fall in the plane and thus not be linearly independent (there will be a vector in the nullspace other than the zero vector

```python
A = Matrix([[1, 2, 3], [1, 2, 3], [2, 5, 7]])
A.nullspace()
```

```python
A.rref()
```

* Indeed, we have a column without a pivot and thus a free variable

* Let's add another, such that we have

```python
A = Matrix([[1, 2, 3], [1, 2, 3], [2, 5, 8]])
A.rref()
```

* Again, a column without a pivot and sure enough, we'll find a vector (other than the zero vector) in the nullspace

```python
A.nullspace()
```

### The special case of a square matrix

* If we now end up with a square matrix, we need only look at it's determinant, i.e., is it invertible

```python
A.det() # .det() calculates the determinant
```

* Indeed the determinant is zero as expected

## Dimension

* Given a (sub)space, every basis for that (sub)space has the same number of vectors (there are usally more than one basis for every (sub)space)
* This called the dimension of a (sub)space

## Important point to remember

* The (sub)space which a set of (column) vectors (matrix of coefficients, A) span, is the set of possible **b**-values

## More examples

#### Example problem

* Consider the column space

```python
A = Matrix([[1, 2, 3, 1], [1, 1, 2, 1], [1, 2, 3, 1]])
```

```python
A
```

* There are *n* = 4 unknowns, *m* = 3 unknowns
* We note that column 1 = column 4
* We note that with 4 unknowns we are dealing with ℝ4
* In essence, there are at most three independent columns, thus the matrix cannot be a basis for ℝ4
* It is possible for them to span the column space (don't get confused by column space (ℝ4) and matrix here)

```python
A.nullspace()
```

```python
A.rref()
```

* As we can see here (columns three and four have free variables, i.e. no pivots)
$$ { x }_{ 1 }+0{ x }_{ 2 }+{ x }_{ 3 }+{ x }_{ 4 }=0\\ 0{ x }_{ 1 }+1{ x }_{ 2 }+{ x }_{ 3 }+{ 0 }_{ 4 }=0\\ { x }_{ 4 }={ c }_{ 2 }\\ { x }_{ 3 }={ c }_{ 1 }\\ \therefore \quad { x }_{ 2 }=-{ c }_{ 1 }\\ \therefore \quad { x }_{ 1 }=-{ c }_{ 1 }-{ c }_{ 2 }\\ \begin{bmatrix} { x }_{ 1 } \\ { x }_{ 2 } \\ { x }_{ 3 } \\ { x }_{ 4 } \end{bmatrix}=\begin{bmatrix} -{ c }_{ 1 }-{ c }_{ 2 } \\ -{ c }_{ 1 } \\ { c }_{ 1 } \\ { c }_{ 2 } \end{bmatrix}=\begin{bmatrix} -{ c }_{ 1 } \\ -{ c }_{ 1 } \\ { c }_{ 1 } \\ 0 \end{bmatrix}+\begin{bmatrix} -{ c }_{ 2 } \\ 0 \\ 0 \\ { c }_{ 2 } \end{bmatrix}={ c }_{ 1 }\begin{bmatrix} -1 \\ -1 \\ 1 \\ 0 \end{bmatrix}+{ c }_{ 2 }\begin{bmatrix} -1 \\ 0 \\ 0 \\ 1 \end{bmatrix} $$

* The rank of the matrix is two (it is the number of pivot columns)
* This matrix space thus have two basis vectors (column vectors 1 and 2) and we say the dimension of this space is two
* Remember, a matrix has a rank, which is the dimension of a column space (the column space representing the space 'produced' by the column vectors)
* We talk about the rank of a matrix, rank(A) and the column space of a matrix, C(A)

* In summary we have two basis above (they span a space)
    * Any two vectors that are not linearly dependent will also span this space, they can't help but to
    * dimC(A)= *r*
    * The nullspace will have *n* - *r* vectors (the dimension of the null space equal the number of free variables)

```python

```


# Otimização

## Introdução

- Problemas de otimização são encontrados em diversas situações da Engenharia e indústria
- Muitos algoritmos da inteligência artificial utilizam algum princípio de otimização
- Problemas de otimização são comumente tratados como *problemas de minimização*:
    - Busca-se o _mínimo global_ de uma _função objetivo_ (FO) escalar $f(x)$
    - Maximizar $f(x)$ equivalente a minimizar $-f(x)$.

### Restrições

- POs são acompanhados de _restrições_:
- Para $g(x) = 0$, $g(x)$ é uma _restrição de igualdade_;
- Para $h(x) \leq 0$, $h(x)$ é uma _restrição de desigualdade_.

### Classificação de problemas de otimização

- _univariado_ (ou _unidimensional_), se $x$ é escalar, i.e. $x \in \mathbb{R}$;
- _multivariado_ (ou _multidimensional_), se $x$ é um vetor, i.e. $x \in \mathbb{R}^n$.
- _linear_: se a FO e as restrições são funções lineares. Neste caso, por razões históricas, diz-se que o problema é de _programação linear_.
- _não-linear_: se a FO e as restrições são funções não-lineares. Neste caso, diz-se que o problema é de _programação não-linear_.

Com respeito às restrições, um PO pode ainda ser:

- _irrestrito_: quando não se assumem limites para os valores de $x$.
- _restrito_: quando limites para os valores de $x$ são impostos.

Aqui trataremos apenas de casos em que $x \in \mathbb{R}$.

### Problemas convexos

- Problemas não-lineares são mais difíceis de resolver do que problemas lineares
- Podem admitir uma ampla variedade de comportamentos.
- Um PO não-linear pode ter tanto _mínimos locais_ quanto _mínimos globais_.
- Encontrar o _mínimo global_ de uma função $f(x)$ não-linear exige técnicas aperfeiçoadas.
- Subclasse de problemas não-lineares que pode ser resolvida eficientemente: _convexos_.

```python
import numpy as np
import matplotlib.pyplot as plt
import sympy as sy
sy.init_printing()
```

### Funções convexas

> Uma função convexa definida em um intervalo $[a,b]$ é aquela em que todos os seus valores estão abaixo da reta secante que passa pelos pontos $(a,f(a))$ e $(b,f(b)$. Isto, por sua vez, garante que ela contenha _somente_ um mínimo global.

**Exemplo**: a função $f(x) = 3x^2 - 0.36x - 11.2$ é convexa em $[-2,3]$.

```python
# domínio
a,b = -2,3
x = np.linspace(a,b,100)

# função e valores nos extremos
f = lambda x: 5*x**2 - 10.36*x - 11.2
fa,fb = f(a),f(b)

# reta secante
s = fa + (fb - fa)/(b - a)*(x - a)

# ponto de mínimo:
xmin = 10.36/10

# plotagem de funções
plt.figure(figsize=(5,3))
plt.plot(x,f(x))
plt.plot(x,s,color='#ffa500')

# pontos da secante
plt.plot(a,f(a),'o',color='#ffa500')
plt.plot(b,f(b),'o',color='#ffa500')

# ponto de mínimo
plt.plot(xmin,f(xmin),'*r',ms=10);

plt.title('Exemplo de função convexa');
```

**Exemplo**: a função $p(x) = 10x^2\textrm{sen}(6x) - 10.36\exp(x/8) - 11.2$ não é convexa em $[-2,3]$.

```python
# função
p = lambda x: 10*x**2*np.sin(6*x) - 10.36*x*np.exp(x/8) - 11.2

# extremos
pa,pb = p(a),p(b)

# secante
t = pa + (pb - pa)/(b - a)*(x - a)

# plotagem de funções
plt.figure(figsize=(5,3))
plt.plot(x,p(x))
plt.plot(x,t,color='#ffa500')

# pontos da secante
plt.plot(a,p(a),'o',color='#ffa500')
plt.plot(b,p(b),'o',color='#ffa500')

# mínimos locais
xloc = [-1.33868618,0.88811853,1.87451904]

for xl in xloc:
    plt.plot(xl,p(xl),'or');

# mínimo global
xmin2 = 2.90547127

plt.plot(xmin2,p(xmin2),'*r',ms=10);

plt.title('Exemplo de função não convexa');
```

### Pontos de sela

- Casos particulares onde a derivada de uma FO anula-se mas o ponto não pode ser definido como de mínimo ou máximo.
- Tais situações implicam a existência dos chamados _pontos de sela_.
- Uma função com um único ponto de sela, por exemplo, não admitirá mínimo global nem mínimo local.
- Para testarmos se um ponto crítico é um ponto de sela, devemos verificar o sinal da segunda derivada da função.
- Uma das seguintes situações deve ser obtida em um ponto crítico $x^*$:
    - _ponto de mínimo:_ $f''(x^*) > 0$
    - _ponto de máximo:_ $f''(x^*) < 0$
    - _ponto de sela:_ $f''(x^*) = 0$

**Exemplo:** qualquer função quadrática admite ou um ponto de mínimo ou de máximo. A função $f(x) = x^3$ possui um ponto de sela em $x^* = 0$.

```python
x = np.linspace(-1,1)

plt.figure(figsize=(10,3))

plt.subplot(131)
plt.plot(x,x**2 + 1)
plt.plot(0,1,'r*',ms=10)
plt.title('mínimo global')

plt.subplot(132)
plt.plot(x,-x**2 + 1)
plt.plot(0,1,'r*',ms=10)
plt.title('máximo global')

plt.subplot(133)
plt.plot(x,x**3 + 1)
plt.plot(0,1,'r*',ms=10)
plt.title('ponto de sela');
```

## Otimização univariada

- Otimização univariada visa resolver um problema de minimização tomando uma FO que depende apenas de uma variável.
- Matematicamente:

$$\text{Encontre } x^{*} = \min f(x), \, \text{sujeito a} \, g(x) = 0, h(x) \leq 0.$$

- Em geral, $x$ é uma _variável de decisão_, isto é, uma quantidade que pode ser ajustada livremente (ex. comprimentos, áreas, ângulos etc.).

### Técnicas

- As técnicas utilizadas para a resolução de um problema desse tipo são baseadas em:
    - métodos analíticos (busca pelos zeros das derivadas);
    - métodos computacionais (determinação de raízes por processos iterativos).
    - métodos chamados de _root finding_ são estudados em um curso introdutório de Métodos Numéricos.

- Para dar exemplos com problemas aplicados de otimização univariada, usaremos a abordagem analítica por meio de computação simbólica (módulo `sympy`).

### Problema resolvido

Consideremos o seguinte problema: _maximizar a área do retângulo inscrito em uma elipse._

### Resolução

- Área de um retângulo com vértice esquerdo inferior na origem da elipse e com vértice direito superior no ponto $(x,y)$ da elipse que está no primeiro quadrante é dada por $A_r = xy$.
- Logo, a área do retângulo inscrito na elipse será $A = 4xy$.

- A área $A$ pode ser escrita isolando $y$ na equação da elipse:

$$\frac{x^2}{a^2} + \frac{y^2}{b^2} = 1,$$

### Declaração do problema

$$\text{Encontre } x^{*} = \min \,( -A(x) ), \, \text{sujeito a} \, x > 0.$$

- Notemos que maximizar $A(x)$ equivale a minimizar $-A(x)$.

Primeiramente, criamos variáveis simbólicas que representem as variáveis de interesse do problema e a expressão da área total.

```python
# cria variáveis simbólicas
x,y,a,b = sy.symbols('x,y,a,b')

# área do retângulo no 1o. quadrante é xy
# logo, área total é 4xy
A = -4*x*y
A
```

Em seguida, resolvemos a equação da elipse para a variável $y$ utilizando a função `sympy.solve`.

```python
# resolve equação da elipse para y
sol = sy.solve(x**2/a**2 + y**2/b**2 - 1,y)
sol[0].expand(),sol[1].expand()
```

Duas soluções são possíveis para $y$. Porém, como o nosso ponto de referência sobre a elipse está no primeiro quadrante, tomamos a expressão para $y > 0$ e a substituímos na expressão da área de forma a obter uma expressão univariada $A(x)$.

```python
# substitui expressão de y positivo em A para ter -A(x)
A = A.subs({'y':sol[1]})
A.expand()
```

Localizaremos o ponto crítico da função a partir da derivada $A'(x)$. Derivando $A$ em relação a $x$, obtemos:

```python
# deriva -A(x) com a,b constantes
dAdx = A.diff(x)
dAdx.expand()
```

Em seguida, buscamos $x^{*}$ tal que $A'(x^{*}) = \frac{dA}{dx}(x^{*}) = 0$.

```python
# resolve A'(x*) = 0
sol_x = sy.solve(dAdx,x)
sol_x
```

Duas soluções, são possíveis, porém, podemos verificar qual ponto de crítico, de fato, é o que minimizará $-A(x)$ através da análise da concavidade. Então, calculamos $A''(x)$, para cada ponto crítico.

```python
# testa A''(x) para os dois pontos
dAdx2 = dAdx.diff(x)
dAdx2.subs(x,sol_x[0]).simplify(),dAdx2.subs(x,sol_x[1]).simplify()
```

Uma vez que a segunda solução verifica a concavidade positiva, temos que o ponto crítico $x^{*}$ é:

```python
# concavidade para cima => ponto de mínimo
xs = sol_x[1]
xs
```

Usando este valor na equação da elipse, obtemos a ordenada correspondente:

```python
# resolve para y > 0
ys = sy.solve(xs**2/a**2 + y**2/b**2 - 1,y)[1]
ys
```

Por fim, substituindo $x^{*}$ na expressão da área, temos que $A_{max}$ é:

```python
# área máxima
A_max = A.subs(x,xs)
A_max
```

ou, de forma, simplificada,

```python
# simplificando
A_max.simplify()
```

### Conclusão

A área do retângulo inscrito na elipse será máxima quando $x = \frac{\sqrt{2}}{2}a$ e $y = \frac{\sqrt{2}}{2}b$. Portanto, $A_{max} = 2ab$, para comprimentos $a$ e $b$ de semi-eixo maior e menor.

## Estudo paramétrico de geometria

- Plotaremos a variação das áreas de retângulos inscritos em uma elipse arbitrária em função do comprimento $x$ da meia-base do retângulo até o limite da meia-base do retângulo de área máxima.
- Adicionalmente, plotaremos a variação do comprimento da diagonal do retângulo.

```python
# semi-eixos da elipse
a,b = 60,30
# no. de retângulos inscritos
nx = 40
# base variável do retângulo
X = np.linspace(0,np.sqrt(2)/2*a,nx)
# área da elipse
e = np.pi*a*b
# áreas dos retângulos
R = []; H = []
for x in X:
    y = b*np.sqrt(1 - x**2/a**2)
    r = 4*x*y
    h = np.hypot(2*x,2*y) # diagonal do retângulo
    R.append(r)
    H.append(h)
# plotagem
fig,ax1 = plt.subplots(figsize=(6,4))
ax1.plot(X,R,'sb',mec='w',alpha=0.8,label='$A_{ret}(x)$')
ax1.plot(X,np.full(X.shape,2*a*b),'--r',alpha=0.8,label='$A_{max}$')
ax1.plot(X,np.full(X.shape,e),'-',alpha=0.8,label='$A_{elip}$')
ax1.legend(fontsize=10)
# labels
plt.xlabel('$x$ [compr. base ret. inscrito]')
plt.ylabel('$A$ [áreas]');
ax2 = ax1.twinx()
ax2.plot(X,H,'og',mec='w',alpha=0.8,label='$h_{ret}(x)$')
ax2.legend(loc=5,ncol=1,fontsize=10)
plt.ylabel('$h$ [compr. diag ret.]');
plt.suptitle('Variação de áreas e diagonais: elipse x retângulo inscrito\n');
plt.title(f'Elipse: $x^2/({a:.1f})^2 + y^2/({b:.1f})^2 = 1$',fontsize=10);
```