Vamos continuar nossa trilha em computação simbólica estendendo o conhecimento sobre o tipo `bool`, expressões e testes lógicos.

## Operadores lógicos

Vimos que `True` e `False` são os dois valores atribuíves a um objeto de tipo `bool`. Eles são úteis para testar condições, realizar verificações e comparar quantidades. Vamos estudar *operadores de comparação*, *operadores de pertencimento* e *operadores de identidade*.

### Operadores de comparação

A tabela abaixo resume os operadores de comparação utilizados em Python.

| operador | significado | símbolo matemático | 
|---|---|---| 
| `<` | menor do que | $<$ |
| `<=` | menor ou igual a | $\leq$ |
| `>` | maior do que | $>$ |
| `>=` | maior ou igual a | $\geq$ |
| `==` | igual a | $=$ |
| `!=` | diferente de | $\neq$ |

Podemos usá-los para comparar objetos. 

**Nota:** `==` está relacionado à igualdade, ao passo que `=` é uma atribuição. São conceitos operadores com finalidade distinta. 


```python
2 < 3 # o resultado é um 'bool'
```




    True




```python
5 < 2 # isto é falso
```




    False




```python
2 <= 2 # isto é verdadeiro
```




    True




```python
4 >= 3 # isto é verdadeiro
```




    True




```python
6 != -2 
```




    True




```python
4 == 4 # isto não é uma atribuição! 
```




    True



Podemos realizar comparações aninhadas:


```python
x = 2
1 < x < 3
```




    True




```python
3 > x > 4
```




    False




```python
2 == x > 3 
```




    False



As comparações aninhadas acima são resolvidas da esquerda para a direita e em partes. Isso nos leva a introduzir os seguintes operadores.

| operador | símbolo matemático | significado | uso relacionado a |
|---|---|---|---|
| `or` | $\vee$ | "ou" booleano | união, disjunção |
| `and` | $\wedge$ | "e" booleano | interseção, conjunção |
| `not` | $\neg$ | "não" booleano | exclusão, negação |


```python
# parênteses não são necessários aqui
(2 == x) and (x > 3) # 1a. comparação: 'True'; 2a.: 'False'. Portanto, ambas: 'False'
```




    False




```python
# parênteses não são necessários aqui
(x < 1) or (x < 2) # nenhuma das duas é True. Portanto, 
```




    False




```python
not (x == 2) # nega o "valor-verdade" que é 'True'
```




    False




```python
not x + 1 > 3 # estude a precedência deste exemplo. Por que é 'True'?
```




    True




```python
not (x + 1 > 3) # estude a precedência deste exemplo. Por que também é 'True'?
```




    True



### Operadores de pertencimento

A tabela abaixo resume os operadores de pertencimento. 

| operador | significado | símbolo matemático
|---|---|---|
| `in` | pertence a | $\in$ |
| `not in` | não pertence a | $\notin$ |

Eles terão mais utilidade quando falarmos sobre sequências, listas. Neste momento, vejamos exemplos com objetos `str`.


```python
'2' in '2 4 6 8 10' # o caracter '2' pertence à string
```




    True




```python
frase_teste = 'maior do que' 
'maior' in frase_teste
```




    True




```python
'menor' in frase_teste # a palavra 'menor' está na frase
```




    False




```python
1 in 2 # 'in' e 'not in' não são aplicáveis aqui
```

### Operadores de identidade

A tabela abaixo resume os operadores de identidade. 

| operador | significado 
|---|---|
| `is` | "aponta para o mesmo objeto" 
| `is not` | "não aponta para o mesmo objeto" |

Esses operadores são úteis para verificar se duas variáveis se referem ao mesmo objeto. Exemplo: 

```python
a is b
a is not b
```

- `is` é `True` se `a` e `b` se referem ao mesmo objeto; `False`, caso contrário.
- `is not` é `False` se `a` e `b` se referem ao mesmo objeto; `True`, caso contrário.


```python
a = 2
b = 3
a is b # valores distintos
```




    False




```python
a = 2
b = a
a is b # mesmos valores
```




    True




```python
a = 2
b = 3
a is not b # de fato, valores não são distintos
```




    True




```python
a = 2
b = a
a is not b # de fato, valores são distintos
```




    False



## Equações simbólicas

Equações simbólicas podem ser formadas por meio de `Eq` e não com `=` ou `==`.


```python
# importação
from sympy.abc import a,b
import sympy as sy 
sy.init_printing(pretty_print=True)
```


```python
sy.Eq(a,b) # equação simbólica
```


```python
sy.Eq(sy.cos(a), b**3) # os objetos da equação são simbólicos
```

### Resolução de equações algébricas simbólicas

Podemos resolver equações algébricas da seguinte forma:

```python
solveset(equação,variável,domínio)
```

**Exemplo:** resolva $x^2 = 1$ no conjunto $\mathbb{R}$.


```python
from sympy.abc import x
sy.solveset( sy.Eq( x**2, 1), x,domain=sy.Reals)
```

Podemos reescrever a equação como: $x^2 - 1 = 0$.


```python
sy.solveset( sy.Eq( x**2 - 1, 0), x,domain=sy.Reals)
```

Com `solveset`, não precisamos de `Eq`. Logo, a equação é passada diretamente.


```python
sy.solveset( x**2 - 1, x,domain=sy.Reals)
```

**Exemplo:** resolva $x^2 + 1 = 0$ no conjunto $\mathbb{R}$.


```python
sy.solveset( x**2 + 1, x,domain=sy.Reals) # não possui solução real
```

**Exemplo:** resolva $x^2 + 1 = 0$ no conjunto $\mathbb{C}$.


```python
sy.solveset( x**2 + 1, x,domain=sy.Complexes) # possui soluções complexas
```

**Exemplo:** resolva $\textrm{sen}(2x) = 3 + x$ no conjunto $\mathbb{R}$.


```python
sy.solveset( sy.sin(2*x) - x - 3,x,sy.Reals) # a palavra 'domain' também pode ser omitida.
```

O conjunto acima indica que nenhuma solução foi encontrada.

**Exemplo:** resolva $\textrm{sen}(2x) = 1$ no conjunto $\mathbb{R}$.


```python
sy.solveset( sy.sin(2*x) - 1,x,sy.Reals)
```

## Expansão, simplificação e fatoração de polinômios

Vejamos exemplos de polinômios em uma variável. 


```python
a0, a1, a2, a3 = sy.symbols('a0 a1 a2 a3') # coeficientes
P3x = a0 + a1*x + a2*x**2 + a3*x**3 # polinômio de 3o. grau em x
P3x
```


```python
b0, b1, b2, b3 = sy.symbols('b0 b1 b2 b3') # coeficientes
Q3x = b0 + b1*x + b2*x**2 + b3*x**3 # polinômio de 3o. grau em x
Q3x
```


```python
R3x = P3x*Q3x # produto polinomial
R3x
```


```python
R3x_e = sy.expand(R3x) # expande o produto
R3x_e
```


```python
sy.simplify(R3x_e) # simplify às vezes não funciona como esperado
```


```python
sy.factor(R3x_e) # 'factor' pode funcionar melhor
```


```python
# simplify funciona para casos mais gerais 
ident_trig = sy.sin(x)**2 + sy.cos(x)**2
ident_trig
```


```python
sy.simplify(ident_trig)
```

## Identidades trigonométricas 

Podemos usar `expand_trig` para expandir funções trigonométricas. 


```python
sy.expand_trig( sy.sin(a + b) ) # sin(a+b)
```


```python
sy.expand_trig( sy.cos(a + b) ) # cos(a+b)
```


```python
sy.expand_trig( sy.sec(a - b) ) # sec(a-b)
```

## Propriedades de logaritmo


Com `expand_log`, podemos aplicar propriedades válidas de logaritmo.


```python
sy.expand_log( sy.log(a*b) )
```

A identidade não foi validada pois `a` e `b` são símbolos irrestritos.


```python
a,b = sy.symbols('a b',positive=True) # impomos que a,b > 0
```


```python
sy.expand_log( sy.log(a*b) ) # identidade validada
```


```python
sy.expand_log( sy.log(a/b) )
```


```python
m = sy.symbols('m', real = True) # impomos que m seja um no. real
sy.expand_log( sy.log(a**m) )
```

Com `logcombine`, compactamos as propriedades.


```python
sy.logcombine( sy.log(a) + sy.log(b) ) # identidade recombinada
```

## Fatorial 

A função `factorial(n)` pode ser usada para calcular o fatorial de um número.


```python
sy.factorial(m)
```


```python
sy.factorial(m).subs(m,10) # 10! 
```


```python
sy.factorial(10) # diretamente
```

**Exemplo:** Sejam $m,n,x$ inteiros positivos. Se $f(m) = 2m!$, $g(n) = \frac{(n + 1)!}{n^2!}$ e $h(x) = f(x)g(x)$, qual é o valor de $h(2)$? 


```python
from sympy.abc import m,n,x

f = 2*sy.factorial(m)
g = sy.factorial(n + 1)/sy.factorial(n**2)

h = (f.subs(m,x)*g.subs(n,x)).subs(x,4)
h
```

## Funções anônimas 

A terceira classe de funções que iremos aprender é a de *funções anônimas*. Uma **função anônima** em Python consiste em uma função cujo nome não é explicitamente definido e que pode ser criada em apenas uma linha de código para executar uma tarefa específica.

Funções anônimas são baseadas na palavra-chave `lambda`. Este nome tem inspiração em uma área da ciência da computação chamada de cálculo-$\lambda$.

Uma função anônima tem a seguinte forma: 

```python
lambda lista_de_parâmetros: expressão
```

Funções anônimas podem são bastante úteis para tornar um código mais conciso. 

Por exemplo, na aula anterior, definimos a função

```python
def repasse(V): 
    return 0.0103*V
```

para calcular o repasse financeiro ao corretor imobiliário. 

Com uma função anônima, a mesma função seria escrita como:


```python
repasse = lambda V: 0.0103*V
```

Não necessariamente temos que atribui-la a uma variável. Neste caso, teríamos:


```python
lambda V: 0.0103*V
```




    <function __main__.<lambda>(V)>



Para usar a função, passamos um valor:


```python
repasse(100000) # repasse sobre R$ 100.000,00
```

O modelo completo com "bonificação" seria escrito como:


```python
r3 = lambda c,V,b: c*V + b # aqui há 3 parâmetros necessários
```

Redefinamos objetos simbólicos:


```python
from sympy.abc import b,c,V
r3(b,c,V)
```

O resultado anterior continua sendo um objeto simbólico, mas obtido de uma maneira mais direta. Podemos usar funções anônimas para tarefas de menor complexidade.

## "Lambdificação" simbólica

Usando `lambdify`, podemos converter uma expressão simbólica do *sympy* para uma expressão que pode ser numericamente avaliada em outra biblioteca. Essa função desempenha papel similar a uma função *lambda* (anônima).


```python
expressao = sy.sin(x) + sy.sqrt(x) # expressão simbólica
f = sy.lambdify(x,expressao,"math") # lambdificação para o módulo math
f(0.2) # avalia
```

Para avaliações simples como a anterior, podemos usar `evalf` e `subs`. A lambdificação será útil quando quisermos avaliar uma função em vários pontos, por exemplo. Na próxima aula, introduziremos sequencias e listas. Para mostrar um exemplo de lambdificação melhor veja o seguinte exemplo.


```python
from numpy import arange # importação de função do módulo numpy

X = arange(40) # gera 40 valores de 0 a 39
```


```python
X
```




    array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
           17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
           34, 35, 36, 37, 38, 39])




```python
f = sy.lambdify(x,expressao,"numpy")(X) # avalia 'expressao' em X
f
```




    array([0.        , 1.84147098, 2.32351099, 1.87317082, 1.2431975 ,
           1.2771437 , 2.17007424, 3.30273791, 3.81778537, 3.41211849,
           2.61825655, 2.31663458, 2.9275287 , 4.02571831, 4.73226474,
           4.52327119, 3.71209668, 3.16170813, 3.49165344, 4.50877615,
           5.38508121, 5.41923133, 4.68156445, 3.94961112, 3.99340112,
           4.86764825, 5.86157796, 6.15252835, 5.56240841, 4.72153092,
           4.48919395, 5.16372672, 6.20828093, 6.74447451, 6.36003458,
           5.48789711, 5.00822115, 5.4392244 , 6.46078258, 7.20879338])



d440ed060512e9bbbad8690d855d75f4753f79f5
ipynb
Jupyter Notebook
_build/html/_sources/ipynb/02b-computacao-simbolica.ipynb
gcpeixoto/FMECD
9bca72574c6630d1594396fffef31cfb8d58dec2
CC0-1.0
_build/html/_sources/ipynb/02b-computacao-simbolica.ipynb
gcpeixoto/FMECD
9bca72574c6630d1594396fffef31cfb8d58dec2
CC0-1.0
_build/html/_sources/ipynb/02b-computacao-simbolica.ipynb
gcpeixoto/FMECD
9bca72574c6630d1594396fffef31cfb8d58dec2
CC0-1.0
Qwen/Qwen-72B
1. YES
2. YES