# Python _for fun and profit_

###### Juan Luis Cano Rodríguez
###### Madrid, 2016-05-13 @ ETS Asset Management Factory

## Outline

* Introduction
* Python for Data Science
* Python for IT
* General advice
* Conclusions

## Outline

* Introduction
* Python for Data Science

  * Interactive computation with Jupyter
  * Numerical analysis with NumPy, SciPy
  * Visualization with matplotlib and others
  * Data manipulation with pandas
  * Machine Learning with scikit-learn

* Python for IT

  * Data gathering with Requests and Scrapy
  * Information extraction with lxml, BeautifulSoup and others
  * User interfaces with PyQt, xlwings and others
  * Other: memcached, SOA

* General advice

  * Python packaging
  * The future of Python

* Conclusions

## `>>> print(self)`

* _Almost_ **Aerospace Engineer**
* Quant Developer for BBVA at Indizen
* Writer and furious tweeter at **Pybonacci**
* Chair ~~and BDFL~~ of **Python España** non-profit
* Co-creator and charismatic leader of **AeroPython** (\*not the Lorena Barba course)
* _When time permits (rare) [writes some open source Python code](https://github.com/Juanlu001/)_

# Python for Data Science

* **Python is a dynamic, interpreted\* language that is easy to learn**
* Very popular in science, research
* Rich ecosystem of packages that interoperate
* Multiple languages are used (FORTRAN, C/C++) and wrapped from Python for a convenient interface

## Jupyter

* **Interactive computation environment in a browser**
* Traces its roots to IPython, created in 2001
* Nowadays it's language-agnostic (**40 languages**)

Jupyter

* Notebook
* Exporting
* Interactive Widgets
* Slides
* Extensions https://github.com/ipython-contrib/IPython-notebook-extensions

It's a notebook!

* Code is computed in cells
* These can contain text, code, images, videos...
* All resulting plots can be integrated in the interface
* We can export it to different formats using `nbconvert` or from the UI

```python

```

```python

```

```python

```

It's interactive!

```python
from ipywidgets import interact, fixed
```

```python
from sympy import init_printing, Symbol, Eq, factor
init_printing(use_latex=True)

x = Symbol('x')

def factorit(n):
    return Eq(x**n-1, factor(x**n-1))
```

```python
interact(factorit, n=(2,40))
```

```python
# Import matplotlib (plotting), skimage (image processing) and interact (user interfaces)
# This enables their use in the Notebook.
%matplotlib inline
from matplotlib import pyplot as plt

from skimage import data
from skimage.feature import blob_doh
from skimage.color import rgb2gray

# Extract the first 500px square of the Hubble Deep Field.
image = data.hubble_deep_field()[0:500, 0:500]
image_gray = rgb2gray(image)

def plot_blobs(max_sigma=30, threshold=0.1, gray=False):
    """
    Plot the image and the blobs that have been found.
    """
    blobs = blob_doh(image_gray, max_sigma=max_sigma, threshold=threshold)

    fig, ax = plt.subplots(figsize=(8,8))
    ax.set_title('Galaxies in the Hubble Deep Field')

    if gray:
        ax.imshow(image_gray, interpolation='nearest', cmap='gray_r')
        circle_color = 'red'
    else:
        ax.imshow(image, interpolation='nearest')
        circle_color = 'yellow'
    for blob in blobs:
        y, x, r = blob
        c = plt.Circle((x, y), r, color=circle_color, linewidth=2, fill=False)
        ax.add_patch(c)
```

```python
interact(plot_blobs, max_sigma=(10, 40, 2), threshold=(0.005, 0.02, 0.001))
```

It's highly extensible!

* Some extensions https://github.com/ipython-contrib/IPython-notebook-extensions
* A thorough guide http://mindtrove.info/4-ways-to-extend-jupyter-notebook/

## NumPy

* N-dimensional data structure.
* Homogeneously typed.
* Efficient!

A universal function (or ufunc for short) is a function that operates on ndarrays. It is a “vectorized function".

```python
import numpy as np
```

```python
my_list  = list(range(0,100000))
res1 = %timeit -o sum(my_list)
```

    1000 loops, best of 3: 1.14 ms per loop

```python
array = np.arange(0, 100000)
res2 = %timeit -o np.sum(array)
```

    10000 loops, best of 3: 61.1 µs per loop

```python
res1.best / res2.best
```

    18.68618617922427

NumPy is much more:

* Advanced manipulation tricks: broadcasting, fancy indexing
* Functions: generalized linear algebra, Fast Fourier transforms
* **Use case**:
  - In-memory, fits-in-my-computer, homogeneous data
  - Easily vectorized operations

## SciPy

General purpose scientific computing library

* `scipy.linalg`: ATLAS LAPACK and BLAS libraries
* `scipy.stats`: distributions, statistical functions...
* `scipy.integrate`: integration of functions and ODEs
* `scipy.optimization`: local and global optimization, fitting, root finding...
* `scipy.interpolate`: interpolation, splines...
* `scipy.fftpack`: Fourier trasnforms
* `scipy.signal`: Signal processing
* `scipy.special`: Special functions
* `scipy.io`: Reading/Writing scientific formats

## matplotlib

* The father of all Python visualization packages
* Modeled after MATLAB API
* Powerful and versatile, but often complex and not so well documented
* Undergoing a deep default style change

```python
# This line integrates matplotlib with the notebook
%matplotlib inline

import matplotlib.pyplot as plt
```

```python
import numpy as np
x = np.linspace(-2, 10)
plt.plot(x, np.sin(x) / x)
```

```python
def g(x, y):
    return np.cos(x) + np.sin(y) ** 2

x = np.linspace(-2, 3, 1000)
y = np.linspace(-2, 3, 1000)

xx, yy = np.meshgrid(x, y)
zz = g(xx, yy)

fig = plt.figure(figsize=(6, 6))
cs = plt.contourf(xx, yy, zz, np.linspace(-1, 2, 13), cmap=plt.cm.viridis)
plt.colorbar()

cs = plt.contour(xx, yy, zz, np.linspace(-1, 2, 13), colors='k')

plt.clabel(cs)

plt.xlabel("x")
plt.ylabel("y")
plt.title(r"Function $g(x, y) = \cos{x} + \sin^2{y}$")
plt.close()
```

```python
fig
```

There are **many** alternatives to matplotlib, each one with its use cases, design decisions, and tradeoffs. Here are some of them:

* `seaborn`: High level layer on top of matplotlib, easier API and beautiful defaults for common visualizations
* `ggplot`: For those who prefer R-like plotting (API and appearance)
* `plotly`: 2D and 3D interactive plots in the browser as a web service
* `Bokeh`: targets modern web browsers and big data
* `pyqtgraph`: Qt embedding, realtime plots

Others: `pygal`, `mpld3`, `bqplot`...

Use the best tool for the job! And in case of doubt, just get matplotlib :)

## pandas

* **High-performance, easy-to-use data structures and data analysis**
* Inspired by R DataFrames
* _Not just NumPy on steroids_
* Input/Output functions for a variety of formats
* SQL and query-like operations

```python
import numpy as np
import pandas as pd

dates = pd.date_range('20130101', periods=6)
df = pd.DataFrame(np.random.randn(6,4), index=dates, columns=list('ABCD'))
df
```

## scikit-learn and others

* `scikit-learn`: **A high quality machine learning package**
* `Theano`: primitives for building neural networks
* `TensorFlow`: Google's take on machine learning and deep learning
* `keras`: deep learning built on top of Theano and TensorFlow

Many possibilities!

# Infrastructure

## Information retrieval extraction

* Web spraping: Requests, Scrapy
* Information extraction: lxml, json, BeautifulSoup, pyparsing
  - Many options depending on the specific format
* Cache systems: memcached, redis-py
  - Python wrappers for existing, mature systems

## User interfaces and applications

* GUI toolkits
  - PyQt is the more powerful, but watch out license terms
  - Other: Tkinter, PyGTK...
  - Are desktop apps dead anyway? Perhaps move to browser?
* Service-oriented architectures (SOA)
  - Flask: Small web frameworks focused on little services
  - Django + Django REST framework: More complex, difficult to master, very powerful

## Python + Excel

* Most interesting option: xlwings
  - Possibility to create User Defined Functions (UDFs) in Python to be used from Excel
  - Also, call VBA Subs and Functions from Python!
  - Creation of Excel Addins
  - Support for pandas DataFrames, charts, CSE formulas and more
  - Debugging helpers, easier than you might think!
* Challenges: _deployment_
* Other options: openpyxl, xlwt, XlsxWriter

# General advice

## Python packaging

Remember this picture? It's _so_ 2012!

And by the way, a bit too optimistic:

* `setuptools` is back
* `easy_install` is not gone

## The future of Python

* Origins: 1995-2005
  - Python is first used in science
  - Thin wrappers around LAPACK and other Netlib libraries
  - No notion of good practices, GitHub or whatsoever
  - Several array packages
  - In 2001 IPython and matplotlib appear
  - Year 2002 marks the beginning of the digital age
  - In 2005 NumPy is born to rule them all

* Growth: 2005-2015
  - The community starts gaining traction
  - GitHub brings a new era on online collaboration, development pace accelerates
  - In 2008 pandas is born
  - In 2012 IPython receives $1.15M from the Sloan Foundation and Continuum Analytics is born
  - Big Data starts getting more and more attention

> "Prediction is very difficult, especially about the future."

* Future: 2015-2025?
  - In 2016 Continuum brings Python to HDFS
  - _Highly opinionated_: Oracle v Google poses threat to Java
  - The Jupyter project diversifies, different notebook interfaces and use cases appear
  - Replacements for NumPy and pandas are developed (DyND, Blaze)
  - Julia and other competitors mature
  - Python 2 will reach EOL in 2020

# Muchas gracias 😊

* This talk: https://github.com/Juanlu001/python-fun-and-profit/
* My LinkedIn https://es.linkedin.com/in/juanluiscanor/en
* 📫 hello@juanlu.space

_Per Python ad astra!_


# **Modelagem**

## **Instalação e importação**

```python
%reset -f
```

```python
#Instalar e importar bibliotecas:

try:
  import CoolProp
except ImportError:
  !pip install CoolProp

import matplotlib.pyplot as plt
from matplotlib.ticker import AutoMinorLocator
import CoolProp.CoolProp as cp
from CoolProp.CoolProp import PropsSI as ps
from CoolProp.CoolProp import State as st
from tabulate import tabulate as tab
import numpy as np
from sympy import *
import pandas as pd
```

    Collecting CoolProp
      Downloading https://files.pythonhosted.org/packages/2d/c9/321ff0b7ddefbfdb653ff9a4eb7bf3cf812c94ff162d24fd6f12c7bcc808/CoolProp-6.4.1-cp37-cp37m-manylinux1_x86_64.whl (4.2MB)
         |████████████████████████████████| 4.2MB 5.3MB/s
    Installing collected packages: CoolProp
    Successfully installed CoolProp-6.4.1

## **Unidade de medida**

```python
Temperatura = input('Temperatura em °C ou em K? (Digite c ou k): ')
```

    Temperatura em °C ou em K? (Digite c ou k): c

## **Declaração de variáveis**

```python
# Declarar estados:

n = 12

fld = "Water"
cp.set_reference_state(fld,'DEF')
if Temperatura == 'k':
  Tnn = "Temperatura [K]"
else:
  Tnn = "Temperatura [°C]"

mnn = "Vazão mássica [kg/s]"
hnn = "Entalpia [kJ/kg]"
rhonn = "Massa específica [m³/kg]"
Pnn = "Pressão [kPa]"
snn = "Entropia [kJ/kg*K]"
Xnn = "Título"

estado = np.arange(1, n+1, 1)

T = np.linspace(0,0,n)
m = np.linspace(0,0,n)
h = np.linspace(0,0,n)
rho = np.linspace(0,0,n)
P = np.linspace(0,0,n)
s = np.linspace(0,0,n)
X = np.linspace(0,0,n)
```

## **Estados**

```python
# Estado 1 - Entrada da turbina:

m[0] = 27.9        #kg/s
P[0] = 6495        #kPa
T[0] = 485 + 273.15       #K
st1 = st(fld, {'P':P[0],'T':T[0]})
h[0] = st1.h         #entalpia
s[0] = st1.s         #entropia
X[0] = st1.Q
rho[0] = st1.rho
```

```python
# Estado 2 - Primeira extração da turbina:

P[1] = 900      #kPa
st_isen2 = st(fld,{'P':P[1],'S':s[0]})     #turbina/bomba isentrópica ideal
h_isen2 = st_isen2.h
η_turb = 0.85       #eficiência da turbina
h[1] = h[0] - (h[0] - h_isen2) * η_turb
st2 = st(fld,{'P':P[1],'H':h[1]})
s[1] = st2.s
T[1] = st2.T
X[1] = st2.Q
rho[1] = st2.rho
```

```python
# Estado 3 - Segunda extração da turbina:

P[2] = 250     #kPa
st_isen3 = st(fld,{'P':P[2],'S':s[1]})
h_isen3 = st_isen3.h
h[2] = h[1] - (h[1] - h_isen3) * η_turb
st3 = st(fld,{'P':P[2],'H':h[2]})
s[2] = st3.s
rho[2] = st3.rho
T[2] = st3.T
X[2] = st3.Q
```

```python
# Estado 4 - Saída final da turbina / entrada do condensador:

T[3] = 51 + 273.15 #K
#P[3] = psi('P','T',T[3],'Q', 1, fld)/1000  #divide por 1000 pra sair em kPa
st4 = st(fld, {'T': T[3], 'Q': 1})
P[3] = st4.p
st_isen4 = st(fld,{'P':P[3],'S':s[2]})
h_isen4 = st_isen4.h
h[3] = h[2] - (h[2] - h_isen4) * η_turb
st4 = st(fld,{'P':P[3],'H':h[3]})
X[3] = st4.Q      #título
s[3]=st4.s
rho[3] = st4.rho
```

```python
# Estado 5 - Saída do condensador / entrada da bomba:

X[4] = 0
P[4] = P[3]
st5 = st(fld, {'P': P[4], 'Q': 0})
h[4] = st5.h
s[4] = st5.s
T[4] = st5.T
rho[4] = st5.rho
```

```python
# Estado 6 - Entrada do desaerador / saída da bomba:

P[5] = P[2]
st_isen6 = st(fld, {'P': P[5], 'S': s[4]})
h_isen6 = st_isen6.h
η_pump = 0.85       #eficiência das bombas
h[5] = (h_isen6 - h[4]) / η_pump + h[4]
st6 = st(fld, {'P':P[5], 'H': h[5]})
s[5] = st6.s
T[5] = st6.T
X[5] = st6.Q
rho[5] = st6.rho
```

```python
# Estado 7 - Saída do desaerador:

P[6] = P[2]
T[6] = 110 + 273.15
st7 = st(fld, {'P': P[6], 'T': T[6]})
h[6] = st7.h
s[6] = st7.s
X[6] = st7.Q
rho[6] = st7.rho
```

```python
# Estado 8 - Entrada da caldeira:

P[7] = P[0]
st_isen8 = st(fld, {'P': P[7], 'S': s[6]})
h_isen8 = st_isen8.h
h[7] = (h_isen8 - h[6]) / η_pump + h[6]
st8 = st(fld, {'P': P[7], 'H': h[7]})
T[7] = st8.T - 273.15
s[7] = st8.s
X[7] = st8.Q
rho[7] = st8.rho
```

```python
# Estado 9 - Entrada da bomba:

st9 = st7
h[8] = st9.h
s[8] = st9.s
P[8] = st9.p
T[8] = st9.T
X[8] = st9.Q
rho[8] = st9.rho
```

```python
# Estado 10 - Saída da bomba / entrada do trocador de calor:

P[9] = P[1]
st_isen10 = st(fld, {'P': P[9], 'S': s[8]})
h_isen10 = st_isen10.h
h[9] = (h_isen10 - h[8]) / η_pump + h[8]
st10 = st(fld, {'P': P[9], 'H': h[9]})
s[9] = st10.s
T[9] = st10.T
X[9] = st10.Q
rho[9] = st10.rho
```

```python
# Estado 11 - Entrada do processo industrial vizinho:

X[10] = 1
P[10] = P[9]
st11 = st(fld, {'P': P[10], 'Q': X[10]})
h[10] = st11.h
s[10] = st11.s
T[10] = st11.T
rho[10] = st11.rho
```

```python
# Estado 12 - Saída do processo industrial vizinho:

X[11] = 0
P[11] = P[9]
st12 = st(fld, {'P':P[11], 'Q': X[11]})
h[11] = st12.h
s[11] = st12.s
T[11] = st12.T
rho[11] = st12.rho
```

## **Tabela - Estados**

```python
# Tabela 1:
headers=["Estado", Tnn, Pnn, Xnn, hnn, snn, rhonn]
table = list(range(n))

for i in table:
  if Temperatura == 'k':
    T[i] = round(float(T[i]),2)
  else:
    T[i] = round(float(T[i]-273.15),2)
  P[i] = round(float(P[i]),2)
  X[i] = round(float(X[i]),2)
  h[i] = round(float(h[i]),2)
  s[i] = round(float(s[i]),4)
  rho[i] = round(float(rho[i]),2)
  table[i] = [estado[i], T[i], P[i], X[i], h[i], s[i], rho[i]]

table = np.array(list(table))

print(tab(table, headers, tablefmt="rst", stralign="center", numalign="left"))
print('\nOBS: Tomar título "-1" como líquido sub-resfriado')

for i in range(0, n):
  if Temperatura == 'k':
    T[i] = round(float(T[i]),2)
  else:
    T[i] = round(float(T[i]+273.15),2)

st_antes = [st1, st2, st3, st4, st5, st6, st7, st8, st9, st10, st11, st12]
```

    ========  ==================  ===============  ========  ==================  ====================  ==========================
    Estado    Temperatura [°C]    Pressão [kPa]    Título    Entalpia [kJ/kg]    Entropia [kJ/kg*K]    Massa específica [m³/kg]
    ========  ==================  ===============  ========  ==================  ====================  ==========================
    1         485                 6495             -1        3381.2              6.7932                19.65
    2         243.27              900              -1        2932.08             6.9522                3.91
    3         127.41              250              1         2714.68             7.0479                1.39
    4         51                  12.98            0.89      2333.12             7.2557                0.1
    5         51                  12.98            0         213.52              0.7167                987.54
    6         51.02               250              -1        213.81              0.7169                987.64
    7         110                 250              -1        461.49              1.4187                951
    8         -162.4              6495             -1        469.21              1.4218                953.43
    9         110                 250              -1        461.49              1.4187                951
    10        110.08              900              -1        462.3               1.4191                951.25
    11        175.35              900              1         2773.03             6.6213                4.65
    12        175.35              900              0         742.56              2.094                 891.92
    ========  ==================  ===============  ========  ==================  ====================  ==========================

    OBS: Tomar título "-1" como líquido sub-resfriado

## **Cálculos**

```python
m1 = m[0]
h1 = h[0]
h2 = h[1]
h3 = h[2]
h4 = h[3]
h5 = h[4]
h6 = h[5]
h7 = h[6]
h8 = h[7]
h9 = h[8]
h10 = h[9]
h11 = h[10]
h12 = h[11]

# Quantidade de iterações:
quant = 10

variacao = np.zeros(quant + 1, dtype = float)
resultados = np.zeros((n+1)*(quant + 1), dtype = float).reshape((n+1, quant + 1))

T_hout_cond = []
η_sys = []
W_liq =[]

STT_T = []
STT_P = []
STT_X = []
STT_h = []
STT_s = []
STT_v = []
Ti = np.linspace(0,0,n)

# Vazões mássicas:
for i in range(quant + 1):
  processo = i/10

  m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12 = var('m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12')
  EqMassa = [m8-m1, m4-m5, m5-m6, m9-m10, m11-m12, m2+m10-m11, m2+m3+m4-m1, m12+m3+m6-m7, m2*h2+m10*h10-m11*h11, m12*h12+m3*h3+m6*h6-m7*h7, m12-6.94*processo]
  massa = linsolve(EqMassa, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12)
  (m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12) =  next(iter(massa))

  massa = np.array(list(massa))

  for j in range(quant + 1):
    massa[0,j] = round(float(massa[0,j]),2)

  variacao[i] = i*10
  resultados[0, i] = variacao[i]
  resultados[1, i] = m[0]
  resultados[2:(n+1), i] = massa

  # Saídas de energia:
  W_p1 = -m5*(h5 - h6) #(Perde energia "-")
  W_p2 = -m8*(h7 - h8) #(Perde energia "-")
  W_p3 = -m9*(h9 - h10) #(Perde energia "-")
  W_pump = W_p1 + W_p2 + W_p3 #(Somatório dos trabalhos da bombas)

  # Eficiência da caldeira:
  η_cald = 0.85
  PCI = 10000 # kJ/kg

  # Encontra o trabalho gerado pela turbina e a vazão de combustível para a demanda:
  W_t = m1*h1 - m2*h2 - m3*h3 - m4*h4
  m_fuel = m1*(h1-h8)/(PCI*η_cald) #η_cald = m1*(h1-h8)/(m_fuel*PCI)

  # Entrada de energia:
  Q_in = m_fuel * PCI #(Ganha energia "+")

  η_sys.append(round((W_t - W_pump)/Q_in, 4))

  W_liq.append(round(η_sys[i]*Q_in,2))

  # Condensador:
  T_cout = 39.5
  T_cin = 29
  T_hin = T[3] - 273.15

  ϵ = (T_cout - T_cin)/(T_hin - T_cin)
  NUT = -ln(1 - ϵ)

  CT_in = st(fld, {'P': 101.325, 'T': T_cin + 273.15})
  CT_out = st(fld, {'P': 101.325, 'T': T_cout + 273.15})

  C_min = 4500/3600*(CT_in.rho + CT_out.rho)/2*(CT_in.cp + CT_out.cp)/2

  UA = NUT * C_min # Coeficiente global de tranferência de calor * Área

  # Sistema não-linear:
  ΔT_0, ΔT_L, T_hout, ΔT_ml, Q_out = var('ΔT_0, ΔT_L, T_hout, ΔT_ml, Q_out')
  EqCond = [ΔT_0-(T_hout-T_cin), ΔT_L-(T_hout-T_cout), ΔT_ml-(ΔT_0-ΔT_L)/ln(ΔT_0/ΔT_L), Q_out-UA*ΔT_ml, Q_out-m4*(h4-h5)]
  EqCond_solve = nonlinsolve(EqCond, ΔT_0, ΔT_L, T_hout, ΔT_ml, Q_out)
  (ΔT_0, ΔT_L, T_hout, ΔT_ml, Q_out) = next(iter(EqCond_solve))

  # Redefinindo estados:
  T[3] = T_hout + 273.15 #K
  #P[3] = psi('P','T',T[3],'Q', 1, fld)/1000  #divide por 1000 pra sair em kPa
  st4 = st(fld, {'T': T[3], 'Q': 1})
  P[3] = st4.p
  st_isen4 = st(fld,{'P':P[3],'S':s[2]})
  h_isen4 = st_isen4.h
  h[3] = h[2] - (h[2] - h_isen4) * η_turb
  st4 = st(fld,{'P':P[3],'H':h[3]})
  X[3] = st4.Q      #título
  s[3]=st4.s
  rho[3] = st4.rho

  X[4] = 0
  P[4] = P[3]
  st5 = st(fld, {'P': P[4], 'Q': X[4]})
  h[4] = st5.h
  s[4] = st5.s
  T[4] = st5.T
  rho[4] = st5.rho

  P[5] = P[2]
  st_isen6 = st(fld, {'P': P[5], 'S': s[4]})
  h_isen6 = st_isen6.h
  η_pump = 0.85       #eficiência das bombas
  h[5] = (h_isen6 - h[4]) / η_pump + h[4]
  st6 = st(fld, {'P':P[5], 'H': h[5]})
  s[5] = st6.s
  T[5] = st6.T
  X[5] = st6.Q
  rho[5] = st6.rho

  P[6] = P[2]
  T[6] = 110 + 273.15
  st7 = st(fld, {'P': P[6], 'T': T[6]})
  h[6] = st7.h
  s[6] = st7.s
  X[6] = st7.Q
  rho[6] = st7.rho

  P[7] = P[0]
  st_isen8 = st(fld, {'P': P[7], 'S': s[6]})
  h_isen8 = st_isen8.h
  h[7] = (h_isen8 - h[6]) / η_pump + h[6]
  st8 = st(fld, {'P': P[7], 'H': h[7]})
  T[7] = st8.T - 273.15
  s[7] = st8.s
  X[7] = st8.Q
  rho[7] = st8.rho

  st9 = st7
  h[8] = st9.h
  s[8] = st9.s
  P[8] = st9.p
  T[8] = st9.T
  X[8] = st9.Q
  rho[8] = st9.rho

  P[9] = P[1]
  st_isen10 = st(fld, {'P': P[9], 'S': s[8]})
  h_isen10 = st_isen10.h
  h[9] = (h_isen10 - h[8]) / η_pump + h[8]
  st10 = st(fld, {'P': P[9], 'H': h[9]})
  s[9] = st10.s
  T[9] = st10.T
  X[9] = st10.Q
  rho[9] = st10.rho

  X[10] = 1
  P[10] = P[9]
  st11 = st(fld, {'P': P[10], 'Q': X[10]})
  h[10] = st11.h
  s[10] = st11.s
  T[10] = st11.T
  rho[10] = st11.rho

  X[11] = 0
  P[11] = P[9]
  st12 = st(fld, {'P':P[11], 'Q': X[11]})
  h[11] = st12.h
  s[11] = st12.s
  T[11] = st12.T
  rho[11] = st12.rho

  for i in range(0,n):
    if Temperatura == 'k':
      Ti[i] = round(T[i],2)
    else:
      Ti[i] = round(T[i]-273.15,2)
    P[i] = round(P[i],2)
    X[i] = round(X[i],2)
    h[i] = round(h[i],2)
    s[i] = round(s[i],2)
    rho[i] = round(rho[i],2)

  STT_T.append([Tnn,processo*100,Ti[0],Ti[1],Ti[2],Ti[3],Ti[4],Ti[5],Ti[6],Ti[7],Ti[8],Ti[9],Ti[10],Ti[11]])
  STT_P.append([Pnn,processo*100,P[0],P[1],P[2],P[3],P[4],P[5],P[6],P[7],P[8],P[9],P[10],P[11]])
  STT_X.append([Xnn,processo*100,X[0],X[1],X[2],X[3],X[4],X[5],X[6],X[7],X[8],X[9],X[10],X[11]])
  STT_h.append([hnn,processo*100,h[0],h[1],h[2],h[3],h[4],h[5],h[6],h[7],h[8],h[9],h[10],h[11]])
  STT_s.append([snn,processo*100,s[0],s[1],s[2],s[3],s[4],s[5],s[6],s[7],s[8],s[9],s[10],s[11]])
  STT_v.append([rhonn,processo*100,rho[0],rho[1],rho[2],rho[3],rho[4],rho[5],rho[6],rho[7],rho[8],rho[9],rho[10],rho[11]])

  T_hout = round(T_hout, 2)
  T_hout_cond.append(T_hout)

# Adiciona linhas vazias entre as propriedades na tabela:
STT_T.append(["","","","","","","","","","","","","",""])
STT_P.append(["","","","","","","","","","","","","",""])
STT_X.append(["","","","","","","","","","","","","",""])
STT_h.append(["","","","","","","","","","","","","",""])
STT_s.append(["","","","","","","","","","","","","",""])
STT_v.append(["","","","","","","","","","","","","",""])

# Incluir na tabela e gráfico:
np.reshape(variacao, (1,n-1))
np.reshape(η_sys, (1,n-1))
np.reshape(T_hout_cond, (1,n-1))
np.reshape(W_liq, (1,n-1))

for i in range(0, n):
    T[i] = round(T[i],2)
    P[i] = round(P[i],2)
    X[i] = round(X[i],2)
    h[i] = round(h[i],2)
    s[i] = round(s[i],2)
    rho[i] = round(rho[i],2)

x = []
y = []
z = []
w = []

for i in range(0, quant+1):
  x.append(variacao[i])
  y.append(T_hout_cond[i])
  z.append(η_sys[i])
  w.append(W_liq[i])

table2 = resultados.T

resultados2 = np.zeros((n+4)*(quant + 1), dtype = float).reshape((n+4, quant + 1))

for i in range(0, quant+1):
  variacao[i] = i*10
  resultados2[0, i] = resultados[0, i]
  resultados2[1, i] = resultados[1, i]
  resultados2[2:(n+1), i] = resultados[2:(n+1), i]
  resultados2[n+2,i] = round(float(w[i]),2)
  resultados2[n+3,i] = round(float(z[i]),4)
table2 = resultados2.T

st_depois = [st1, st2, st3, st4, st5, st6, st7, st8, st9, st10, st11, st12]
```

## **Tabela - Vazões mássicas**

```python
# Tabela 2:
for i in range(0, quant+1):
  if Temperatura == 'k':
    headers2 = ["%", "m1 [kg/s]", "m2 [kg/s]", "m3 [kg/s]", "m4 [kg/s]", "m5 [kg/s]", "m6 [kg/s]", "m7 [kg/s]", "m8 [kg/s]", "m9 [kg/s]", "m10 [kg/s]", "m11 [kg/s]", "m12 [kg/s]", "T_hout [K]", "W_liq [kJ/s]", "η"]
    resultados2[n+1,i] = round(float(y[i]+273.15),2) #converter para K
    y[i] = resultados2[n+1,i]
  else:
    headers2 = ["%", "m1 [kg/s]", "m2 [kg/s]", "m3 [kg/s]", "m4 [kg/s]", "m5 [kg/s]", "m6 [kg/s]", "m7 [kg/s]", "m8 [kg/s]", "m9 [kg/s]", "m10 [kg/s]", "m11 [kg/s]", "m12 [kg/s]", "T_hout [°C]", "W_liq [kJ/s]", "η"]
    resultados2[n+1,i] = round(float(y[i]),2)
print(tab(table2, headers2, tablefmt="rst", stralign="center", numalign="left"))
print('\nA vazão mássica de combustível é de %.2f kg/s\n' %m_fuel)

# Gráficos:
escala1 = 1.5
plt.figure(dpi=100, figsize=[escala1*2*6.4, escala1*4.8])
plt.subplot(1,2,1)
plt.xlabel('Processo [%]', fontsize=14)
if Temperatura == 'k':
  plt.ylabel('Temperatura de saída do condensador [K]', fontsize=14)
  plt.plot(x, y, color='r', marker = 'o', linestyle = 'solid')
else:
  plt.ylabel('Temperatura de saída do condensador [°C]', fontsize=14)
  plt.plot(x, y, color='r', marker = 'o', linestyle = 'solid')
plt.grid()
plt.subplot(1,2,2)
plt.xlabel('Processo [%]', fontsize=14)
plt.ylabel('$η_{sistema}$', fontsize=14)
plt.plot(x, z, color='b', marker = 'o', linestyle = 'solid')
plt.grid()
plt.show()
```

## **Gráfico completo Ciclo Rankine**

```python
# Gráfico do Ciclo Rankine:
escala2 = 1.2
plt.figure(dpi=150, figsize=[escala2*6.4, escala2*4.8])
y1 = 273.15
y2 = 850
x1 = -0.5
x2 = 10
plt.ylim(y1,y2)
plt.xlim(x1,x2)
plt.title('Ciclo Rankine',fontsize=20)
plt.xlabel('Entropia, s[kJ/kg$\cdot$K]')
plt.ylabel('Temperatura, T[K]')

Tmin = ps('Tmin',fld )
Tcrit = ps('Tcrit',fld)
Pcrit = ps('Pcrit', fld)

Larg_isolines = .25
Larg_cycle = 1.5
Larg_scatters = 15

#Linhas de entalpia:
T = np.linspace(Tmin,Tcrit,1000)
Q = np.arange(0.1,1,0.1)
for i in Q:
  s = ps('S','T',T,'Q',i,'Water')/1000
  plt.plot(s,T,'#6ca8fa',alpha=0.7,lw=Larg_isolines)

#Domo:
T = np.linspace(Tmin,Tcrit,1000)
s = ps('S','T',T,'Q',0,fld)/1000
plt.plot(s,T,'black',lw=2*Larg_isolines)

T = np.linspace(Tcrit,Tmin,1000)
s = ps('S','T',T,'Q',1,fld)/1000
plt.plot(s,T,'black',lw=2*Larg_isolines)

#Linhas de pressão constante:
T = np.linspace(Tmin,1000,1000)
P = [st_antes[0].p,st_antes[1].p,st_antes[2].p,st_antes[3].p,st_depois[3].p] #P1, P2, P3, P4 e P4*
for i in P:
  s = ps('S','T',T,'P',i*1000,'Water')/1000
  plt.plot(s,T,'#cc00ff',alpha=.7,lw=Larg_isolines)

#Ciclo:
#(antes)
T = np.linspace(st_antes[7].T,st_antes[0].T,1000)
s = ps('S','P',st_antes[0].p * 1000,'T',T,'Water')/1000
plt.plot(s,T,'r',lw=Larg_cycle)

T = np.linspace(st_antes[9].T,st_antes[1].T,1000)
s = ps('S','T',T,'P',st_antes[9].p*1000,'Water')/1000
plt.plot(s,T,'r',lw=Larg_cycle)
plt.plot([st_antes[3].s,st_antes[4].s],[st_antes[3].T,st_antes[4].T],'r',lw=Larg_cycle)

plt.plot([st_antes[0].s,st_antes[1].s],[st_antes[0].T,st_antes[1].T],color='r',linestyle='dashed',lw=Larg_cycle)
plt.plot([st_antes[1].s,st_antes[2].s],[st_antes[1].T,st_antes[2].T],color='r',linestyle='dashed',lw=Larg_cycle)

s = np.linspace(st_antes[2].s,st_antes[6].s,1000)
T = ps('T','S',s*1000,'P',st_antes[2].p*1000,'Water')
plt.plot(s,T,'r',lw=Larg_cycle)

T = np.linspace(st_antes[5].T,st_antes[6].T,1000)
s = ps('S','P',st_antes[5].p*1000,'T',T,'Water')/1000
plt.plot(s,T,'r',lw=Larg_cycle)

s = np.linspace(st_antes[2].s,st_antes[3].s,1000)
plt.plot([st_antes[3].s,st_antes[2].s],[st_antes[3].T,st_antes[2].T],color='r',linestyle='dashed',lw=Larg_cycle)

#(depois)
T = np.linspace(st_depois[7].T,st_depois[0].T,1000)
s = ps('S','P',st_depois[0].p * 1000,'T',T,'Water')/1000
plt.plot(s,T,'lime',lw=Larg_cycle)

T = np.linspace(st_depois[9].T,st_depois[1].T,1000)
s = ps('S','T',T,'P',st_depois[9].p*1000,'Water')/1000
plt.plot(s,T,'lime',lw=Larg_cycle)
plt.plot([st_depois[3].s,st_depois[4].s],[st_depois[3].T,st_depois[4].T],'lime',lw=Larg_cycle)

plt.plot([st_depois[0].s,st_depois[1].s],[st_depois[0].T,st_depois[1].T],color='lime',linestyle='dashed',lw=Larg_cycle)
plt.plot([st_depois[1].s,st_depois[2].s],[st_depois[1].T,st_depois[2].T],color='lime',linestyle='dashed',lw=Larg_cycle)

s = np.linspace(st_depois[2].s,st_depois[6].s,1000)
T = ps('T','S',s*1000,'P',st_depois[2].p*1000,'Water')
plt.plot(s,T,'lime',lw=Larg_cycle)

T = np.linspace(st_depois[5].T,st_depois[6].T,1000)
s = ps('S','P',st_depois[5].p*1000,'T',T,'Water')/1000
plt.plot(s,T,'lime',lw=Larg_cycle)

s = np.linspace(st_depois[2].s,st_depois[3].s,1000)
plt.plot([st_depois[3].s,st_depois[2].s],[st_depois[3].T,st_depois[2].T],color='lime',linestyle='dashed',lw=Larg_cycle)

#Pontuar e nomear:
for i in range(0, n):
  plt.scatter(st_antes[i].s,st_antes[i].T,zorder=5,color='k',s=Larg_scatters)
  plt.scatter(st_depois[i].s,st_depois[i].T,zorder=5,color='k',s=Larg_scatters)

plt.text(st_antes[0].s+.1,st_antes[0].T,'1',ha='left')
plt.text(st_antes[1].s+.1,st_antes[1].T,'2',ha='left')
plt.text(st_antes[2].s+.1,st_antes[2].T,'3',ha='left')
plt.text(st_antes[3].s+.1,st_antes[3].T,'4',ha='left')
plt.text(st_antes[4].s-.1,st_antes[4].T,'5, 6',ha='right')
plt.text(st_antes[6].s-.1,st_antes[6].T,'7, 8, 9, 10',ha='right')
plt.text(st_antes[10].s-.1,st_antes[10].T,'11',va='bottom',ha='right')
plt.text(st_antes[11].s-.1,st_antes[11].T+.1,'12',ha='right')
plt.text(st_depois[3].s+.1,st_depois[3].T,'4*',va='top',ha='left')
plt.text(st_depois[4].s-.1,st_depois[4].T,'5*, 6*',va='top',ha='right')

#plt.grid(lw=Larg_isolines)
plt.twinx()
plt.ylim(y1-273.15,y2-273.15)
plt.ylabel('Temperatura, T[°C]')
#plt.grid(lw=Larg_isolines)

plt.savefig('Diagrama T-s.png')
#files.download('Diagrama T-s.png')
```

## **Tabela relatório completo Ciclo Rankine**

```python
#@title Texto de título padrão
# Tabela 3:
table3 = STT_T + STT_P + STT_X + STT_h + STT_s + STT_v
headers3=["Propriedade", "%", "Estado 1", "Estado 2", "Estado 3", "Estado 4", "Estado 5", "Estado 6", "Estado 7", "Estado 8", "Estado 9", "Estado 10", "Estado 11", "Estado 12"]

print(tab(table3, headers3, tablefmt="rst", stralign="center", numalign="center"))
```

    ========================  =====  ==========  ==========  ==========  ==========  ==========  ==========  ==========  ==========  ==========  ===========  ===========  ===========
          Propriedade           %     Estado 1    Estado 2    Estado 3    Estado 4    Estado 5    Estado 6    Estado 7    Estado 8    Estado 9    Estado 10    Estado 11    Estado 12
    ========================  =====  ==========  ==========  ==========  ==========  ==========  ==========  ==========  ==========  ==========  ===========  ===========  ===========
        Temperatura [°C]       0.0     485.0       243.27      127.41      50.64       50.64       50.66       110.0       -162.4      110.0       110.08       175.35       175.35
        Temperatura [°C]      10.0     485.0       243.27      127.41      49.99       49.99       50.01       110.0       -162.4      110.0       110.08       175.35       175.35
        Temperatura [°C]      20.0     485.0       243.27      127.41      49.08       49.08        49.1       110.0       -162.4      110.0       110.08       175.35       175.35
        Temperatura [°C]      30.0     485.0       243.27      127.41      47.97       47.97       47.99       110.0       -162.4      110.0       110.08       175.35       175.35
        Temperatura [°C]      40.0     485.0       243.27      127.41      46.72       46.72       46.74       110.0       -162.4      110.0       110.08       175.35       175.35
        Temperatura [°C]      50.0     485.0       243.27      127.41       45.4        45.4       45.42       110.0       -162.4      110.0       110.08       175.35       175.35
        Temperatura [°C]      60.0     485.0       243.27      127.41      44.09       44.09       44.11       110.0       -162.4      110.0       110.08       175.35       175.35
        Temperatura [°C]      70.0     485.0       243.27      127.41      42.85       42.85       42.87       110.0       -162.4      110.0       110.08       175.35       175.35
        Temperatura [°C]      80.0     485.0       243.27      127.41      41.76       41.76       41.78       110.0       -162.4      110.0       110.08       175.35       175.35
        Temperatura [°C]      90.0     485.0       243.27      127.41      40.86       40.86       40.88       110.0       -162.4      110.0       110.08       175.35       175.35
        Temperatura [°C]      100.0    485.0       243.27      127.41       40.2        40.2       40.21       110.0       -162.4      110.0       110.08       175.35       175.35
               ..
         Pressão [kPa]         0.0     6495.0      900.0       250.0       12.75       12.75       250.0       250.0       6495.0      250.0        900.0        900.0        900.0
         Pressão [kPa]        10.0     6495.0      900.0       250.0       12.34       12.34       250.0       250.0       6495.0      250.0        900.0        900.0        900.0
         Pressão [kPa]        20.0     6495.0      900.0       250.0        11.8        11.8       250.0       250.0       6495.0      250.0        900.0        900.0        900.0
         Pressão [kPa]        30.0     6495.0      900.0       250.0       11.16       11.16       250.0       250.0       6495.0      250.0        900.0        900.0        900.0
         Pressão [kPa]        40.0     6495.0      900.0       250.0       10.48       10.48       250.0       250.0       6495.0      250.0        900.0        900.0        900.0
         Pressão [kPa]        50.0     6495.0      900.0       250.0        9.8         9.8        250.0       250.0       6495.0      250.0        900.0        900.0        900.0
         Pressão [kPa]        60.0     6495.0      900.0       250.0        9.15        9.15       250.0       250.0       6495.0      250.0        900.0        900.0        900.0
         Pressão [kPa]        70.0     6495.0      900.0       250.0        8.58        8.58       250.0       250.0       6495.0      250.0        900.0        900.0        900.0
         Pressão [kPa]        80.0     6495.0      900.0       250.0        8.11        8.11       250.0       250.0       6495.0      250.0        900.0        900.0        900.0
         Pressão [kPa]        90.0     6495.0      900.0       250.0        7.73        7.73       250.0       250.0       6495.0      250.0        900.0        900.0        900.0
         Pressão [kPa]        100.0    6495.0      900.0       250.0        7.46        7.46       250.0       250.0       6495.0      250.0        900.0        900.0        900.0
               ..
             Título            0.0      -1.0        -1.0        1.0         0.89        0.0         -1.0        -1.0        -1.0        -1.0        -1.0          1.0          0.0
             Título           10.0      -1.0        -1.0        1.0         0.89        0.0         -1.0        -1.0        -1.0        -1.0        -1.0          1.0          0.0
             Título           20.0      -1.0        -1.0        1.0         0.89        0.0         -1.0        -1.0        -1.0        -1.0        -1.0          1.0          0.0
             Título           30.0      -1.0        -1.0        1.0         0.89        0.0         -1.0        -1.0        -1.0        -1.0        -1.0          1.0          0.0
             Título           40.0      -1.0        -1.0        1.0         0.88        0.0         -1.0        -1.0        -1.0        -1.0        -1.0          1.0          0.0
             Título           50.0      -1.0        -1.0        1.0         0.88        0.0         -1.0        -1.0        -1.0        -1.0        -1.0          1.0          0.0
             Título           60.0      -1.0        -1.0        1.0         0.88        0.0         -1.0        -1.0        -1.0        -1.0        -1.0          1.0          0.0
             Título           70.0      -1.0        -1.0        1.0         0.88        0.0         -1.0        -1.0        -1.0        -1.0        -1.0          1.0          0.0
             Título           80.0      -1.0        -1.0        1.0         0.88        0.0         -1.0        -1.0        -1.0        -1.0        -1.0          1.0          0.0
             Título           90.0      -1.0        -1.0        1.0         0.88        0.0         -1.0        -1.0        -1.0        -1.0        -1.0          1.0          0.0
             Título           100.0     -1.0        -1.0        1.0         0.88        0.0         -1.0        -1.0        -1.0        -1.0        -1.0          1.0          0.0
               ..
        Entalpia [kJ/kg]       0.0     3381.2     2932.08     2714.68     2331.17      212.02      212.3       461.49      469.21      461.49       462.3       2773.03      742.56
        Entalpia [kJ/kg]      10.0     3381.2     2932.08     2714.68     2328.23      209.29      209.58      461.49      469.21      461.49       462.3       2773.03      742.56
        Entalpia [kJ/kg]      20.0     3381.2     2932.08     2714.68     2323.34      205.5       205.79      461.49      469.21      461.49       462.3       2773.03      742.56
        Entalpia [kJ/kg]      30.0     3381.2     2932.08     2714.68     2317.33      200.86      201.14      461.49      469.21      461.49       462.3       2773.03      742.56
        Entalpia [kJ/kg]      40.0     3381.2     2932.08     2714.68     2310.55      195.63      195.92      461.49      469.21      461.49       462.3       2773.03      742.56
        Entalpia [kJ/kg]      50.0     3381.2     2932.08     2714.68     2303.38      190.12      190.41      461.49      469.21      461.49       462.3       2773.03      742.56
        Entalpia [kJ/kg]      60.0     3381.2     2932.08     2714.68     2296.22      184.63      184.92      461.49      469.21      461.49       462.3       2773.03      742.56
        Entalpia [kJ/kg]      70.0     3381.2     2932.08     2714.68     2289.46      179.46      179.75      461.49      469.21      461.49       462.3       2773.03      742.56
        Entalpia [kJ/kg]      80.0     3381.2     2932.08     2714.68     2283.46      174.88      175.17      461.49      469.21      461.49       462.3       2773.03      742.56
        Entalpia [kJ/kg]      90.0     3381.2     2932.08     2714.68     2278.53      171.13      171.42      461.49      469.21      461.49       462.3       2773.03      742.56
        Entalpia [kJ/kg]      100.0    3381.2     2932.08     2714.68     2274.88      168.36      168.64      461.49      469.21      461.49       462.3       2773.03      742.56
               ..
       Entropia [kJ/kg*K]      0.0      6.79        6.95        7.05        7.26        0.71        0.71        1.42        1.42        1.42        1.42         6.62         2.09
       Entropia [kJ/kg*K]     10.0      6.79        6.95        7.05        7.26        0.7         0.7         1.42        1.42        1.42        1.42         6.62         2.09
       Entropia [kJ/kg*K]     20.0      6.79        6.95        7.05        7.26        0.69        0.69        1.42        1.42        1.42        1.42         6.62         2.09
       Entropia [kJ/kg*K]     30.0      6.79        6.95        7.05        7.27        0.68        0.68        1.42        1.42        1.42        1.42         6.62         2.09
       Entropia [kJ/kg*K]     40.0      6.79        6.95        7.05        7.27        0.66        0.66        1.42        1.42        1.42        1.42         6.62         2.09
       Entropia [kJ/kg*K]     50.0      6.79        6.95        7.05        7.28        0.64        0.64        1.42        1.42        1.42        1.42         6.62         2.09
       Entropia [kJ/kg*K]     60.0      6.79        6.95        7.05        7.28        0.63        0.63        1.42        1.42        1.42        1.42         6.62         2.09
       Entropia [kJ/kg*K]     70.0      6.79        6.95        7.05        7.29        0.61        0.61        1.42        1.42        1.42        1.42         6.62         2.09
       Entropia [kJ/kg*K]     80.0      6.79        6.95        7.05        7.29        0.6         0.6         1.42        1.42        1.42        1.42         6.62         2.09
       Entropia [kJ/kg*K]     90.0      6.79        6.95        7.05        7.3         0.58        0.58        1.42        1.42        1.42        1.42         6.62         2.09
       Entropia [kJ/kg*K]     100.0     6.79        6.95        7.05        7.3         0.58        0.58        1.42        1.42        1.42        1.42         6.62         2.09
               ..
    Massa específica [m³/kg]   0.0     19.65        3.91        1.39        0.1        987.71      987.8       951.0       953.43      951.0       951.25        4.65        891.92
    Massa específica [m³/kg]  10.0     19.65        3.91        1.39        0.09       988.0       988.1       951.0       953.43      951.0       951.25        4.65        891.92
    Massa específica [m³/kg]  20.0     19.65        3.91        1.39        0.09       988.41      988.5       951.0       953.43      951.0       951.25        4.65        891.92
    Massa específica [m³/kg]  30.0     19.65        3.91        1.39        0.09       988.9       989.0       951.0       953.43      951.0       951.25        4.65        891.92
    Massa específica [m³/kg]  40.0     19.65        3.91        1.39        0.08       989.44      989.54      951.0       953.43      951.0       951.25        4.65        891.92
    Massa específica [m³/kg]  50.0     19.65        3.91        1.39        0.08       990.0       990.1       951.0       953.43      951.0       951.25        4.65        891.92
    Massa específica [m³/kg]  60.0     19.65        3.91        1.39        0.07       990.55      990.65      951.0       953.43      951.0       951.25        4.65        891.92
    Massa específica [m³/kg]  70.0     19.65        3.91        1.39        0.07       991.05      991.15      951.0       953.43      951.0       951.25        4.65        891.92
    Massa específica [m³/kg]  80.0     19.65        3.91        1.39        0.06       991.49      991.59      951.0       953.43      951.0       951.25        4.65        891.92
    Massa específica [m³/kg]  90.0     19.65        3.91        1.39        0.06       991.84      991.94      951.0       953.43      951.0       951.25        4.65        891.92
    Massa específica [m³/kg]  100.0    19.65        3.91        1.39        0.06       992.1       992.2       951.0       953.43      951.0       951.25        4.65        891.92
               ..
    ========================  =====  ==========  ==========  ==========  ==========  ==========  ==========  ==========  ==========  ==========  ===========  ===========  ===========


Capítulo 3
======

### Fórmulas bem formadas

Estamos a descrever um sistema formal, denominado de cálculo proposicional clássico, que formaliza a chamada lógica clássica, ou lógica proposicional clássica. O vocabulário desse sistema tem os seguintes símbolos primitivos:

1. uma colecção de símbolos, $A,B,C,\ldots$ ou $P_1,P_2,\ldots$ ou $p,q,r,\ldots$, chamados de símbolos proposicionais,
+ símbolos lógicos $\neg,\wedge,\vee,\rightarrow,\leftrightarrow,\oplus$, e
+ símbolos de pontuação $($ e $)$.

As expressões da linguagem do cálculo proposicional são sequências finitas destes símbolos (\emph{strings}), como $\neg)\vee A))(\vee B$. Convém distinguir entre as expressões ou fórmulas bem formadas (fbf) das demais. Isso é feito impondo um conjunto de regras gramaticais para a linguagem.

As regras gramaticais, para esta linguagem formal, definem por fbf (expressões gramaticalmente bem formadas na linguagem) unicamente aquelas expressões $\alpha$ obtidas por alguma das seguintes cláusulas:
1. $\alpha$ é igual a um símbolo proposicional $A,B,C,\ldots$ ou $P_1,P_2,\ldots$ ou $p,q,r,\ldots$, ou
+ $\alpha$ é igual a $(\neg \beta)$ ou $(\beta\wedge\gamma)$ ou  $(\beta\vee\gamma)$ ou $(\beta\rightarrow\gamma)$ ou  $(\beta\leftrightarrow\gamma)$ ou $(\beta\oplus\gamma)$, onde onde $\beta$ e $\gamma$,
+ nada mais é uma fbf.
Note que, os parêntesis são usados para evitar ambiguidade. Por exemplo, $(\neg p\vee q)$ deve ser distinguida de $\neg(p \vee q)$. No segundo caso, o operador $\neg$ aplica-se à fórmula $(p\vee q)$, ao passo que no primeiro ele é aplicado apenas a $p$.

Na escrita das fbf do cálculo proposicional adoptámos a convenção de eliminar  parêntesis externos e impondo uma ordem de precedência aos operadores. Num sistema formal é frequente a definição de novos símbolos com base em símbolos lógicos primitivos. Na literatura é frequente usar como únicos símbolos primitivos, para o cálculo proposicional,  $\neg$ e $\vee$, a partir dos quais se pode definir os outros fazendo por exemplo:

1. $p\wedge q =_{def}\neg(\neg p\vee\neg q)$
+ $p\rightarrow q =_{def}\neg p\vee q$
+ $p\leftrightarrow q =_{def}(p\rightarrow q)\wedge (q\rightarrow p)$

Note que neste contexto os novos símbolos $\wedge,\rightarrow,\leftrightarrow$ não fazem parte do vocabulário básico da linguagem.

##### Exercício:
Quais das seguintes expressões são proposições bem formadas?
1. $\neg((A\rightarrow B)\rightarrow \neg(B\rightarrow A)$
+ $(S\wedge (((P\rightarrow Q)\wedge (\neg Q\rightarrow R))\rightarrow (Q\vee \neg Q)))$
+ $((((A\wedge \neg B)\vee (\neg A \wedge B))\leftrightarrow \neg\neg\neg\neg C))$
+ $(((A\rightarrow B)\rightarrow C)\rightarrow \neg ((A\vee B)\leftrightarrow \neg\neg(C\wedge A)))$

### Semântica

Seja $V$ um conjunto de variáveis proposicionais. A atribuição de valores às variáveis proposicionais é descrita por uma aplicação $v$ de $V$ no conjunto $\{0,1\}$. Por $P(p_1,p_2,\ldots,p_n)$ representamos uma fbf do cálculo proposicional que dependa dos símbolos proposicionais $p_1,p_2,\ldots,p_n$. Entendendo os símbolos como variáveis proposicionais $p_1,p_2,\ldots,p_n$ no conjunto $V$, a atribuição $v$ pode ser estendida a $P$, definindo a avaliação da fórmula $v(P)$. A avaliação de $P$ reflecte a sua estrutura sintáctica, sendo definida em função da avaliação das suas partes (definição indutiva):
1. Se $P$ é definida apenas pelo símbolo $p_i$, define-se $v(P)=v(p_i)$.
+ Se $P=(\neg Q)$, define-se  $v(P)=\neg v(Q)$.
+ Se $P=(Q\wedge R)$, define-se $v(P)=v(Q)\wedge v(R)$.
+ Se $P=(Q\vee R)$, define-se  $v(P)=v(Q)\vee v(R)$.
+ Se $P=(Q\rightarrow R)$, define-se $v(P)=v(Q)\rightarrow v(R)$.
+ Se $P=(Q\leftrightarrow R)$, define-se $v(P)=v(Q)\leftrightarrow v(R)$.
+ Se $P=(Q\oplus R)$, define-se $v(P)=v(Q)\oplus v(R)$.
onde por $Q$ e $R$ se entende uma parte de $P$ que é uma $fbf$, os operadores envolvidos devem ser interpretados pela correspondente tabela de verdade.

##### Exercício:
Assumindo que as variáveis proposicionais $p$ e $q$ são verdadeiras e que $r$ e $s$ são falsas, avalie as fórmulas:
1. $(\neg(P\wedge Q)\wedge \neg R)\rightarrow ((Q\leftrightarrow \neg P)\rightarrow (R\rightarrow \neg S))$
+ $(P\vee Q)\rightarrow (\neg Q\rightarrow S)$
+ $(P\vee (Q\vee(R\rightarrow \neg P)))\leftrightarrow (Q\vee \neg S)$

Seja $P(p_1,p_2,\ldots,p_n)$ uma fórmula proposicional nas variáveis proposicionais $p_1,p_2,$ $\ldots,p_n$. Se considerarmos todas as atribuições de valores de verdade possíveis a $p_1,p_2,\ldots,p_n$, o valor de verdade de $P(p_1,p_2,\ldots,p_n)$ define a tabela de verdade para $P$. Tal tabela com já vimos contem $2^n$ linhas.

### Argumento
Sejam $P,Q$ e $R$ três proposições. Se da veracidade de $P$ e $Q$ se  pode concluir que a veracidade da implicação
$$
(P\wedge Q)\rightarrow R,
$$
( ou seja, que da veracidade de P e Q resulta sempre a veracidade de R) então pode argumentar-se que da hipótese de $P$ e $Q$ resulta a veracidade de $R$. Assim,  caso $P$ e $Q$ sejam aceites como verdadeiras bem como $(P\wedge Q)\rightarrow R$, então a veracidade de $R$ resulta logicamente dos pressupostos. A uma tal justificação damos o nome de *argumento* e constitui o método usado para a demonstração matemática.

De um modo geral, chama-se argumento a uma sequência finita de proposições organizadas na forma seguinte
$$
P_1\wedge P_2\wedge\ldots\wedge P_n \Rightarrow Q
$$
onde as proposições $P_1, P_2,\ldots\, P_n$ são designadas de *premissas* (ou hipóteses) e $Q$ a *conclusão* (ou tese). Ao fazer-se a leitura do argumento $(P_1\wedge\ldots\wedge P_n)\rightarrow Q$ é costume inserir uma das locuções ''portanto'', ''por conseguinte'', ''logo'', lendo-se por exemplo: ''$P_1,\ldots,P_n$, portanto, $Q$''. Para sugerir esta leitura usa-se, uma das seguintes notações:
$$
\begin{align}
\begin{array}{c}
  P_1 \\
  \vdots \\
  P_n \\
  \hline
  Q \\
\end{array}
\end{align}
$$
ou

$$P_1,\ldots, P_n\therefore Q\;$$

Interessa distinguir entre argumentos correctos  e argumentos inválidos.

### Argumento válido

Um argumento $$P_1,\ldots, P_n\therefore Q$$ diz-se **correcto** ou **válido** se a conclusão for verdadeira sempre que as premissas $$P_1,\ldots, P_n$$ forem simultaneamente verdadeiras e diz-se **incorrecto**, **inválido** ou **falacioso** no caso contrário, isto é, se alguma situação permitir que as premissas sejam todas verdadeiras e a conclusão falsa.

As regras que permitem passar de hipóteses feitas e resultados já demonstrados a novas proposições são conhecidas por regras de inferência. A regra de inferência mais frequentemente usada é o \emph{modus ponens}:
$$
\begin{align}
\begin{array}{l}
  P\rightarrow Q \\
  P \\
  \hline
  Q \\
\end{array}
\end{align}
$$
Se a implicação $P\rightarrow Q$ é verdadeira e também a proposição $P$, então $Q$ tem de ser necessariamente verdadeira. A validade desta regra pode ser comprovada recorrendo a uma tabela de verdade.

neste caso dizemos que $P\rightarrow Q,P\therefore Q$ é um argumento válido.

De um modo geral,
$$
P_1,\ldots, P_n\therefore Q
$$ é um argumento válido  se e só se
$$
P_1\wedge P_2\wedge\ldots\wedge P_n\Rightarrow Q,
$$
ou seja,  se e só se
$$
(P_1\wedge P_2\wedge\ldots\wedge P_n)\rightarrow Q
$$
for uma tautologia.

#### Exemplo
O argumento $$p,q\rightarrow r,\neg r\therefore \neg q$$ é válido já que na tabela de verdade que relaciona os valores de verdade das proposições $p,q\rightarrow r,\neg r, \neg q$ nas linhas onde as premissas são verdadeiras a conclusão também o é.
$$
\begin{align}
\begin{array}{|ccc||c|c|c||c|}
\hline
p & q & r & p & q\rightarrow r & \neg r & \neg q \\
\hline
V & V & V & V & V & F & F \\
V & V & F & V & F & V & F \\
V & F & V & V & V & F & V \\
\hline
V & F & F & *V* & *V* & *V* & *V* \\
\hline
F & V & V & F & V & F & F \\
F & V & F & F & F & V & F \\
F & F & V & F & V & F & V \\
F & F & F & F & V & V & V \\
\hline
\end{array}
\end{align}
$$

### Exemplo
Mostremos que o argumento abaixo é válido:
> "Só se o Eclipse ganhar a corrida é que pagarei as minhas dívidas. Os meus credores não ficarão satisfeitos a não ser que eu pague as minhas dívidas. Logo, ou o Eclipse ganha a corrida ou os meus credores não ficarão satisfeitos."

Interpretação:
1. P: Eclipse ganha a corrida.
+ Q: Pago as minhas dívidas.
+ R: Os meus credores ficarão satisfeitos.

Formalização:

  $$Q\rightarrow P, \neg Q\rightarrow \neg R\therefore P\vee\neg R$$

Inspector de circunstâncias:

O argumento é válido um vez que a formalização é um sequente tautológico, ou seja, a proposição
$$((Q\rightarrow P)\wedge (\neg Q\rightarrow \neg R))\rightarrow (P\vee\neg R)$$
é uma tautologia.

### Exemplo
Verifiquemos se o argumento abaixo é válido:
> "Ou o Eclipse ganha a corrida ou ganha o Estrela da Manhã. Se o Eclipse ganhar, Icabod ficará satisfeito. Logo, se o Estrela da Manhã ganhar, Icabod não ficará satisfeito."

Interpretação:
1. Eclipse ganha a corrida.
+ O Estrela da Manhã ganha a corrida.
+ Icabod fica satisfeito.

Formalização:

  $$P \vee Q, P\rightarrow R\therefore Q\rightarrow\neg R$$

Inspector de circunstâncias:

O argumento não é válido,  pois há pelo menos uma circunstância que torna as premissas verdadeiras e a conclusão falsa o que faz com que a proposição
$$((P \vee Q)\wedge ( P\rightarrow R))\rightarrow (Q\rightarrow\neg R)$$
não seja uma tautologia.

#### Exercício
Formalize os seguintes argumentos e teste a sua validade usando inspectores de circunstância para determinar se a formalização é um sequente tautológico:
1. "Não existe tempo se não existe mudança. Não há mudança a não ser que existam objectos que possam mudar. Logo, ou existem alguns objectos que possam mudar ou o tempo não existe."
+ "A vaca não existe a não ser que eu a veja. Se a vaca não existe, os campos e até a Terra não existem. Se os campos e a Terra não existem, eu não posso existir. Mas eu só posso ver a vaca se eu existir. É por isso óbvio que eu não existo."

Podemos assim usar tautologias do tipo $$(A_1\wedge A_2\wedge \ldots\wedge A_n)\rightarrow B$$
para provar argumentos e definir regras de inferência.

Usando tautologias deste tipo ou inspectores de circunstância podemos mostrar serem válidas as relações de inferência da tabela que se segue.

  Name | Tautologia | Regra de inferência
-------|------------|---------------------
Modus Ponens | $_{(p\wedge (p\rightarrow q))\rightarrow q}$ | $_{p, p\rightarrow q \therefore q}$
Modus Tollens| $_{(\neg q\wedge (p\rightarrow q))\rightarrow \neg p}$ | $_{\neg q,p\rightarrow q\therefore  \neg p}$
Silogismo Hipotético | $_{((p\rightarrow q)\wedge(q\rightarrow r))\rightarrow(p\rightarrow r)}$ | $_{p\rightarrow q,q\rightarrow r\therefore p\rightarrow r}$
Silogismo Disjuntivo | $_{((p\vee q)\wedge\neg p)\rightarrow q}$ | $_{p\vee q,\neg p\therefore q}$
Simplificação | $_{(p \wedge q)\rightarrow p}$ | $_{p \wedge q\therefore p}$
Adição | $_{p\rightarrow (p\vee q)}$ | $_{p\therefore p\vee q}$
Lei da resolução | $_{((p\vee q)\wedge (\neg p\vee r))\rightarrow(q\vee r)}$ | $_{p\vee q,\neg p\vee r\therefore q\vee r}$
Eliminação | $_{((p\rightarrow(q\vee r))\wedge \neg q)\rightarrow (p\rightarrow r)}$ | $_{p\rightarrow(q\vee r)), \neg q\therefore p\rightarrow r}$
Prova por Casos | $_{((p\rightarrow r)\wedge (q \rightarrow r))\rightarrow ((p\vee q)\rightarrow r)}$ | $_{p\rightarrow r,q \rightarrow r\therefore (p\vee q)\rightarrow r}$
Lei da combinação | $_{(p\wedge q)\rightarrow (p\wedge q)}$ | $_{p,q\therefore p\wedge q}$
Redução ao absurdo | $_{(\neg p\rightarrow q \wedge \neg p \rightarrow \neg q)\rightarrow p}$ | $_{\neg p\rightarrow q, \neg p \rightarrow \neg q\therefore p}$

#### Exercício
Demonstre as seguintes regras de inferência:
1. Modus Tollens
+ Silogismo Hipotético
+ Redução ao absurdo

### Demonstração válida
A sequência
$$A_1,A_2,\ldots,A_n,B$$
é uma *demonstração válida* se e só se cada fórmula na sequência:
1. ou é uma hipótese,
+ ou é uma tautologia,
+ ou é derivada por uma regra de inferência tendo por premissas fórmulas que a antecedem na sequência,
+ ou é equivalente a uma fórmula que a antecede na sequência.

Neste caso a proposição $A_1\wedge A_2\wedge \ldots\wedge A_n \rightarrow B$, e dizemos que a sequência
$$A_1,A_2,\ldots,A_n,B$$
é uma demonstração válida do sequente ou argumento
$$C_1,C_2,\ldots,C_m\therefore B$$
se  as únicas hipóteses usadas na demonstração $A_1,A_2,\ldots,A_n,B$, estão na sequência
$C_1,C_2,\ldots,C_m$.

A definição de demonstração válida assenta nos seguintes factos:

#### Terorema [Substituição por equivalência]
1. Se $C_m\Leftrightarrow D$ e $C_1,C_2,\ldots,C_m\therefore B$, então $C_1,C_2,\ldots,C_{m-1},D\therefore B$.
 \]
+ Se $B\Leftrightarrow D$ e $C_1,C_2,\ldots,C_m\therefore B$, então $C_1,C_2,\ldots,C_m\therefore D$.

Como exemplo de demonstração, seja $\Gamma=\{p,p\rightarrow q, q\rightarrow r\}$. Mostremos que $\Gamma\therefore r$. Com efeito, temos (1) $p$ é hipótese (está em $\Gamma$); (2) $p\rightarrow q$ é hipótese (idem); (3) $q$ (de 1 e 2, por Modus Ponens); (4) $q\rightarrow r$ é hipótese (está em $\Gamma$); (5) $r$ (de 2 e 4, por Modus Ponens). Logo, como por hipótese $p,p\rightarrow q, q\rightarrow r$ são proposições verdadeiras temos de ter $r$ verdadeira.

Admitindo agora que $\Gamma$ tem duas fórmulas contraditórias, da forma $p$ e $\neg p$. Provemos que se pode derivar qualquer fórmula $q$ a partir de $\Gamma$ (ou seja, mostramos que ''duma falsidade tudo se segue'').  Como $p$ e $\neg p$ são hipóteses, proposições válidas, podemos inferir que $p\wedge\neg p$ é válida.
$$
\begin{align}
\begin{array}{lll}
  1 & p & \text{hipótese} \\
  2 & \neg p & \text{hipótese} \\
  3 & p \rightarrow (\neg q\rightarrow p) & \text{tautologia} \\
  4 & \neg p \rightarrow (\neg q\rightarrow \neg p) & \text{tautologia} \\
  5 & \neg q\rightarrow p & \text{Modus Ponens a 2 e 3}  \\
  6 & \neg q\rightarrow \neg p & \text{Modus Ponens a 1 e 4}\\
  7 & (\neg q\rightarrow \neg p)\rightarrow ((\neg q\rightarrow p)\rightarrow q) & \text{tautologia}\\
  8 & (\neg q\rightarrow p)\rightarrow q & \text{Modus Ponens a 6 e 7} \\
  \hline
  9 & q & \text{Modus Ponens a 5 e 8} \\
\end{array}
\end{align}
$$
Assim podemos concluir que se tivermos premissas contraditórias, podemos derivar qualquer proposição.

#### Exemplo
Aplicando regras de inferência, demonstremos que o argumento abaixo é correcto.
$$ \neg p \rightarrow \neg q, (p \vee\neg q) \rightarrow r, \neg s \rightarrow \neg r, s\rightarrow(\neg w \vee \neg v) \therefore \neg w \vee \neg v$$

Temos:
$$
\begin{align}
\begin{array}{lll}
  1 & \neg p \rightarrow \neg q & \text{hipótese} \\
  2 & (p \vee\neg q) \rightarrow r &\text{ hipótese} \\
  3 & \neg s \rightarrow \neg r & \text{hipótese} \\
  4 & s\rightarrow(\neg w \vee \neg v) & \text{hipótese} \\
  5 & p \vee \neg q & \text{Def. implicação em 1} \\
  6 & r & \text{Modus Ponens a 2 e 5} \\
  7 & r\rightarrow s & \text{Contraposição em 3}\\
  8 & s & \text{Modus Ponens a 6 e 7} \\
  \hline
  9 & \neg w \vee \neg v & \text{Modus Ponens a 4 e 8} \\
\end{array}
\end{align}
$$

#### Exemplo
Aplicando regras de inferência, demonstremos que o argumento abaixo é correcto.
$$ \neg(\neg p \vee q),\neg r \rightarrow \neg s, (p\wedge \neg q)\rightarrow s, \neg r \vee t\therefore t$$
Temos:
$$
\begin{align}
\begin{array}{lll}
  1 & \neg(\neg p \vee q) & \text{hipótese} \\
  2 & \neg r \rightarrow \neg s & \text{hipótese} \\
  3 & (p\wedge \neg q)\rightarrow s & \text{hipótese} \\
  4 & \neg r \vee t & \text{hipótese} \\
  5 & \neg \neg p \wedge \neg q & \text{Lei de De Morgan em 1} \\
  6 & p \wedge \neg q & \text{Dupla negação de 5} \\
  7 & s & \text{Modus Ponens a 3 e 6} \\
  8 & s\rightarrow r & \text{Modus Tollens a 2 e 7} \\
  9 & r & \text{Modus Ponens a 7 e 8} \\
  10 & r\rightarrow t & \text{Def. de implicação em 4} \\
  \hline
  11 & t & \text{Modus Ponens a 9 e 10} \\
\end{array}
\end{align}
$$

### Exercícios:
Sendo $p,q,r$ e $s$ quatro proposições, classifique os argumentos abaixo se são ou não  válidos.
1. $(\neg p)\vee q,p\therefore q$
+ $p,p\rightarrow q, q\rightarrow r \therefore r$
+ $p\rightarrow q, r\rightarrow (\neg q)\therefore p\rightarrow (\neg r)$
+ $(\neg p)\vee q, (\neg r)\rightarrow (\neg q)\therefore p\rightarrow (\neg r)$

### Propriedades do operador $\therefore$
De forma simples podemos mostrar que o operador $\therefore$ satisfaz as seguintes propriedades:
1. (*Inclusão*) Para todo $p\in \Gamma$, tem-se que $\Gamma\therefore p$.
+ (*Monotonia*) Se $\Gamma\subseteq\Delta$ e se $\Gamma\therefore p$, então $\Delta\therefore p$. Informalmente, se algo é dedutível a partir dum dado conjunto de premissas $\Gamma$, continua a ser dedutível em qualquer conjunto de premissas contendo $\Gamma$.
+ (*Corte*) Se $\Delta\therefore p$ e de $\Gamma\therefore q$ para cada $q\in\Delta$, então $\Gamma\therefore p$.
+ (*Teorema da Dedução*) Se $\Gamma,p\therefore q$ então $\Gamma\therefore p\rightarrow q$.

Assim, por exemplo, como $p,p\rightarrow q\therefore q$, pelo Teorema da Dedução, temos que  $p\therefore (p\rightarrow q) \rightarrow q$, ou seja $\therefore p \rightarrow((p\rightarrow q) \rightarrow q)$. Donde podemos concluir que $p \rightarrow((p\rightarrow q) \rightarrow q)$ é uma tautologia, já que é ''sempre verdadeira'' o seu valor de verdade não depende de nenhuma hipótese. Assim, sempre que a proposição $P$ é uma tautologia escrevemos que $\therefore P$ já que o seu valor de verdade não depende de nenhuma hipótese.

### Exercícios:
Mostre que:
1. $\therefore (\neg p\rightarrow p)\rightarrow p$ (outra forma de redução ao absurdo)
+ $\therefore (p\rightarrow q)\rightarrow ((p\rightarrow \neg q)\rightarrow \neg p)$ (redução ao absurdo intuicionista)
+ $\therefore p\rightarrow p\vee q$ (regra da adição)
+ $\therefore \neg p \rightarrow (p\rightarrow q)$
+ $\therefore (p\rightarrow \neg q)\rightarrow (q \rightarrow \neg p)$
+ $\therefore (p\wedge q)\leftrightarrow \neg (\neg p \wedge \neg q)$ (regra de De Morgan)
+ $\therefore \neg (p\wedge \neg p)$ (lei da contradição)
+ $\therefore (p \wedge \neg p)\rightarrow q$ (Lei de Duns Scotus)

## Exercícios de revisão:

### Exercício:
Usando as afirmações

R: O Nuno é rico\\
H: O Nuno é feliz

escreva as seguintes afirmações na forma simbólica
1. O Nuno é pobre mas feliz.
+ O Nuno é rico ou feliz.
+ O Nuno não é nem rico nem feliz.
+ O Nuno é pobre ou ele é simultaneamente rico e feliz.

### Exercício:
Quatro indivíduos são suspeitos de terem cometido um crime. É sabido que um e só um deles cometeu o crime. Quando interrogados pela polícia fizeram as seguintes afirmações:
1. [Artur]: Foi o José que cometeu o crime.
+ [José]: Foi o Tiago que cometeu o crime,
+ [Gabriel]: Eu não o fiz.
+ [Tiago]: José mente quando diz que fui eu.

Se exactamente uma destas afirmações é falsa, quem foi o criminoso?

### Exercício:
Quais das seguintes expressões são proposições bem formadas?
1. $\neg((A\rightarrow B)\rightarrow \neg(B\rightarrow A)$
+ $(S\wedge (((P\rightarrow Q)\wedge (\neg Q\rightarrow R))\rightarrow (Q\vee \neg Q)))$
+ $((((A\wedge \neg B)\vee (\neg A \wedge B))\leftrightarrow \neg\neg\neg\neg C))$
+ $(((A\rightarrow B)\rightarrow C)\rightarrow \neg ((A\vee B)\leftrightarrow \neg\neg(C\wedge A)))$

### Exercício:
Construa a tabela de verdade para as seguintes fórmulas:
1 $\neg(\neg P \vee \neg Q)$
+ $\neg(\neg P \wedge \neg Q)$
+ $P\wedge(P\vee Q)$
+ $P\wedge(Q\wedge P)$
+ $(\neg P\wedge(\neg Q \wedge R))\vee (Q\wedge R)\vee (P\wedge R)$
+ $(P\wedge Q)\vee (\neg P \wedge Q)\vee (P\wedge\neg Q)\vee (\neg P\wedge\neg Q)$

### Exercício:
Assumindo que as variáveis proposicionais $P$ e $Q$ são verdadeiras e que $R$ e $S$ são falsas, determine o valor de verdade das afirmações:
1 $P\wedge(Q\vee R)$
+ $(P\wedge (Q\wedge R))\vee\neg((P\vee Q)\wedge(R\vee S))$
+ $(\neg(P\wedge Q)\vee\neg R)\vee(((\neg P\wedge Q)\vee \neg R)\wedge S)$

### Exercício:
Mostre que o valor lógico das fórmulas apresentadas abaixo é independente das suas componentes:
1. $(P\wedge (P\rightarrow Q))\rightarrow Q$
+ $(P\rightarrow Q)\leftrightarrow (\neg P \vee Q)$
+ $((P\rightarrow Q)\wedge (Q\rightarrow R))\rightarrow (P\rightarrow R)$
+ $(P\leftrightarrow Q)\leftrightarrow((P\wedge Q)\vee (\neg P\wedge \neg Q))$

### Exercício:
Construa a tabela de verdade das seguintes fórmulas:
1. $(Q\wedge(P\rightarrow Q))\rightarrow P$
+ $\neg(P\vee (Q\wedge R))\leftrightarrow ((P\vee Q)\wedge (P\vee R))$

### Exercício:
Assumindo que as variáveis proposicionais $P$ e $Q$ são verdadeiras e que $R$ e $S$ são falsas, determine os valores de verdade das seguintes fórmulas.
1. $(\neg(P\wedge Q)\vee \neg R)\vee ((Q\leftrightarrow \neg P)\rightarrow (R\vee \neg S))$
+ $(P\leftrightarrow Q)\wedge (\neg Q\rightarrow S)$
+ $(P\vee (Q\rightarrow(R\wedge \neg P)))\leftrightarrow (Q\vee \neg S)$

### Exercício:
Suponha-se que se define uma nova conectiva, denotada por $\ast$, tal que $p\ast q$ é verdadeira quando $q$ é verdadeira e $p$ falsa, e é falsa em todos os outros casos. Construa as tabelas de verdade para
1. $p\ast q$
+ $q\ast p$
+ $(p\ast q)\ast p$

### Exercício:
Elimine o maior número de parêntesis possível sem alterar o significado das expressões:
1. $((p\rightarrow (\neg q))\wedge r)$
+ $(p\vee (q \vee r))$
+ $(((p\wedge (\neg q))\wedge r)\vee s)$
+ $((p\vee(\neg q))\vee (p\wedge q))$
+ $((p\leftrightarrow q)\leftrightarrow(\neg(r\vee s)))$

### Exercício:
Reponha os parêntesis:
1. $s\vee \neg q\wedge r$
+ $s\rightarrow \neg\neg\neg\neg q \wedge r$
+ $s\rightarrow \neg(q\wedge r \rightarrow s)\wedge\wedge q \leftrightarrow r$
+ $s\rightarrow r\rightarrow r\leftrightarrow \neg r \vee t$

### Exercício:
Mostre as seguintes equivalências
1. $P\rightarrow (Q\rightarrow P)\Leftrightarrow \neg P\rightarrow (P\rightarrow Q)$
+ $P\rightarrow (Q\vee R)\Leftrightarrow (P\rightarrow Q)\vee (P\rightarrow R)$
+ $(P\rightarrow Q)\wedge (R\rightarrow Q)\Leftrightarrow (P\rightarrow Q)\vee (P\rightarrow R)$
+ $\neg(P\leftrightarrow Q)\Leftrightarrow (P\vee Q)\wedge \neg(P\vee Q)$

### Exercício:
Mostre que $P$ é equivalente às seguintes fórmulas
$\neg\neg P$, $P\wedge P$, $P\vee P$, $P\vee (P\wedge Q)$, $P\wedge (P\vee Q)$,
$(P\wedge Q)\vee (P\wedge \neg Q)$, e $(P\vee Q)\wedge (P\vee \neg Q)$.

### Exercício:
Mostre as seguintes equivalências
1. $\neg(P\wedge Q)\Leftrightarrow \neg P \vee \neg Q$
+ $\neg(P\wedge Q)\Leftrightarrow \neg P \wedge \neg Q$
+ $\neg(P\rightarrow Q)\Leftrightarrow P \wedge \neg Q$
+ $\neg(P\leftrightarrow Q)\Leftrightarrow (P \wedge \neg Q) \vee (\neg P\wedge Q)$

### Exercício:
Mostre as seguintes equivalências:
1. $A\rightarrow (P\vee C)\Leftrightarrow (A\wedge \neg P)\rightarrow C$
+ $(P\rightarrow C)\wedge (Q\rightarrow C)\Leftrightarrow (P\vee Q)\rightarrow C$
+ $((Q\wedge A)\rightarrow C)\wedge (A\rightarrow (P\vee C))\Leftrightarrow (A\wedge (P\rightarrow Q))\rightarrow C$
+ $((P\wedge Q \wedge A)\rightarrow C)\wedge (A\rightarrow (P\vee Q\vee C))\Leftrightarrow (A\wedge (P\leftrightarrow Q))\rightarrow C$

### Exercício:
Simplifique as fórmulas abaixo:
1. $((P\rightarrow Q)\leftrightarrow (\neg Q\rightarrow \neg P))\wedge R$
+ $P\vee (\neg P \vee (Q \wedge \neg Q))$
+ $(P\wedge (Q\wedge S))\vee (\neg P \wedge (Q \wedge S))$

### Exercício:
Mostre as seguintes implicações lógicas
1. $(P\wedge Q)\Rightarrow(P\rightarrow Q)$
+ $P\Rightarrow (Q\rightarrow P)$
+ $(P\rightarrow(Q\rightarrow R)\Rightarrow (P\rightarrow Q)\rightarrow (P\rightarrow R)$

### Exercício:
Escreva as fórmulas abaixo de forma equivalente, mas onde a negação seja aplicada apenas a variáveis.
1. $\neg(P\vee Q)$
+ $\neg(P\wedge Q)$
+ $\neg(P\rightarrow Q)$
+ $\neg(P\leftrightarrow Q)$

### Exercício:
Mostre que a conclusão $C$ segue das premissas $H_1,H_2,H_3$ nos seguintes casos:
1. $H_1:P\rightarrow Q$, $\therefore C:P\rightarrow (P\wedge Q)$
+ $H_1:\neg P\vee Q, H_2:\neg(Q\wedge \neg R), H_3:\neg R$, $\therefore C:\neg P$
+ $H_1:\neg P, H_2:P\vee Q$ $\therefore C:Q$
+ $H_1:\neg Q, H_2:P\rightarrow Q$ $\therefore C:\neg P$
+ $H_1:P\rightarrow Q, H_2:Q\rightarrow R$ $\therefore C:P\rightarrow R$
+ $H_1:R, H_2:P\vee \neg P$ $\therefore C:R$

### Exercício:
Mostre a validade dos seguintes argumentos, onde as premissas aparecem à esquerda e as conclusões à direita:
1. $\neg(P\wedge \neg Q),\neg Q\vee R,\neg R \therefore\neg P$
+ $(A\rightarrow B)\wedge (A\rightarrow C), \neg(B\wedge C), D\vee A \therefore D$
+ $\neg J\rightarrow (M\vee N), (H\vee G)\rightarrow \neg J, H\vee G \therefore M\vee N$
+ $P\rightarrow Q, (\neg Q\vee R)\wedge \neg R, \neg(\neg P\wedge S \therefore \neg S$
+ $(P \wedge Q)\rightarrow R, \neg R\vee S, \neg S \therefore \neg P \vee \neg Q$
+ $P\rightarrow Q, Q\rightarrow \neg R, R, P\vee (J\wedge S) \therefore J\wedge S$

### Exercício:
Sendo $p,q,r$ e $s$ quatro proposições, classifique os argumentos abaixo se são ou não válidos.
1. $p\vee (\neg q),\neg q\therefore p$
1. $\neg p\therefore p\rightarrow q $
+ $(p\wedge q)\rightarrow (r\wedge s),\neg r\therefore (\neg p)\vee(\neg q)$
+ $p\rightarrow q, (\neg q)\rightarrow(\neg r), s\rightarrow(p\vee r),s\therefore q$
+ $p\vee q, q \rightarrow (\neg r),(\neg r)\rightarrow (\neg p)\therefore \neg(p\wedge q)$
+ $p\rightarrow q, (\neg r)\rightarrow (\neg q), r \rightarrow (\neg p)\therefore \neg p$
+ $p\rightarrow (\neg p)\therefore \neg p$
+ $p\vee q,p\rightarrow r, \neg r \therefore q$
+ $p,q\rightarrow(\neg p),(\neg q)\rightarrow(r\vee (\neg s)),\neg r\therefore \neg s$
+ $p\rightarrow(q\vee s),q\rightarrow r\therefore p\rightarrow(r\vee s)$
+ $p\rightarrow(\neg q), q\rightarrow p, r\rightarrow p\therefore \neg q$
+ $p\rightarrow q, r\rightarrow s, \neg(p\rightarrow s)\therefore q\wedge (\neg r)$

### Exercício:
Quais dos seguintes argumentos são válidos?
1. $P\rightarrow Q, \neg Q\rightarrow R, \neg R, \therefore P$
+ $A\rightarrow (A\rightarrow (B\rightarrow C)),B, \therefore A\rightarrow C$
+ Se a Rute comprou um carro de luxo, foi porque ou assaltou um banco ou o seu tio rico morreu. Rute não assaltou um banco ou o seu tio rico não morreu. Consequentemente, o seu tio rico não morreu.
+ Hoje é domingo. Amanhã não é domingo. Consequentemente a Lua é feita de queijo verde.
+ O livro está na secretária ou na estante. Não está na estante. Consequentemente, está na secretária.
+ Se a função $f$ não é contínua, então não é diferenciável. A função $f$ é diferenciável. Consequentemente, a função $f$ é contínua.
+ Se existe vida em Marte, então os especialistas estão enganados e o governo está a mentir. Se o governo está a mentir, então os especialistas estão certos ou não existe vida em Marte. O governo está a mentir. Consequentemente, existe vida em Marte.
+ (Lewis Carroll) Os bebés são ilógicos. Ninguém que consiga domar um crocodilo deve ser menosprezado. Pessoas ilógicas são  menosprezadas. Consequentemente, os bebés não conseguem domar crocodilos.
+ (Lewis Carroll) Nenhum cão de caça vagueia pelo Zodíaco. Apenas os cometas vagueiam pelo Zodiaco. Só os cães de caça tem a cauda encaracolada. Consequentemente, nenhum cometa tem a cauda enrolada.
+ As frutas verdes não são saudáveis. Todas estas maçãs não são saudáveis. Nenhum fruto, que tenha crescido na escuridão é saudável. Estas maçãs não cresceram ao sol. Consequentemente, toda a fruta madura é saudável.

## Exercícios de python

##### Exercício:
Usando funções implementadas no capítulo anterior, defina uma função

     argumento(list, list)->bool

que verifica se a primeira lista [q1,q2,...,qm] é um argumento válido, onde cada proposição é definida por uma string e tem  variáveis na segunda lista $[p1,p2,...pn]$. (USANDO: a linguagem proposicional de símbolos 0,1,\&,$|$ e $\sim$, mais as funções imp(bool,bool)->bool e biimp(bool,bool)->bool )

     >>>  argumento(['p1', 'imp(p1,p2)','p2'],['p1','p2'])
     True

(Funções do capítulo anterior que vamos usar)

```python
def imp(p,q):
    u''' imp(bool,bool)->bool
         Operador de implicação '''
    return not p or q

def biimp(p,q):
    u''' biimp(bool,bool)->bool
         Operador de bi-implicação'''
    return imp(p,q) and imp(q,p)

def Eval(exp, atrib):
    u''' Eval(string,list)->bool

         Avalia a expressão proposicional, na sintaxe do Python,
         associando a cada variável usada <var> o valor lógico <bool>.
         A associação entre variáveis e valores lógicos deve ser descrita
         por pares (<var>,<bool>) na lista que serve de argumento.
             '''
    for var in atrib:
        exp = exp.replace(var[0],str(var[1]))
    return eval(exp)

def tautologia(exp,var):
    u''' tautologia(str,list)->bool

         Verifica se a proposição descrita pela string é uma tautologia,
         assumindo que as suas variáveis estão descritas na lista.
         USANDO: a linguagem proposicional de símbolos 0,1,\&,$|$ e $\sim$,
         mais as funções imp(bool,bool)->bool e biimp(bool,bool)->bool
             '''
    sai = True
    nvar = len(var)
    for n in range(2**nvar-1,-1,-1):
        l=str(bin(n))[2:].rjust(nvar,'0')
        cont=0
        lista = []
        for v in var:
            lista.append((v,bool(int(l[cont]))))
            cont = cont + 1
        sai = sai and bool(Eval(exp,lista))
    return sai
```

(Nova função)

```python
def argumento(lista,var):
    u''' tautologia(list,list)->bool

         Verifica se a primeira lista [q1,q2,...,qm] é um argumento válido,
         onde cada proposição é definida por uma string e tem  variáveis na
         segunda lista [p1,p2,...pn].
         USANDO: a linguagem proposicional de símbolos 0,1,\&,$|$ e $\sim$,
         mais as funções imp(bool,bool)->bool e biimp(bool,bool)->bool
             '''
    sequente = 'imp(' + lista[0]
    for prop in lista[1:-1]:
        sequente = sequente + ' and '+ prop
    sequente = sequente + ',' + lista[-1] + ')'
    return tautologia(sequente,var)
```

(teste da nova função)

```python
argumento(['p1', 'imp(p1,p2)','p2'],['p1','p2'])
```

    True

```python

```


```python
import numpy as np
import matplotlib.pyplot as plt
from IPython.display import display, HTML, IFrame
from ipywidgets import interact,fixed

from mpl_toolkits import mplot3d
from numpy.linalg import norm
from numpy import cos,sin,tan,arctan,exp,log,pi,sqrt,arange,array,linspace,meshgrid

from ipykernel.pylab.backend_inline import flush_figures

%matplotlib inline

plt.rcParams['figure.figsize'] = [8.0, 8.0]

# Uncomment the one that corresponds to your Jupyter theme
plt.style.use('default')
# plt.style.use('dark_background')
# plt.style.use('fivethirtyeight')
# plt.style.use('Solarize_Light2')

# plt.rcParams.update({
#     "text.usetex": True,
# #     "font.family": "serif",
# })

```

$\newcommand{\RR}{\mathbb{R}}$
$\newcommand{\bv}[1]{\begin{bmatrix} #1 \end{bmatrix}}$
$\renewcommand{\vec}{\mathbf}$

# One-minute Review

The **linearization** of a differentiable function $f(x,y)$ about a point $(a,b)$ is the linear function
$$L(x,y) = f(a,b) + f_x(a,b)(x-a)  + f_y(a,b)(y-b). $$

Its graph is tangent to the graph of $f$.

[Tangents demo](https://3demos.surge.sh/?currentChapter=Intro&shadeUp=true&flipInfo=true&obj0_kind=graph&obj0_params_a=-2&obj0_params_b=2&obj0_params_c=-2&obj0_params_d=2&obj0_params_z=1-%28x+-+1%29%5E2%2F6+-+%28y+%2B+1%29%5E2+%2F+10&obj0_params_tau=0&obj0_params_t0=0&obj0_params_t1=1&obj1_kind=curve&obj1_params_a=0&obj1_params_b=2*pi&obj1_params_x=cos%28t%29&obj1_params_y=sin%28t%29&obj1_params_z=1-%28cos%28t%29+-+1%29%5E2%2F6+-+%28sin%28t%29+%2B+1%29%5E2+%2F+10&obj1_params_tau=0&obj2_kind=curve&obj2_params_a=-pi%2F6&obj2_params_b=pi%2F6&obj2_params_x=cos%28t%29&obj2_params_y=sin%28t%29&obj2_params_z=9%2F10+-+%28sin%28t%29%29%2F5&obj2_params_tau=0)

## Theorem of Differentiability

If all partial derivatives $\frac{\partial f}{\partial x_i}$ are continuous in a neighborhood of a point $P$, then $f$ is differentiable at $P$.

#### Nonexample

Consider $$f(x,y) = \frac{xy}{\sqrt{x^2 + y^2}}.$$

```python
@interact(angle=(-114,18,6))
def _(angle=-30):
    plt.figure(figsize=(7,7),dpi=100)
    x = y = np.linspace(-1,1,100)
    x,y = np.meshgrid(x,y)
    ax = plt.subplot(projection='3d')
    ax.view_init(30,angle)
    ax.plot_surface(x,y,x*y/(sqrt(x**2 + y**2)),cmap='viridis',alpha=.5)
    # ax.contour(x,y,x*y/(sqrt(x**2 + y**2)))
    ax.contour(x,y,x*y/(sqrt(x**2 + y**2)),zdir='x',cmap='gray_r')
    ax.contour(x,y,x*y/(sqrt(x**2 + y**2)),zdir='y',cmap='gray');
    flush_figures()
```

    interactive(children=(IntSlider(value=-30, description='angle', max=18, min=-114, step=6), Output()), _dom_cla…

\begin{align*}
f_{x} &= \frac{y}{\sqrt{x^2 + y^2}} - \frac{x^2y}{(x^2 +y^2)^{3/2}} \\
\end{align*}

are not continuous near the origin.

# Lecture 10 - The Chain Rule

  - Objectives
    - Compute derivatives of compositions.
    - Compute derivatives from implicit relations.

  - Resources
    - Content
      - Stewart: §14.5
      - New Strang: [§4.5](https://cnx.org/contents/oxzXkyFi@6.1:8QoqMp7K@7/4-5-The-Chain-Rule)

    - Practice
      - Mooculus: [Chain Rule](https://ximera.osu.edu/mooculus/calculus3/directionalDerivativeAndChainRule/digInChainRule)
    - Extras
      - CalcBLUE: WARNING! This is very matrix-dependent (and thus extra) [The Chain Rule](https://youtu.be/3WtjD3bewBk)

[Photo credit: Joe Paradiso](http://paradiso.media.mit.edu/synth.html)

# The Chain Rule

Start by recalling the 1-D chain rule $$(f\circ g)'(x) = f'(g(x))g'(x)$$

or if $u=g(x)$, $$ \frac{df}{dx} = \frac{df}{du}\frac{du}{dx}$$ where the derivatives are evaluated at the appropriate point.

## The main problem

Suppose a hiking party charts a route on a map given by $\langle x(t),y(t) \rangle$ where the altitude is given by a function $f(x,y)$.

What is $\frac{df}{dt}$ at a given time $t_0$?

```python
f = lambda x,y: exp(-4*(y-sin(x))**2)*(1-np.abs(x+pi/2)/5)

@interact
def _(func=fixed(f),angle=(-90,120,6),vangle=(0,90,6),pt=(1,98)):
    pt = 99-pt
    fig = plt.figure(figsize = (10,5),dpi=100)
    ax = fig.add_subplot(121,projection='3d')
    ax.view_init(vangle,angle)
    for c in 'xyz':
#         getattr(ax,f"set_{c}lim")([-1,1]);
        getattr(ax,f"set_{c}label")(f"${c}$",size=16)
    x =  np.linspace(-4,4,601)
    y =  np.linspace(-2,2,301)
    X,Y = np.meshgrid(x,y)
    Z = func(X,Y)
    ax.plot_surface(X,Y,Z,alpha=.6,cmap='ocean',rcount=100,ccount=100);
    t = np.linspace(-pi/2,pi/2,100)
    X = t
    Y = t/pi - 1/2 - t*(t**2-pi**2/4)/5
    Z = func(X,Y)
    ax.plot(X,Y,Z,lw=6,color='r',alpha=1)
    ax2 = fig.add_subplot(122)
    ax2.plot((pi/2-t)/pi*4,Z)
    ax2.set_xlabel("$t$",size=16)
    ax2.set_ylabel("$z$",size=16)
    dt = t[pt+1]-t[pt-1]
    dx = X[pt+1]-X[pt-1]
    dy = Y[pt+1]-Y[pt-1]
    dz = Z[pt+1]-Z[pt-1]
    s = np.linspace(-20,20,100)
    ax.plot(X[pt] + dx*s,Y[pt] + dy*s,Z[pt] + dz*s,lw=4)
    ax.set_zlim3d([0,1])
    ax2.plot((pi/2-t)/pi*4,dz/dt*(t-t[pt])+Z[pt])
    ax2.set_ylim([0,1])
    flush_figures();
```

    interactive(children=(IntSlider(value=12, description='angle', max=120, min=-90, step=6), IntSlider(value=42, …

##### Clue: replace $f$ with $L$

```python
@interact
def _(angle=(-100,14,6)):
    fig = plt.figure(figsize=(6,6),dpi=100)
    ax = fig.add_subplot(111,projection='3d')
    x = y = np.linspace(0,2,75)
    x,y = np.meshgrid(x,y)
    ax.view_init(30,angle)
    for c in 'xyz':
    #         getattr(ax,f"set_{c}lim")([-1,1]);
        getattr(ax,f"set_{c}label")(f"${c}$",size=16)
    ax.plot_surface(x,y,-(x-2)**2 - (y-2)**2/2,alpha=.5)
    ax.plot_surface(x,y,2*(x-1) + (y-1) -3/2,alpha=.5)
    t = np.linspace(0,2,50)
    ax.plot(t,t,-(t-2)**2 - (t-2)**2/2)
    ax.plot(t,t,2*(t-1) + (t-1) - 3/2);
    flush_figures();
```

    interactive(children=(IntSlider(value=-46, description='angle', max=14, min=-100, step=6), Output()), _dom_cla…

That is, linearize $f$ around the point $(a,b) = (x(t_0),y(t_0))$.

$$\frac{d}{dt} f(x(t),y(t)) = \frac{d}{dt} L(x(t),y(t))$$

$$= \frac{d}{dt} \left( f(a,b) + f_x(a,b)(x(t)-a) + f_y(a,b)(y(t) - b)\right)$$

$$= f_x(a,b) x'(t) + f_y(a,b) y'(t)$$

$$= \frac{\partial f}{\partial x}\frac{dx}{dt} + \frac{\partial f}{\partial y}\frac{dy}{dt}$$ where, again, we're careful to evaluate the partials at the appropriate point.

# The Chain Rule

If $f(x_1,\ldots,x_n)$ is differentiable at $\vec x_0 = \langle x_1(t_0),\ldots,x_n(t_0) \rangle$ and each $x_i$ is differentiable at $t_0$, then

$$ \frac {df}{dt}\Big|_{t_0} = \sum_{i=1}^n \frac{\partial f}{\partial x_i}\Big|_{\vec x_0}\frac{dx_i}{dt}\Big|_{t_0} $$

#### Definition

This is more easily expressed using the **gradient** vector of a function $$\nabla f = \begin{bmatrix} f_{x_1} \\ f_{x_2} \\ \vdots \\ f_{x_n} \end{bmatrix}$$

*There will be **much** more to say about this later; for now, just treat it as notation.*

Thus for differetiable functions $f:\RR^n\to \RR$ and $\vec r: \RR \to \RR^n$, the composition has derivative $$\frac{d}{dt} f(\vec r(t)) = \nabla f(\vec r(t))\cdot \vec r'(t).$$

## Other forms

Other cases can be handled by extrapolating from the case above.

$$\frac{\partial}{\partial t} f(x(s,t),y(s,t),z(s,t)) = \frac{\partial f}{\partial x} \frac{\partial x}{\partial t} + \frac{\partial f}{\partial y}\frac{\partial y}{\partial t} +\frac{\partial f}{\partial z}\frac{\partial z}{\partial t} $$

### Example

A particle circles the $z$-axis every second at a distance of 1 unit. If it is confined to the surface $z=xy$, find the maximum of $\frac{dz}{dt}$.

```python
fig = plt.figure(figsize=(6,6),dpi=100)
ax = fig.add_subplot(projection='3d')
x = y = np.linspace(-1,1,100)
x,y = np.meshgrid(x,y)
ax.plot_surface(x,y,x*y,cmap='viridis',alpha=.3);
t = np.linspace(-pi,pi,100)
ax.plot(cos(t),sin(t),1/2*sin(2*t));
```

Note the period is 1 second, so $x = \cos(2\pi t), y = \sin (2\pi t)$.

$$ \frac{dz}{dt} = \frac{\partial z}{\partial x}\frac{dx}{dt} + \frac{\partial z}{\partial y}\frac{dy}{dt} $$

$$ = y (-2\pi\sin (2\pi t)) + x(2\pi \cos(2\pi t)) $$

$$ = -2\pi\sin^2 (2\pi t) + 2\pi \cos^2(2\pi t) $$

$$ = 2\pi \cos(4\pi t) $$ which has a maximum of $2\pi$.

### Example

The base radius of a right cone is increasing at a rate of  1 cm/min, and its height is decreasing at 2cm/min. When the base has radius 4 cm and the height is 8 cm, is the volume increasing or decreasing?

```python
@interact
def _(angle=fixed(-60),dt=(-.5,.5,.05)):
    fig = plt.figure(figsize=(6,6),dpi=100)
    ax = fig.add_subplot(111,projection='3d')
    r = np.linspace(0,4+dt,75)
    t = np.linspace(0,2*np.pi,75)
    r,t = np.meshgrid(r,t)
    ax.view_init(30,angle)
    for c in 'xyz':
    #         getattr(ax,f"set_{c}lim")([-1,1]);
        getattr(ax,f"set_{c}label")(f"${c}$",size=16)
    ax.plot_surface(r*cos(t),r*sin(t),-2*dt+8 - r*(-2*dt+8)/(dt+4),alpha=.5)
    ax.set_xlim((-5,5))
    ax.set_ylim((-5,5))
    ax.set_zlim((0,10))
    ax.plot([4+dt,0,0],[0,0,0],[0,0,8-dt*2],'k',lw=2)
    flush_figures();
```

    interactive(children=(FloatSlider(value=0.0, description='dt', max=0.5, min=-0.5, step=0.05), Output()), _dom_…

## Example

Suppose $f(x,y)$ has continuous derivatives of all order. Express $\frac{\partial^2 f}{\partial r\partial \theta}$ in terms of the partial derivatives of $f$.

$r$ and $\theta$ are the usual polar coordinates.

$$\frac{\partial f}{\partial r} = f_x  \frac{\partial x}{\partial r} + f_y \frac{\partial y}{\partial r}$$

$$ = f_x \cos \theta + f_y \sin \theta $$

\begin{align*}\frac{\partial^2 f}{\partial \theta \partial r } \\
\ &= \left(f_{xx} \frac{\partial x}{\partial \theta} + f_{xy} \frac{\partial y}{\partial \theta}\right)\cos \theta - f_x \sin \theta + \left(f_{yx} \frac{\partial x}{\partial \theta} + f_{yy} \frac{\partial y}{\partial \theta}\right)\sin \theta + f_y \cos \theta \\
\ &= (f_{yy} - f_{xx})r\sin\theta \cos \theta + f_{xy} r \cos (2\theta) + f_y \cos \theta - f_x \sin\theta
\end{align*}

### Exercises

  1. Wheat production $W$ in a given year depends on the average temperature $T$ and the annual rainfall $R$. Scientists estimate that the average temperature is rising at a rate of $0.15^\circ$C/year and rainfall is decreasing at a rate of $0.1$ cm/year. They also estimate that at current production levels, $\partial W/\partial T = -2$ and $\partial W/\partial R = 8$.

  - What is the significance of the signs of these partial derivatives?

  - Estimate the current rate of change of wheat production, $dW/dt$.

  2. Suppose
\begin{align}
z &= z(x,y) \\
x &= x(u,v) \\
y &= y(u,v) \\
u &= u(s,t) \\
v &= v(s,t) \\
\end{align}
are all differentiable. Find an expression for $\frac{\partial z}{\partial s}$.

$$ \frac{\partial z}{\partial s} = \frac{\partial z}{\partial x}\frac{\partial x}{\partial u}\frac{\partial u}{\partial s}
+ \frac{\partial z}{\partial x}\frac{\partial x}{\partial v}\frac{\partial v}{\partial s}
+ \frac{\partial z}{\partial y}\frac{\partial y}{\partial u}\frac{\partial u}{\partial s}
+ \frac{\partial z}{\partial y}\frac{\partial y}{\partial v}\frac{\partial v}{\partial s} $$

## Example

If $g:\RR\to\RR$ is any smooth function, show that $f(x,y) = g(x^2+y^2)$ is radially symmetric. That is, $\frac{\partial f}{\partial \theta} =0$

$$\frac{\partial f }{\partial \theta} = \frac{\partial}{\partial x} (g(x^2 + y^2)) \frac{\partial x}{\partial \theta}
+ \frac{\partial}{\partial y} (g(x^2 + y^2)) \frac{\partial y}{\partial \theta} $$

$$ = g'(x^2 + y^2)2x (-r \sin \theta) + g'(x^2 + y^2)2y (-r \cos \theta) $$

$$ = g'(x^2 + y^2)( -2xy + 2yx) = 0 $$

# Implicit differentiation

Every implicit relationship among variables $x$ and $y$ can be expressed as a level set $$ F(x,y) = c. $$

To find the rate of change $\frac{dy}{dx}$ determined by this relation, we can be clever and differentiate the whole expression with respect to $x$.

$$ \frac{d}{dx}F(x,y) = 0$$

**WARNING** Mind your $d$'s and $\partial$'s.

$$ \frac{d}{dx}F(x,y(x)) = 0$$

$$ \frac{\partial F}{\partial x}\frac{dx}{dx} + \frac{\partial F}{\partial y}\frac{dy}{dx} = 0$$

$$ \frac{dy}{dx} = -\frac{F_x}{F_y}$$

## Example

Find the slope of the tangent line to

$$ x \sin(y) - \frac12 = \sqrt{2} - 2\cos(xy)$$ at the point $\left(\frac12,\frac\pi2\right)$.

```python
x = y = np.linspace(-pi,pi,102)
x,y = np.meshgrid(x,y)
z = x*sin(y) + 2*cos(x*y) - sqrt(2) - 1/2
plt.figure(figsize=(7,7))

cp = plt.contour(x,y,z,levels=arange(-3,3.4,.5),alpha=.5,colors='y')

cp = plt.contour(x,y,z,levels=[0],colors='y')
# plt.clabel(cp,fmt="%d");
x = np.linspace(-2.5,3.5,102)
plt.plot(x,pi/2 + (x-1/2) * (sqrt(2) - pi),color='r',lw=3);
plt.grid(True)
plt.scatter(1/2,pi/2)
plt.xlim(-pi,pi)
plt.ylim(-pi,pi);
```

$$F(x,y) = x \sin y + 2\cos(xy) = \frac12 + \sqrt 2 $$

$$ \frac{dy}{dx} = \left.-\frac{F_x}{F_y} \right\rvert_{(1/2,\pi/2)} = \left.-\frac{\sin y -2\sin(xy)y}{x\cos y -2 \sin(xy)x}\right\rvert_{(1/2,\pi/2)} $$

$$ = - \frac{1 - \frac{\pi}{\sqrt2}}{-\frac{1}{\sqrt2}} = \sqrt2 - \pi $$

```python

```


# Dynamical System Approximation
This notebook aims at learning a functional correlation based on given snapshots. The data is created through the following ODE:
\begin{align}
\frac{d^2}{dt^2} x_i = \sum_{i_{l-1},i_l,i_{l+1}=1}^4 c_{i_{l-1} i_{l}i_{l+1}}\psi_{i_{l-1}}(x_{l-1})\psi_{i_l}({x_l})\psi_{i_{l+1}}(x_{l+1}),
\end{align}
where only $20$ coefficients $ c_{i_{l-1} i_{l}i_{l+1}}$ are non zero, and randomly distributed between $[-1,1]$.
Here we only regularize the optimized part of the coefficients, not the selection tensor.

```python
import numpy as np
import xerus
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm
import time
import helpers as hp
import pandas as pd
import random
%precision  4
```

```python
# we construct a random solution with 20 (10 at the boundary) non zero coefficients in each equation
# the selection pattern is the same as in the fermi pasta equations
def project(X):
    dim = ([(3 if i == 0 or i == noo -1 else 4) for i in range(0,noo)])
    dim.extend(dim)
    C2T = xerus.TTOperator(dim)
    for eq in range(noo):
        idx = [0 for i in range(noo)]
        if eq == 0:
            idx[0] = 2
            idx[1] = 3
        elif eq == noo -1:
            idx[noo-2] = 1
            idx[noo-1] = 1
        elif eq == noo -2:
            idx[eq-1] = 1
            idx[eq]   = 2
            idx[eq+1] = 2
        else:
            idx[eq-1] = 1
            idx[eq]   = 2
            idx[eq+1] = 3
        idx.extend(idx)
        C2T += xerus.TTOperator.dirac(dim,idx)
    C2T.round(1e-12)
    i1,i2,i3,i4,i5,i6,j1,j2,j3,j4,k1,k2,k3 = xerus.indices(13)

    X(i1^noo,j1^noo) << X(i1^noo,k1^noo) * C2T(k1^noo,j1^noo)
    X.round(1e-12)
    return X

def exact(noo,p):
    s = 3
    coeffs = 10 #number of random coefficients for the first and last equation will be doubled for the other equations
    rank = 4
    dim = [p for i in range(0,noo)]
    dim.extend([s+1 for i in range(0,noo)])
    dim[noo] = s
    dim[2*noo-1]=s
    ranks = [1] +  [rank for i in range(noo-1)] + [1]
    C1ex = xerus.TTOperator(dim)

    i=0 # first component
    tmp = xerus.Tensor([ranks[i],p,dim[i+noo],ranks[i+1]])
    tmp1 = xerus.Tensor.dirac([ranks[i],p,1,ranks[i+1]],[0,0,0,0])
    tmp2 = xerus.Tensor([ranks[i],p,1,ranks[i+1]])
    for c in range(coeffs):
        r1 = random.randint(0,ranks[i]-1)
        r2 = random.randint(0,ranks[i+1]-1)
        pp = random.randint(0,p-1)
        tmp2[r1,pp,0,r2] = 2*random.random() - 1
    tmp3 = xerus.Tensor.identity([ranks[i],p])
    tmp3.reinterpret_dimensions([ranks[i],p,1,1])
    tmp4 = xerus.Tensor.identity([1,p,1,ranks[i+1]])

    tmp.offset_add(tmp1,[0,0,0,0])
    tmp.offset_add(tmp2,[0,0,2,0])
    tmp.offset_add(tmp4,[0,0,1,0])
    C1ex.set_component(i,tmp)

    i = noo-1 # last component
    tmp = xerus.Tensor([ranks[i],p,dim[i+noo],ranks[i+1]])
    tmp1 = xerus.Tensor.dirac([ranks[i],p,1,ranks[i+1]],[0,0,0,0])
    tmp2 = xerus.Tensor([ranks[i],p,1,ranks[i+1]])
    for c in range(coeffs):
        r1 = random.randint(0,ranks[i]-1)
        r2 = random.randint(0,ranks[i+1]-1)
        pp = random.randint(0,p-1)
        tmp2[r1,pp,0,r2] = 2*random.random() - 1
    tmp3 = xerus.Tensor.identity([ranks[i],p])
    tmp3.reinterpret_dimensions([ranks[i],p,1,1])
    tmp4 = xerus.Tensor.identity([1,p,1,ranks[i+1]])

    tmp.offset_add(tmp1,[0,0,0,0])
    tmp.offset_add(tmp2,[0,0,1,0])
    tmp.offset_add(tmp3,[0,0,2,0])
    C1ex.set_component(i,tmp)

    #loop for all components in between
    for i in range(1,noo-1):
        tmp = xerus.Tensor([ranks[i],p,dim[i+noo],ranks[i+1]])
        tmp1 = xerus.Tensor.dirac([ranks[i],p,1,ranks[i+1]],[0,0,0,0])
        tmp2 = xerus.Tensor([ranks[i],p,1,ranks[i+1]])
        for c in range(2*coeffs):
            r1 = random.randint(0,ranks[i]-1)
            r2 = random.randint(0,ranks[i+1]-1)
            pp = random.randint(0,p-1)
            tmp2[r1,pp,0,r2] = 2*random.random() - 1
        tmp3 = xerus.Tensor.identity([ranks[i],p])
        tmp3.reinterpret_dimensions([ranks[i],p,1,1])
        tmp4 = xerus.Tensor.identity([1,p,1,ranks[i+1]])

        tmp.offset_add(tmp1,[0,0,0,0])
        tmp.offset_add(tmp2,[0,0,2,0])
        tmp.offset_add(tmp3,[0,0,3,0])
        tmp.offset_add(tmp4,[0,0,1,0])
        C1ex.set_component(i,tmp)

    C1ex = project(C1ex)
    return C1ex #/ C1ex.frob_norm()

```

```python
# We initialize with a random TT in the needed format
def initialize(p,noo):
    rank = 4 #fix rank
    dim = [p for i in range(0,noo)]
    dim.extend([4 for i in range(0,noo)])
    dim[noo] = 3
    dim[2*noo-1]=3
    C = xerus.TTOperator.random(dim,[rank for i in range(0,noo-1)]) # initalize randomly
    C.move_core(0,True)
    return C / C.frob_norm()
```

```python
# We choose different pairs of dimensions and samplesizes to run the algoirthm for.
#data_noo_nos = [(6,1000),(6,1400),(6,1800),(6,2200),(6,2600),(6,3000),(6,3400),(6,3800),\
#                (12,1400),(12,1900),(12,2400),(12,2900),(12,3400),(12,3900),(12,4400),(12,4900),\
#                (12,5500),(12,6500),(12,7500),(12,9000),\
#                (18,1600),(18,2200),(18,2800),(18,3400),(18,4000),(18,4600),(18,5200),(18,5800),\
#                (18,6500),(18,7500),(18,8500),(18,10000)]
#                                                       pairs used in simulations in the paper
#                                                       uncomment to simulate but is computational intensive
data_noo_nos = [(8,3000)] #specify pairs to simulate for
runs = 1 #specify number of runs for each pair (10 in the paper)
#runs = 10
max_iter = 25 # specify number of sweeps
output = 'data.csv' # specify name of output file

number_of_restarts = 5 # here integrated a restart functionality, this specifies the number of recoveries if
eps = 1e-6             # the threshold eps was not reached

tuples = []
for data in data_noo_nos:
    noo = data[0]
    nos = data[1]
    for r in range(0,runs):
        tuples.append((noo,nos,r))

index = pd.MultiIndex.from_tuples(tuples, names=['d', 'm','runs'])

# The results of each optimization is store in a Dataframe
df = pd.DataFrame(np.zeros([len(tuples),max_iter]), index=index)
print(len(index))

print(data_noo_nos)
df['restarts'] = 0
```

```python
#loop over all pairs of samples, calls hp.run_als for the solution
i1,i2 = xerus.indices(2)
lam = 1 #regularization parameter
#Master iteration
psi = hp.basis(0) # get basis functions, Legendre
p = len(psi)
for data in data_noo_nos:
    noo = data[0]
    nos = data[1]
    print( "(noo,nos) = (" + str(noo) +',' + str(nos) + ')' )
    C2list = hp.build_choice_tensor2(noo)
    for r in range(runs):
        C1ex = exact(noo,p) # get new model, whcih will be the exact solution
        print("C1ex frob_norm: " +str(C1ex.frob_norm()))
        x = 2 * np.random.rand(noo, nos) - 1 #create samples
        Alist = hp.build_data_tensor_list2(noo,x,nos,psi,p) # build dictionary tensor
        y = hp.random_data_selection(Alist,C1ex,C2list,noo,nos) # calculate rhs from random model C1ex
        Y = xerus.Tensor.from_ndarray(y)
        starts = 0
        errors = [1]
        while np.nanmin(errors) > eps and starts < number_of_restarts: # restart loop
            starts +=1
            print("Number of starts = " + str(starts))
            C1 = initialize(p,noo) # each time random new initialization
            start = time.time()
            errors = hp.run_als(noo,nos,C1,C2list,Alist,C1ex,Y,max_iter,lam)
            print(str(time.time() - start) + ' secs')
        for i in range(1,len(errors)):
            df[i-1].loc[(noo,nos,r)] = errors[i-1]
        df['restarts'].loc[(noo,nos,r)] = starts - 1
        print("Run: " +str(r) + " finished result = " + str(errors))
        df.to_csv(output)
```

```python

```

```python

```


```python
import numpy as np
import pandas as pd
import sympy as sm
import matplotlib.pyplot as plt
import ipywidgets as widgets
from ipywidgets import interactive, interact
from scipy import linalg
from scipy import optimize
sm.init_printing(use_unicode=True) #for pretty printing
```

```python
# Create model domain and empty array for values of K
K_size = 50
kt = np.arange(K_size)

# Parameters
alpha = 1/3
delta = 0.05
s = 0.3
B = 1
n = 0.025

# Defining CD-function
def GDP(kt):
    y = B * (kt)**(alpha)
    return y

# Defining equations for diagram
y = GDP(kt)
dep = (delta+n)*kt
S = s*B*kt**alpha

# Defining steady state expressions
ssk = (B**(1/(1-alpha))*(s/(n+delta))**(1/(1-alpha)))
ssy = (B**(1/(1-alpha))*(s/(n+delta))**(alpha/(1-alpha)))

# Plotting the Solow Diagram
y_max = np.max(y)
v = [0, 20, 0, 1.75]

fig, ax = plt.subplots(figsize=(10, 8))
ax.plot(kt, dep, ls = '-', label="Depreciation")
ax.plot(kt, S, ls = '-', label="Savings")
ax.set(title="Solow Model", xlabel="Capital Stock")
plt.text(18.4, 1.55,  r'$ (n+\delta)k_t$')
plt.text(19,.85, r'$sBk_t^\alpha$')
plt.axvline(x = ssk, ls = "--", color = 'k', label='SS')
plt.legend(loc=2)
plt.axis(v)
plt.show()

```

    <function __main__.interactive_figure(n, delta, s, alpha)>

```python

```